// -------------------------------------------------------- // Rutinas referentes a PSIS // -------------------------------------------------------- // devuelve el artículo correspondiente a un PSI según su número y género // PERO sólo cuando es pa sustituirlo por el artículo, no para ponerlo delante del nombre!!!!!!! // -------------------------------------------------------- Sub Pronombre(psi) Declare(art) art:="" If PSI[psi].Femenino Then art:="la" // que la cojas en brazos Else art:="le" // que le cojas en brazos EndIf If PSI[psi].Plural Then art:=art + "s" EndIf Return art // Busca un psi concreto en las inmediaciones, y devuelve la dirección en la que está. // Si no lo encuentra devuelve 0. Se usa pa que los PSIS localicen objetivos. Sub BuscaPSIAdy(loc,objetivo) declare(conexiones) declare(numconex) declare(conex) declare(locady) declare(i) declare(res) declare(eureka) eureka:=false conexiones:=LOC[loc].Conexiones() // almacena el verbo de las direcciones numconex:=ArrayLen(conexiones) // y la localidad a la que conectan. if (numconex<>0) then i:=1 while NOT(eureka)&(i<=(numconex-1)) conex:=ArrayItem(conexiones,i) locady:=ArrayItem(conexiones,i+1) if (locady>0)&(loc<>locady) then // mira a través de todas las conexiones salvo las que sean a una misma. if PSI[objetivo].Localidad=locady then res:=conex eureka:=TRUE endif endif i:=i+2 loop endif return res // DirContraria(dir) devuelve simplemente la dirección antónima a dir. Sub DirContr(dir) declare(ret) dir:=UCase(dir) Select dir Case "NORTE" ret:="SUR" Case "SUR" ret:="NORTE" Case "ESTE" ret:="OESTE" Case "OESTE" ret:="ESTE" Case * ret:="" EndSelect return ret // -------------------------------------------------------- // devuelve el texto correspondiente a la dirección de movimiento de un PSI // -------------------------------------------------------- Sub DirPSI(mov) Declare(txt) Select Ucase(mov) Case "NORTE" txt:="va hacia el norte" Case "SUR" txt:="va hacia el sur" Case "ESTE" txt:="va hacia el este" Case "OESTE" txt:="va hacia el oeste" Case "NORESTE" txt:="va hacia el noreste" Case "NOROESTE" txt:="va hacia el noroeste" Case "SURESTE" txt:="va hacia el sureste" Case "SUROESTE" txt:="va hacia el suroeste" Case "SUBIR" txt:="sube" Case "BAJAR" txt:="baja" Case "ENTRAR" txt:="entra" Case "SALIR" txt:="sale" Case * txt:="se va" EndSelect Return txt // -------------------------------------------------------- // da formato e imprime los diálogos de los PSIs // recibe: // 'txt_psi' lo que dice el PSI // 'txt' texto adicional que se imprimirá justo detrás // de lo que dice el PSI (si se pasa cadena vacía se ignora) // -------------------------------------------------------- Sub hablaPSI(txt_psi,txt) Print(CR + dialogo_psi1 + txt_psi + dialogo_psi2 + tipo_letra + color_letra) If txt<>"" Then Print(" " + txt) EndIf Print(CR) Return // Generar(psi). Genera un zombie aleatorio. Con descripción aleatoria y adjetivo aleatoria, y lo coloca en la localidad de generación de zombies. Allí el jugador no entra nunca. sub Generar(psi) declare(texto) declare(dado) if PSI[psi].nombre="ZOMBIE" then // Esto es sólo para zombies... por ahora... PSI[psi].Localidad:="GENERADOR" select PSI[psi].adjetivo case "GROTESCO" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie grotesco" else PSI[psi].DescCorta:="un zombie dantesco" endif case "PUTREFACTO" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie putrefacto" else PSI[psi].DescCorta:="un zombie podrido" endif case "HEMBRA" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie moribundo" else PSI[psi].DescCorta:="un zombie agonizante" endif case "HEDIONDO" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie hediondo" else PSI[psi].DescCorta:="un zombie apestoso" endif case "ESPECTRAL" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie espectral" else PSI[psi].DescCorta:="un zombie fantasmal" endif case "HORRIBLE" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie horrible" else PSI[psi].DescCorta:="un zombie horripilante" endif case "INMUNDO" if Random(1,100)>50 then PSI[psi].DescCorta:="un zombie inmundo" else PSI[psi].DescCorta:="un zombie asqueroso" endif endselect // ahora viene la generación de la descripción dado:=Random(1,5) if dado=1 then texto:="Es una masa de jirones de ropa y carne putrefacta. " endif if dado=2 then texto:="Los restos de lo que en su día fue un ser humano. " endif if dado=3 then texto:="¡Es un niño!. Contemplas horrorizado la blasfemia de un cuerpo juvenil apestado y maldito: tiene la tez pálida, los ojos enrojecidos, al igual que las comisuras de sus labios y las puntas de los dedos pero de sangre claro. " endif if dado=4 then texto:="Se mueve a pesar de esta horriblemente mutilado y rasgado como si hubiese sido... devorado. " endif if dado=5 then texto:="Su cuerpo es un cúmulo de bultos, carne desgarrada, heridas supurantes de gusanos. Parece ser que ya era cadaver antes de volver a la 'no-vida'. " endif dado:=Random(1,5) if dado=1 then texto:=texto+"Lleva la cabeza ladeada como si sus únicas fuerzas estubiesen en los hilos que le hacen andar dando tumbos y con los brazos por delante. " endif if dado=2 then texto:=texto+"Se mueve a espasmos, lentamente, arrastrando esa carcasa que tiene por cuerpo, siempre en pos tuya. " endif if dado=3 then texto:=texto+"Va murmurando letanías del infierno. Incesantes gorgojeos que salen de su garganta llena de coágulos de sangre. " endif if dado=4 then texto:=texto+"Ni siquiera parece mirar, ya que sus globos oculares están vueltos hacia arriba. Aún así parece saber con exactitud donde encontrarte. " endif if dado=5 then texto:=texto+"La cabeza ladeada. Se mueve lentamente hacia ti. De su boca surgen incesantes murmullos, parodias de palabras. " endif dado:=Random(1,5) if dado=1 then texto:=texto+"Aún lleva ropas, parodia grotesca de la humanidad que poseyó. " endif if dado=2 then texto:=texto+"Viste un chándal azul, rasgado en algunas zonas donde se ven heridas cicatrizadas verdes y supurantes. Restos de lo que le convirtió en un zombie." endif if dado=3 then texto:=texto+"Jirones de ropa le cuelgan, mezclados con la carne podrida, pero está casi desnudo, expirando un olor fétido por cada poro de su cuerpo grotesco." endif if dado=4 then texto:=texto+"Viste pantalones vaqueros y un jersey a rayas, en perfecto estado: desde luego, este no lleva mucho tiempo no-muerto." endif if dado=5 then texto:=texto+"La ropa que lleva apenas puede contener que se despedazen los trozos de carne desgarrados, que cuelgan de todo su cuerpo." endif PSI[psi].DescLarga:=texto PSI[psi].Peso:=50 PSI[psi].Tam:=20 PSI[psi].muerto:=0 PSI[psi].plural:=0 PSI[psi].femenino:=0 PSI[psi].Mov_Ruta:="SEGUIR" PSI[psi].Mov_Repetir:=0 PSI[psi].Mov_paso:="" PSI[psi].gore:=0 PSI[psi].fuerza:=100 PSI[psi].hostil:=1 PSI[psi].lentitud:=3 PSI[psi].estado:="normal" PSI[psi].locuaz:=0 PSI[psi].daño_base:=Random(15,25) PSI[psi].vitalidad:=Random(110,175) PSI[psi].vida_cabeza:=60 PSI[psi].vida_cuerpo:=70 PSI[psi].vida_brazo_izq:=45 PSI[psi].vida_brazo_dch:=45 PSI[psi].vida_pierna_izq:=60 PSI[psi].vida_pierna_dch:=60 PSI[psi].turno:=5 PSI[psi].direccion:=Array("BAJAR","SUR","OESTE") PSI[psi].viene_de:="" PSI[psi].objetivo:=PSIJugador PSI[psi].tipo_ataque:="devorar" PSI[psi].arma_preferida:="" PSI[psi].atacante:="" endif return // -------------------------------------------------------- // muestra el inventario de un PSI // recibe: // 'psi' nombre del PSI del que queremos el inventario // 'formato' formato para imprimir el inventario: // 0: inventario del jugador // 1: inventario de un PSI // -------------------------------------------------------- Sub Inventario(psi,formato) Declare(objetos) Declare(numobjetos) Declare(listaobjs) Declare(obj) Declare(c) Declare(i) objetos:=PSI[psi].Objetos() numobjetos:=ArrayLen(objetos) If numobjetos>0 Then // construimos la lista de objetos listaobjs:="" For i:=1 To numobjetos obj:=ArrayItem(objetos,i) // sólo incluimos los objetos visibles If Not(OBJ[obj].Invisible) Then c:=Articulo(obj,0) + OBJ[obj].DescCorta If (OBJ[obj].Prenda) & (OBJ[obj].Puesto) Then c:=c + " (puest" + TMF(FALSE,obj) + ")" EndIf If ArrayLen(listaobjs)=0 Then listaobjs:=Array(c) Else listaobjs:=ArrayInsert(listaobjs,ArrayLen(listaobjs)+1,c) EndIf EndIf Next EndIf Select formato Case 0 // este formato se usa para el inventario normal del jugador // imprimimos el inventario, sustituyendo la coma final por un punto (.) If ArrayLen(listaobjs)>=1 Then Print("Aparte de las ropas llevas " + ArrayFormat(listaobjs,", "," y ",".","") + CR) Else Print("Aparte de la ropa no llevas nada." + CR) EndIf Case 1 // este formato se usa para el inventario de los PSIs que examinamos // imprimimos el inventario, sustituyendo la coma final por un punto (.) If ArrayLen(listaobjs)>=1 Then Print(" Lleva " + ArrayFormat(listaobjs,", "," y ",".","")) EndIf EndSelect Return // MoverCond permite bloquear una salida a los PSIS, por exigencias del guión. // En mi caso, no permito que se metan en la niebla ni que se metan en salidas bucle. // Por defecto devuelve TRUE, o sea, que siempre las salidas posibles con el comando Mover de los // procedimientos de un PSI estarán abiertas. Para bloquear una salidas sólo hay que devolver FALSE. Sub MoverCond(psi,dir) declare(res) declare(conex) declare(pos) declare(loc) declare(locdestino) res:=TRUE loc:=PSI[psi].Localidad dir:=UCase(dir) conex:=LOC[loc].Conexiones pos:=InArray(conex,dir) if (pos>0) then locdestino:=ArrayItem(conex,pos+1) if (locdestino=loc) then // Esto chequea que no se un bucle la conexión, a la misma loc. res:=FALSE endif endif if (loc="18JULIO2")&(dir="SUR") then // Los PSIS no pasarán por la niebla. res:=FALSE if PSI[PSIJugador].Localidad="18JULIO3" then print(PSI[psi].DescCorta + " intenta avanzar hacia aqui, pero inexplicablemente no se atreve a pasar más allá de la niebla." +CR) endif endif return res // Esto se usa cuando un PSI llega a localidad del jugador. sub DirViene(mov) declare(txt) Select Ucase(mov) Case "NORTE" txt:="viene del sur" Case "SUR" txt:="viene del norte" Case "ESTE" txt:="viene del oeste" Case "OESTE" txt:="viene del este" Case "NORESTE" txt:="viene del noroeste" Case "NOROESTE" txt:="viene del nordeste" Case "SURESTE" txt:="viene del suroeste" Case "SUROESTE" txt:="viene del surdeste" Case * txt:="viene" EndSelect endselect return txt // PSIAtaca(psi,tipo,psi2,zona) esto efectúa un ataque del psi al psi2. Según las características de psi. // y según el tipo de ataque realizado. // ZONA se codifica de la siguiente manera: "cuerpo", "cabeza", "brazo_izq", "brazo_dch", "pierna_izq", "pierna_dch". sub PSIAtaca(psi,tipo,psi2,zona) if psi=psi2 then // esto no funciona... me puedo pegar a mi mismo return endif declare(daño_total) declare(daño_base) declare(arma) declare(base_arma) declare(peso_arma) declare(fuerza) declare(exito) declare(nohay) declare(dado) declare(zonas) declare(zonadesc) declare(amputacion) declare(muerte) declare(locpsi) declare(i) fuerza:=PSI[psi].fuerza locpsi:=PSI[psi].Localidad daño_base:=PSI[psi].daño_base if tipo="" then // si no se elige un tipo de ataque, se toma el preferido del PSI tipo:=PSI[psi].TIPO_ATAQUE endif if tipo="" then // Si el PSI no tiene uno preferido, por defecto será: golpear. PSI[psi].TIPO_ATAQUE:="golpear" tipo:="golpear" endif exito:=FALSE nohay:=FALSE dado:=Random(1,100) // Esto establece la probabilidad de tener exito en el ataque. if tipo="empujar" then if dado<=exito_cuerpo then zonadesc:="" PSI[psi2].Turno:=PSI[psi2].Lentitud exito:=TRUE endif endif if (tipo="golpear")|(tipo="devorar") then muerte:=FALSE amputacion:=FALSE if tipo="golpear" then // Calcula el daño base del arma que se use. En este caso sólo el PSI elige el arma, pero se podría hacer que los no jugadores eligiesen la mejor. base_arma:=0 arma:=PSI[psi].Arma_Preferida if arma<>"" then if PSI[psi].Contiene(arma) then base_arma:=OBJ[arma].Contundencia else arma:="" // si no posee el arma preferida... esta se quita. endif endif endif daño_total:=((daño_base+base_arma)*fuerza)/100 // fórmula que calcula el daño inflingido. if zona="" then // Si el PSI no elige una zona a atacar, se hace arbitrariamente. zonas:=ARRAY("cabeza","cuerpo","brazo_izq","brazo_dch","pierna_izq","pierna_dch") zona:=Random(1,6) zona:=ArrayItem(zonas,zona) endif Select zona Case "cabeza" zonadesc:="la cabeza" if PSI[psi2].Vida_Cabeza<=0 then nohay:=TRUE else if dado<=exito_cabeza then exito:=TRUE PSI[psi2].VIDA_CABEZA:=PSI[psi2].VIDA_CABEZA-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_cabeza)/100) if PSI[psi2].VIDA_CABEZA<=0 then amputacion:=TRUE PSI[psi2].vida_cabeza:=0 PSI[psi2].Vitalidad:=0 LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre+3 LOC[locpsi].gore_cuerpo:=LOC[locpsi].gore_cuerpo+1 LOC[locpsi].gore_cabeza:=LOC[locpsi].gore_cabeza+1 endif endif endif Case "cuerpo" zonadesc:="el cuerpo" if PSI[psi2].Vida_Cuerpo<=0 then NOHAY:=TRUE else if dado<=exito_cuerpo then exito:=TRUE PSI[psi2].VIDA_CUERPO:=PSI[psi2].VIDA_CUERPO-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_cuerpo)/100) if PSI[psi2].VIDA_CUERPO<=0 then PSI[psi2].VIDA_CUERPO:=0 PSI[psi2].Vitalidad:=0 LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 3 LOC[locpsi].gore_cuerpo:=LOC[locpsi].gore_cuerpo + 1 endif endif endif Case "brazo_izq" zonadesc:="el brazo izquierdo" if PSI[psi2].Vida_Brazo_Izq<=0 then Nohay:=TRUE else if dado<=exito_brazo then exito:=TRUE PSI[psi2].VIDA_BRAZO_IZQ:=PSI[psi2].VIDA_BRAZO_IZQ-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_brazo)/100) if PSI[psi2].VIDA_BRAZO_IZQ<=0 then amputacion:=TRUE PSI[psi2].VIDA_BRAZO_IZQ:=0 PSI[psi2].fuerza:=PSI[psi2].fuerza-25 LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 3 LOC[locpsi].gore_brazo:=LOC[locpsi].gore_brazo + 1 endif endif endif Case "brazo_dch" zonadesc:="el brazo derecho" if PSI[psi2].Vida_Brazo_Dch<=0 then nohay:=TRUE else if dado<=exito_brazo then exito:=TRUE PSI[psi2].VIDA_BRAZO_DCH:=PSI[psi2].VIDA_BRAZO_DCH-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_brazo)/100) if PSI[psi2].VIDA_BRAZO_DCH<=0 then amputacion:=TRUE PSI[psi2].VIDA_BRAZO_DCH:=0 PSI[psi2].fuerza:=PSI[psi2].fuerza-25 LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 3 LOC[locpsi].gore_brazo:=LOC[locpsi].gore_brazo + 1 endif endif endif Case "pierna_izq" zonadesc:="la pierna izquierda" if PSI[psi2].Vida_Pierna_Izq<=0 then nohay:=TRUE else if dado<=exito_pierna then exito:=TRUE PSI[psi2].VIDA_PIERNA_IZQ:=PSI[psi2].VIDA_PIERNA_IZQ-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_pierna)/100) if PSI[psi2].VIDA_PIERNA_IZQ<=0 then amputacion:=TRUE PSI[psi2].VIDA_PIERNA_IZQ:=0 PSI[psi2].lentitud:=PSI[psi2].lentitud+1 PSI[psi2].turno:=PSI[psi2].lentitud LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 3 LOC[locpsi].gore_pierna:=LOC[locpsi].gore_pierna + 1 endif endif endif Case "pierna_dch" zonadesc:="la pierna derecha" if PSI[psi2].Vida_Pierna_Dch<=0 then nohay:=TRUE else if dado<=exito_pierna then exito:=TRUE PSI[psi2].VIDA_PIERNA_DCH:=PSI[psi2].VIDA_PIERNA_DCH-daño_total PSI[psi2].VITALIDAD:=psi[psi2].VITALIDAD-((daño_total*porc_pierna)/100) if PSI[psi2].VIDA_PIERNA_DCH<=0 then amputacion:=TRUE PSI[psi2].VIDA_PIERNA_DCH:=0 PSI[psi2].lentitud:=PSI[psi2].lentitud+1 PSI[psi2].turno:=PSI[psi2].lentitud LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 3 LOC[locpsi].gore_pierna:=LOC[locpsi].gore_pierna + 1 endif endif endif EndSelect if (exito)&(tipo="devorar") then PSI[psi2].Estado:="devorado" endif endif // caso de "golpear" o "devorar" // NOTIFICACIONES if exito then // COSAS QUE PASAN CUANDO SE ATACA CON EXITO if PSI[psi2].VITALIDAD<=0 then // el PSI atacado finalmente ha muerto!!!!!!!!!! muerte:=TRUE i:=InArray(PSI[psi].Atacante,psi2) // al morir el psi2, lo quitamos de la lista de atacantes, si estaba allí if i<>0 then PSI[psi].Atacante:=ArrayRemove(PSI[psi].Atacante,i) endif Reciclar(psi2) // lo reciclamos Generar(psi2) // lo resucitamos, pero ahora es un zombie diferente ;). endif i:=InArray(PSI[psi2].ATACANTE,psi) // ACTUALIZAR ATACANTES if i<>0 then // si ya estaba antes, se borra y se inserta al principio del array. PSI[psi2].ATACANTE:=ArrayRemove(PSI[psi2].ATACANTE,psi,i) PSI[psi2].ATACANTE:=ArrayInsert(PSI[psi2].Atacante,1,psi) // el psi atacante pasa al inicio del array else // el atacante no estaba antes PSI[psi2].ATACANTE:=ArrayInsert(PSI[psi2].Atacante,1,psi) // el psi atacante pasa al array de atacantes endif if tipo="golpear" then // Sangre que salpica al golpear. PSI[psi2].gore:=PSI[psi2].gore + 2 PSI[psi].gore:=PSI[psi].gore + 1 LOC[locpsi].gore_sangre:=LOC[locpsi].gore_sangre + 1 if arma<>"" then OBJ[arma].gore:=OBJ[arma].gore + 1 endif endif // Notificaciones concretas if psi=PSIJugador then // mesajes que se imprimen pues el jugador los ocasiona. if tipo="empujar" then print("Empujas a "+PSI[psi2].DescCorta+" ferozmente. Este se tambalea hacia atrás perdiendo el equilibrio, pero pronto comienza su lento avance haci ti."+CR) PSI[PSIJugador].fuerza:=PSI[PSIJugador].fuerza-13 // restamos fuerza al jugador endif if tipo="golpear" then peso_arma:=0 if arma<>"" then // esto es pa restar la fuerza apropiada según el peso del arma usada if PSI[PSIJugador].Contiene(arma) then // como se puede ver. sólo se aplica esto peso_arma:=OBJ[arma].Peso // al jugador, por el juego en si. endif // Pero se puede aplicar a todos los PSIS si fuese necesario. endif PSI[PSIJugador].fuerza:=PSI[PSIJugador].fuerza-(6+peso_arma) // restamos fuerza al jugador puntos:=puntos+10 if (zona="cabeza")&(arma="BARRA HIERRO")&(amputacion)&(NOT(heresville)) then print("Golpeas al espectro con la barra y el impacto le arranca la cabeza, que vuela describiendo una órbita ") print("elíptica alrededor del lugar hasta que cae al suelo, junto a su cuerpo inanimado."+CR) heresville:=TRUE puntos:=puntos+30 else print("Golpeas a "+PSI[psi2].DescCorta+ " con ") if arma<>"" then print(Articulo(arma,1)+OBJ[arma].DescCorta+" ") else print("las manos desnudas ") endif print("en "+zonadesc+". ") if amputacion then puntos:=puntos+20 print("Produces un desgarrón definitivo, y ") if (PSI[psi2].vida_pierna_izq<=0)|(PSI[psi2].vida_pierna_dch<=0) then print("le machacas el miembro contra el suelo, separando "+zonadesc+" del cuerpo. ") else if Random(1,2)<2 then print("sale volando del golpe, hasta caer al suelo, unos metros más allá, en un charco de sangre. ") else print("queda colgando del muñon por unos tendones y venas, antes de caer al suelo en un charco de sangre. ") endif endif else if daño_total>15 then print("El tremendo golpe hace saltar sangre por todos lados, salpicando el suelo y a ti mismo. "+CR) else print("Ha sido un golpe débil y flojo."+CR) if muerte then print("Pero el "+Lcase(PSI[psi2].nombre)+" está casi destrozado y... ") endif endif endif if muerte then puntos:=puntos+30 if (zona="cuerpo")&(arma<>"") then if Random(1,2)>1 then print("Finalmente "+Articulo(arma,1)+OBJ[arma].DescCorta+" le destroza el pecho y ") else print("Le abres el vientre con "+Articulo(arma,1)+OBJ[arma].DescCorta+" y todas sus vísceras caen al suelo mezclándose con la sangre... ") endif else print("Con este golpe pareces haberle gastado sus últimas energías y ") endif print("el "+LCase(PSI[psi2].Nombre)+ " cae al suelo y entre espasmos, poco a poco deja de moverse..."+CR) else if PSI[psi2].estado="dormido" then PSI[psi2].estado:="normal" print("La zombie se despierta con un grito murmullado; da dos pasos ") print("hacia atrás desequilibrada y comienza a avanzar hacia ti... en busca de tus sesos."+CR) else if (amputacion)&((zona="pierna_izq")|(zona="pierna_dch")) then if ((zona="pierna_izq")&(PSI[psi2].vida_pierna_dch<=0))|((zona="pierna_dch")&(PSI[psi2].vida_pierna_izq<=0)) then // ESTO ES UNA PARANOYAAAAAAAAAAAAA print("Al terminar con la pierna que le quedaba, el zombie intenta mover los muñones para avanzar, pero consigue poco mientras abundante sangre sale a borbotones de las venas y arterias rasgadas."+CR) else // Esto es lo más asqueroso que he escrito en mi vida... print("Al desmembrarle la pierna, el zombie pierde el equilibrio y cae al suelo aparatosamente."+CR) endif else print("Y el zombie continúa su lento avance hacia ti."+CR) endif endif endif endif // si arranca cabeza igual que en Heresville. endif // si el tipo de golpe es GOLPEAR else // el atacante es un PSI no jugador. if psi2=PSIJugador then // Si el jugador es la victima... PSI[PSIJugador].fuerza:=PSI[PSIJugador].fuerza-5 //pierde fuerza por ser atacado, aunque sea un poco. if tipo="devorar" then if (PSI[psi].vida_brazo_izq<=0)&(PSI[psi].vida_brazo_dch<=0) then print("Con un inesperado impulso, "+PSI[psi].DescCorta+" te clava los dientes en "+zonadesc) else print("Lentamente "+PSI[psi].DescCorta+" te agarra y empieza a morderte en "+zonadesc) endif if Random(1,2)>1 then print(" horadando tu carne. ") else print(" sorbiendo la sangre y masticando. ") endif if amputacion then muerte:=TRUE // si el jugador se queda sin algo, muere al instante. if Random(1,2)>1 then print("Finalmente tu carne no puede más y cede a los mordiscos desgajandotelo. ") else print("El zombie te lo arranca. ") endif if zona="cabeza" then print("Tu cabeza cae al suelo, y desde ahi puedes contemplar como el zombie abraza tu ") print("cuerpo y bebe de la abundante sangre, que como una fuente mana de tu cuello ") print("desgarrado y mancha y se esparce por todo alrededor..."+CR) print("Al fin tu cuerpo cae rendido al suelo junto con el zombie, que no para de beber y morder y profanar tus entrañas. "+CR) else if Random(1,2)>1 then print("Notas el vacío en "+zonadesc+" que cae al suelo con el zombie detrás, que se arrodilla para seguir mamando de la ") print("abundante sangre del miembro amputado."+CR) else print("Como un peso muerto "+zonadesc+" cae al suelo chorreando sangre, mientras el zombie empieza a beber de la fuente imparable que sale del muñon. "+CR) endif endif else if Random(1,2)>1 then print("El dolor es insoportable, invade todos tu sentidos, ") else print("No puedes reprimir un grito de terror, ") endif if Random(1,2)>1 then print("mientras ves como su boca bebe ávida de la herida abierta. "+CR) else print("mientras la sangre cae al suelo, formando charcos rojos. "+CR) endif endif if muerte then print("Finalmente no puedes resistir más el dolor. La vista se te empieza a ") print("emborronar por la falta de oxígeno y la sangre perdida, y quedas a merced ") print("de los zombies... mientras te sumes en la oscuridad."+CR) USR_Fin(1) endif Endif endif // fin del caso en que el jugador sea victima de un zombie endif // si el jugador era atacante o un PSI else // Notificaciones cuando NO SE TIENE EXITO AL ATACAR Select psi CASE PSIJugador if tipo="empujar" then print("Fallas torpemente el empujón, lo que te lleva a estar más cerca del abrazo del zombie."+CR) endif if tipo="golpear" then if nohay then print("Pero... ¡Si no tiene "+zonadesc+"!"+CR) else print("Lanzas el golpe a "+zonadesc+" pero le rozas levemente y no llegas a golpear"+Pronombre(psi2)+" efectivamente."+CR) endif endif CASE * if psi2=PSIJugador then print("Murmurando "+PSI[psi].DescCorta+" se abalanza sobre ti, pero consigues zafarte de sus fauces. "+CR) endif EndSelect endif return // -------------------------------------------------------- // jugador pide objeto a PSI // recibe: // 'psi' PSI al que nos dirigimos // -------------------------------------------------------- Sub PSIDame(psi) Declare(i) Declare(obj) Declare(lista) Declare(todo) Declare(txt_dice) txt_dice:="dice " + PSI[psi].DescCorta + "." // comprobamos si quiere que le de TODO If ParseNombre1="TODO" Then lista:=PSI[psi].Objetos If ArrayLen(lista)=0 Then HablaPSI("No tengo nada que pueda darte.",txt_dice) Return EndIf todo:=TRUE Else obj:=NombreCompleto(ParseNombre1,ParseAdjetivo1) If obj="" Then HablaPSI("¿Qué quieres que te dé?",txt_dice) Return EndIf lista:=Search(obj,"TipoContenedor=2,Contenedor=" + psi,9) todo:=FALSE EndIf Select ArrayLen(lista) Case 0 HablaPSI("No tengo eso.",txt_dice) Return Case 1 // si hemos encontrado sólo uno se lo damos obj:=ArrayItem(lista,1) If PSI[psi].Dejar(obj) Then HablaPSI("Toma " + DescObj(obj) + ".",txt_dice) ParseVerbo:="COGER" ParseNombre1:=OBJ[obj].Nombre ParseAdjetivo1:=OBJ[obj].Adjetivo Coger() Else HablaPSI("No te puedo dar " + DescObj(obj) + ".",txt_dice) EndIf Case * If Not(todo) Then // si hemos encontrado más de uno debe especificar cuál debe darle HablaPSI("¿Qué " + LCase(obj) + " quieres que te dé?",txt_dice) Return Else // intentamos dar todos los objetos For i:=1 To ArrayLen(lista) obj:=ArrayItem(lista,i) If PSI[psi].Dejar(obj) Then HablaPSI("Toma " + DescObj(obj) + ".",txt_dice) ParseVerbo:="COGER" ParseNombre1:=OBJ[obj].Nombre ParseAdjetivo1:=OBJ[obj].Adjetivo Coger() Else HablaPSI("No te puedo dar " + DescObj(obj) + ".",txt_dice) EndIf Next EndIf EndSelect Return // PSIs_IA() se encarga de mover los Psis y de posibles acciones que ellos desempeñen. // En este juego hace sólo dos cosas: o moverse en busca del JUGADOR o intentar // COMERSELO que será cuando ataquen. sub PSIs_IA() declare(i) For i:=0 To NumPSI-1 // saltamos el PSI del jugador If i<>PSIJugador Then PSI_IA(i) endif next return // PSI_IA(psi) este controla la mente de un solo PSI, y decide el paso a ejecutar // por él. Sólo lo mueve cuando le llega su TURNO=0 según la LENTITUD. // También según el estado en el que se encuentre... si está dormido, por ejemplo. sub PSI_IA(psi) declare(objetivo) if NOT(PSI[psi].Muerto)&(NOT(PSI[psi].Localidad="")) then //los muertos y los que esten en el limbo, no harán nada. if LOC[PSI[psi].Localidad].Marabunta then Reciclar(psi) // si un PSI está dentro de la marabunta se funde con ella. else if PSI[psi].Turno>0 then PSI[psi].Turno:=PSI[psi].Turno-1 else PSI[psi].Turno:=PSI[psi].Lentitud objetivo:=PSI[psi].Objetivo if PSI[psi].Estado="dormido" then // con 'dormido' tb pueden hacer acciones if PSI[psi].localidad=PSI[PSIJugador].Localidad then print(PSI[psi].DescCorta+" emite unos murmullos guturales. Respira profundamente como si durmiera."+CR) endif else if (PSI[psi].vida_pierna_izq<=0)&(PSI[psi].vida_pierna_dch<=0)&(PSI[psi].vida_brazo_izq<=0)&(PSI[psi].vida_brazo_dch<=0) then if PSI[psi].localidad=PSI[PSIJugador].Localidad then print("Con espasmos, el "+LCase(NombreCompleto(PSI[psi].nombre,PSI[psi].adjetivo))+" se convulsiona en el sitio indefenso, intentando moverse sin brazos ni piernas... parece un pez agonizante fuera del agua."+CR) endif else if (objetivo<>"") then if PSI[psi].Localidad=PSI[objetivo].Localidad then if PSI[objetivo].Muerto then PSI[psi].Objetivo:="" PSI[psi].MOV_RUTA="SEMIALEATORIO" return endif if PSI[psi].Hostil then if (PSI[psi].vida_pierna_izq<=0)|(PSI[psi].vida_pierna_dch<=0) then PSIAtaca(psi,PSI[psi].TIPO_ATAQUE,objetivo,"PIERNA") else PSIAtaca(psi,PSI[psi].TIPO_ATAQUE,objetivo,"") endif endif else PSIMueve(psi) endif else // Si no hay ningún tipo de objetivo, Mueve. PSIMueve(psi) endif // si el objetivo endif // si no tiene miembros... endif endif endif // de la marabunta endif return // -------------------------------------------------------- // mueve al PSI en cuestión. // este procedimiento usa la variable de PSI: MOV_RUTA para decidir que tipo de // movimiento realizará: // Puede tomar los siguientes valores: // -Un array con la ruta específica a seguir. // -SEGUIR, que hará que el PSI siga al OBJETIVO especificado. Siempre que le // sea visible, si el OBJETIVO se aleja, el PSI seguirá avanzando SEMIALEATORIAMENTE. // -SEMIALEATORIO, que moverá al PSI aleatoriamente según lo indicado en DIRECCION. // -ESTATICO, no se moverá // // Variables usadas: // MOV_PASO: contiene el índice del array del siguiente paso de la ruta // debería inicializarse a 1 // MOV_REPETIR: si es 1 el PSI repetirá la ruta desde el principio // cuando se llegue al final de la misma, para ello // se debería definir una ruta circular, es decir, que // acabe en la misma localidad donde se inició // si es 0 el PSI se parará cuando complete la ruta // DIRECCION: Es un array con las posibles direcciones en que se moverá, // si está vacío no se moverá, si esta repleto de todos las direcciones // será completamente aleatorio; si sólo tiene un par de ellas, se // consigue que el PSI vague hacia una dirección semialeatorimente. // VIENE_DE: Dirección por la que ha llegado el PSI (si es posible saberla). // Se chequeará que sea lógica esa conexión. // OBJETIVO: Marca el objetivo a seguir o a atacar por el PSI, en este caso para // Seguirle. // // NOTA: Es importante ver que el procedimiento primero calcula donde y como mover // y después lo ejecuta y notifica al jugado si está presente. // MEJORAS: Aún no controla si hay puertas cerradas, en el futuro lo hará. // Pero es que para este juego no hace falta. // -------------------------------------------------------- Sub PSIMueve(psi) declare(movido) declare(camino) declare(i) declare(conex) declare(longconex) declare(loc_ant) declare(dir) movido:=FALSE camino:=UCASE(PSI[psi].Mov_ruta) if camino="" then camino:="ESTATICO" endif if camino="ESTATICO" then movido:=FALSE endif if camino="SEGUIR" then conex:=BuscaPSIAdy(PSI[psi].Localidad,PSI[psi].Objetivo) // busca el objetivo en los alrededores, y devuelve la dirección por donde está if conex<>"" then // si el PSI-objetivo está cerca, lo seguirá loc_ant:=PSI[psi].Localidad if MoverCond(psi,conex) then // Chequea si se permite mover. movido:=PSI[psi].Mover(conex) endif dir:=conex // esto es para la notificación de después. else // si no, seguirá moviendose en busca de su objetivo. camino:="SEMIALEATORIO" endif endif if (camino="SEMIALEATORIO")|(camino="ALEATORIO") then // aleatorio y semi, usan las mismas variables y rutinas. conex:=PSI[psi].Direccion // aqui se almacenan las posibles direcciones donde el PSI irá preferiblemente. loc_ant:=PSI[psi].Localidad while NOT(movido) // este bucle intenta una y otra vez mover en las... longconex:=ArrayLen(conex) //... posibles direccione contenidas en PSI[psi].Direccion. if (longconex=0)|(camino="ALEATORIO") then // esta zona actualiza el campo Dirección a todas las salidas posibles, en cada turno. conex:=LOC[PSI[psi].Localidad].Conexiones // todas las salidas posibles PSI[psi].Direccion:="" // borra el campo Direccion. longconex:=Arraylen(conex)/2 if longconex=0 then // IMPOSIBLE MOVERSE!!! return endif for i:=1 to longconex PSI[psi].Direccion:=ArrayInsert(PSI[psi].Direccion,1,ArrayItem(conex,(i*2)-1)) next conex:=PSI[psi].Direccion longconex:=ArrayLen(conex) endif i:=Random(1,longconex) // elige al azar entre las posibles direcciones dir:=ArrayItem(conex,i) if MoverCond(psi,dir) then // chequea si se permite mover movido:=PSI[psi].Mover(dir) endif if NOT(movido) then // si no mueve descarta esa salida pero... conex:=ArrayRemove(conex,i) //... no en el campo Direccion, sólo temporalmente, para este movimiento. endif loop endif if movido then // si se mueve hay que hacer algunas cosillas... PSI[psi].Viene_De:=DirContr(dir) // Usa DirPsi(dir) para cuando un PSI se va. USR_Movcontrario pa cuando llega. // notificamos al jugador si está en la misma localidad, tanto a la ida como a la vuelta. If (PSI[PSIJugador].Localidad=loc_ant) Then // esto es que se va Print(PSI[psi].DescCorta + " " + DirPSI(dir) + "." + CR) Else If (PSI[PSIJugador].Localidad=PSI[psi].Localidad) Then // esto es que viene Print(PSI[psi].DescCorta + " " + DirViene(dir)) if (PSI[psi].vida_pierna_izq<=0)|(PSI[psi].vida_pierna_dch<=0) then print(" arrastrándose por el suelo como puede."+CR) else if Random(1,2)>1 then print(" arrastrando los pies hasta aqui."+CR) else if Random(1,2)<2 then print(" con paso lento pero decidido."+CR) else print(" con paso agonizante."+CR) endif endif // del random de arrastrando los pies endif // de arrastrandose por el suelo EndIf // si el PSI viene... EndIf // si el PSI se va... EndIf // si ha movido Return // Reciclar(psi) esto recicla un psi, para hacer luego un psi nuevo con Generar(psi). // Vamos... que lo pone fuera de circulación. sub Reciclar(psi) PSI[psi].Localidad:="" return // QuitaObjetos Pone en el limbo todos los objetos de un PSI. sub RobaObjetos(psi) declare(lista) declare(i) declare(long) declare(obj) lista:=PSI[psi].Objetos() long:=ArrayLen(lista) if (long>0) then for i:=1 to long obj:=ArrayItem(lista,i) OBJ[obj].Contenedor:="" next endif return