Hola,
Os presento un sistema para crear fácilmente lo que llamo Areas de Efecto, versión 1.0 Beta.
Consiste en un trigger y opcionalmente un ubicado controlador que aplican efectos a los personajes o criaturas que se encuentran dentro de dicho trigger, o lo cruzan, todo ello con 3 scripts.
El trigger aplica un efecto (entre 40 ahora mismo) que dura mientras estés dentro del trigger, opcionalmente afecta a criaturas no jugadoras y también opcionalmente permite configurar un objeto que te libra del daño (por ejemplo una gema de protección contra el mal o un casco de respirar bajo el agua) . Puedes configurar que este objeto deba estar equipado o simplemente vale con que esté en tu inventario.
Opcionalmente aplica un efecto visual al entrar y salir y otro mientras estés dentro del trigger.
Opcionalmente muestra un texto al entrar o salir del trigger (¡El aire de aquí me quema los pulmones!.... Ya se respira mejor)
Ejemplos de uso:
-Aplicar efecto de daño por fuego cada tanto tiempo si tu personaje se acerca al borde de un río de lava.
-Aplicar daño por ácido al permanecer en una habitación con atmósfera envenenada.
-Aplicar daño por frío y efecto de reducción de velocidad al estar bajo el agua, con efecto de burbujas)
-Aplicar en resumen cada uno de los tipos de daño, con efecto de daño (ejemplo 2d6), efecto visual y frase opcional al recibir daño (Ay ay, coff coff)
-Bonus a la armadura por cobertura.
-Zona santuario (¡Estoy en casa, no me puedes hacer nada!)
-Zona de magia muerta, que impide lanzar todos los hechizos, o solo de tal escuela (¡En el templo de Iuz no puedes lanzar curaciones!)
-Barrera antihechizos, que disipa toda tu magia o todos los hechizos hasta tal nivel.
-Zona de terreno dificil, que dificulta movimiento.
-Zona de alta velocidad --> como una cinta transportadora!
-Zona de polimorfizacion (para aventuras en las que te conviertes en pollo o rata o lo que sea para pasar desapercibido, o como broma o como trampa)
-Incrementar ataques, maximo 5 por turno por limitacion de motor.
-Zonas elementales (ejemplo Plano del Aire: daño incrementado electrico, no puedes usar hechizos de fuego, mas velocidad)
-Zona de bonus al ataque por ventaja, por ejemplo zona alta vs zona baja
-Apresurar, Enlentecer
-Reduccion de daño
-Resistencia a la magia
-Así hasta 40 efectos en esta versión
Fácilmente configurable por variables que se ponen en el trigger y si usas ubicado controlador en el controlador.
Optimizado para no requerir mucha CPU, en el caso de daño por tiempo.
El efecto se puede desactivar. Al usar una palanca desaparecen los vapores, etc etc.
Ver el módulo de ejemplo para ver cómo se configura y haceros una idea de los usos.
Scripts:
On Enter del Trigger
//:://///////////////////////////////////////////// //:: TIERRA DE HEROES - oe_area_efecto //:: Copyright (c) 2018 Fran Luque (Avernum). //::////////////////////////////////////////////// /* oe_area_efecto oh_area_efecto ox_area_efecto */ //::////////////////////////////////////////////// //:: Created By: Fran Luque //:: Created On: 12/05/2018 //:: Last Updated: 01/05/2020 //::////////////////////////////////////////////// void main() { //if (GetLocalInt(OBJECT_SELF, "AreaDesactivada")==TRUE){return;} object oPC = GetEnteringObject(); string sFraseEnter = GetLocalString(OBJECT_SELF,"FraseEnter"); int iEfectoSobrePJ = GetLocalInt(OBJECT_SELF, "EfectoSobrePJ"); int iFX = GetLocalInt(OBJECT_SELF, "FXPermanente"); int iFXInstant = GetLocalInt(OBJECT_SELF, "FXInstant"); int iParam1 = GetLocalInt(OBJECT_SELF, "Parametro1"); int iParam2 = GetLocalInt(OBJECT_SELF, "Parametro2"); int iParam3 = GetLocalInt(OBJECT_SELF, "Parametro3"); string sMiTag = GetTag(OBJECT_SELF); effect eEfectoPJ; effect eFX; effect eFXInstant; if (GetLocalInt(OBJECT_SELF,"AfectaEnemigos")==FALSE) { if (!GetIsPC(oPC)) return; } SetLocalInt (oPC, "EfectoAreaEfecto"+sMiTag, GetTimeSecond() + 1); //Efectos mientras estes en el area de efecto, independientes de oh_area_efecto //EffectSlow //EffectBlindness //EffectCurse //EffectConcealment(50,MISS_CHANCE_TYPE_NORMAL); //EffectDarkness //EffectMovementSpeedDecrease(porcentaje); //EffectMovementSpeedIncrease(porcentaje); //EffectRegenerate(cantidad, cadaxsegundos); //EffectSanctuary(dc); //EffectSpellFailure(porcentaje,SPELL_SCHOOL_GENERAL); //Dispel //Polymorph //Swarm ATENCION: Los bichos swarmeados seran parte de la party del pj , o sea sus colegas if (iEfectoSobrePJ!=0) { switch(iEfectoSobrePJ) { case 1: eEfectoPJ = EffectSlow(); break; case 2: eEfectoPJ = EffectBlindness(); break; case 3: eEfectoPJ = EffectCurse(); break; case 4: eEfectoPJ = EffectConcealment(iParam1, iParam2); break; //50,MISS_CHANCE_TYPE_NORMAL case 5: eEfectoPJ = EffectDarkness(); break; case 6: eEfectoPJ = EffectMovementSpeedIncrease(iParam1); break; //Porcentaje case 7: eEfectoPJ = EffectMovementSpeedDecrease(iParam1); break; //Porcentaje case 8: eEfectoPJ = EffectRegenerate(iParam1, 1.0f); break; //Cantidad por segundo case 9: eEfectoPJ = EffectSanctuary(iParam1); break; //DC case 10: eEfectoPJ = EffectSpellFailure(iParam1, iParam2); break; //100(porcentaje),SPELL_SCHOOL_GENERAL case 11: eEfectoPJ = EffectDispelMagicAll(iParam1); break; //Nivel case 12: eEfectoPJ = EffectPolymorph(iParam1, TRUE); break; //POLYMORPH_TYPE_CHICKEN case 13: eEfectoPJ = EffectSwarm(TRUE, "zep_skeldolls", "zep_skeldwarf", "zep_skeldolls", "zep_skeldwarf"); break; case 14: eEfectoPJ = EffectHaste(); break; case 15: eEfectoPJ = EffectTrueSeeing(); break; case 16: eEfectoPJ = EffectDamageIncrease(iParam1, iParam2); break; //int nBonus, int nDamageType=DAMAGE_TYPE_MAGICAL case 17: eEfectoPJ = EffectDamageDecrease(iParam1, iParam2); break; //int nPenalty, int nDamageType=DAMAGE_TYPE_MAGICAL case 18: eEfectoPJ = EffectDamageImmunityIncrease(iParam1, iParam2); break; //DAMAGE_TYPE_MAGICAL, 50 case 19: eEfectoPJ = EffectDamageImmunityDecrease(iParam1, iParam2); break; //DAMAGE_TYPE_MAGICAL, 50 case 20: eEfectoPJ = EffectNegativeLevel(iParam1); break; //Niveles case 21: eEfectoPJ = EffectTemporaryHitpoints(iParam1); break; //HP case 22: eEfectoPJ = EffectSpellResistanceIncrease(iParam1); break; //Cantidad case 23: eEfectoPJ = EffectSpellResistanceDecrease(iParam1); break; //Cantidad case 24: eEfectoPJ = EffectAbilityIncrease(iParam1, iParam2); break; //ABILITY_CONSTITUTION,6 case 25: eEfectoPJ = EffectAbilityDecrease(iParam1, iParam2); break; //ABILITY_CONSTITUTION,6 case 26: eEfectoPJ = EffectSavingThrowIncrease(iParam1, iParam2); break; //SAVING_THROW_ALL,5 case 27: eEfectoPJ = EffectSavingThrowDecrease(iParam1, iParam2); break; //SAVING_THROW_ALL,5 case 28: eEfectoPJ = EffectACIncrease(iParam1); break; //Cantidad CA case 29: eEfectoPJ = EffectACDecrease(iParam1); break; //Cantidad CA case 30: eEfectoPJ = EffectAttackIncrease(iParam1); break; //Cantidad bonus ataques case 31: eEfectoPJ = EffectAttackDecrease(iParam1); break; //Cantidad bonus ataques case 32: eEfectoPJ = EffectSkillIncrease(iParam1, iParam2); break; //SKILL_CONCENTRATION,5 case 33: eEfectoPJ = EffectSkillDecrease(iParam1, iParam2); break; //SKILL_CONCENTRATION,5 case 34: eEfectoPJ = EffectDamageReduction(iParam1, iParam2); break; //10/+4 por ejemplo case 35: eEfectoPJ = EffectDamageResistance(iParam1, iParam2); break; //DAMAGE_TYPE_MAGICAL, 10 case 36: eEfectoPJ = EffectDamageShield(iParam1, iParam2, iParam3); break; //5, DAMAGE_BONUS_*, DAMAGE_TYPE_* case 37: eEfectoPJ = EffectImmunity(iParam1); break; //IMMUNITY_TYPE_* case 38: eEfectoPJ = EffectMissChance(iParam1); break; //Porcentaje fallo case 39: eEfectoPJ = EffectModifyAttacks(iParam1); break; //5 max case 40: eEfectoPJ = EffectSpellImmunity(iParam1); break; //SPELL_* o -1 para todos } eEfectoPJ = TagEffect(eEfectoPJ, "EfectoAreaEfecto"+sMiTag); eEfectoPJ = SupernaturalEffect(eEfectoPJ); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEfectoPJ, oPC); } //FX mientras estes en area de efecto (VFX_DUR) if (iFX!=0) { eFX = EffectVisualEffect(iFX); eFX = TagEffect(eFX, "EfectoAreaEfecto"+sMiTag); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eFX, oPC); } //FX instantaneo al entrar en la zona (VFX_FNF, VFX_IMP, VFX_COM if (iFXInstant!=0) { eFXInstant = EffectVisualEffect(iFXInstant); ApplyEffectToObject(DURATION_TYPE_INSTANT, eFXInstant, oPC); } //Texto informativo al entrar en el trigger if (sFraseEnter!=""){FloatingTextStringOnCreature(sFraseEnter, oPC, FALSE);} }
On Exit del Trigger
//:://///////////////////////////////////////////// //:: TIERRA DE HEROES - ox_area_efecto //:: Copyright (c) 2018 Fran Luque (Avernum). //::////////////////////////////////////////////// /* oe_area_efecto oh_area_efecto ox_area_efecto */ //::////////////////////////////////////////////// //:: Created By: Fran Luque //:: Created On: 12/05/2018 //:: Last Updated: 03/04/2020 //::////////////////////////////////////////////// void main() { object oPC = GetExitingObject(); string sFraseExit = GetLocalString(OBJECT_SELF,"FraseExit"); int iFXInstant = GetLocalInt(OBJECT_SELF, "FXInstantExit"); string sMiTag = GetTag(OBJECT_SELF); effect eFXInstant; if (GetLocalInt(OBJECT_SELF,"AfectaEnemigos")==FALSE) { if (!GetIsPC(oPC)) return; } SetLocalInt (oPC, "EfectoAreaEfecto"+sMiTag, FALSE); if (sFraseExit!=""){FloatingTextStringOnCreature(sFraseExit, oPC, FALSE);} //Quitar efectos aplicados al entrar en trigger - oe_area_efecto effect eLoop = GetFirstEffect(oPC); while (GetIsEffectValid(eLoop)) { if (GetEffectTag(eLoop)=="EfectoAreaEfecto"+sMiTag) { RemoveEffect(oPC, eLoop); } eLoop = GetNextEffect(oPC); } //FX instantaneo al salir de la zona (VFX_FNF, VFX_IMP, VFX_COM if (iFXInstant!=0) { eFXInstant = EffectVisualEffect(iFXInstant); ApplyEffectToObject(DURATION_TYPE_INSTANT, eFXInstant, oPC); } }
On Heartbeat del Ubicado controlador (opcional, solo si quieres efectos durante tiempo)
//:://///////////////////////////////////////////// //:: TIERRA DE HEROES - oh_area_efecto //:: Copyright (c) 2020 Fran Luque (Avernum). //::////////////////////////////////////////////// /* Sistema de Areas de Efecto de Daño -Refactorizado: Ahora 1 solo heartbeat por grupo de areas, en vez de N*areas de efecto oe_area_efecto oh_area_efecto ox_area_efecto Ejemplo: Daño fuego al estar cerca de lava Daño de veneno por atmosfera venenosa DAMAGE_TYPE_ACID 16 DAMAGE_TYPE_BLUDGEONING 1 DAMAGE_TYPE_COLD 32 DAMAGE_TYPE_DIVINE 64 DAMAGE_TYPE_ELECTRICAL 128 DAMAGE_TYPE_FIRE 256 DAMAGE_TYPE_MAGICAL 8 DAMAGE_TYPE_NEGATIVE 512 DAMAGE_TYPE_PIERCING 2 DAMAGE_TYPE_POSITIVE 1024 DAMAGE_TYPE_SLASHING 4 DAMAGE_TYPE_SONIC 2048 Fuego effect eDam = EffectDamage(daño,DAMAGE_TYPE_FIRE); effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M); maligno effect eDam = EffectDamage(daño,DAMAGE_TYPE_NEGATIVE); effect eVis = EffectVisualEffect(VFX_IMP_EVIL_HELP); veneno effect eDam = EffectDamage(daño,DAMAGE_TYPE_ACID); effect eVis = EffectVisualEffect(VFX_IMP_POISON_L); */ //::////////////////////////////////////////////// //:: Created By: Fran Luque //:: Created On: 12/05/2018 //:: Last Update: 02/05/2020 //::////////////////////////////////////////////// // Devuelve TRUE o FALSE dependiendo de si hay algun jugador en el area // Uso: if( CheckForPCInArea( GetArea(OBJECT_SELF) ) == FALSE ){return;} int CheckForPCInArea(object oArea){object oPC = GetFirstPC();while ( oPC!=OBJECT_INVALID ){if( GetArea(oPC)==oArea ){return TRUE;}else{oPC = GetNextPC();}}return FALSE;} //::////////////////////////////////////////////// int CheckForItem(object oQuien, string sTagItem, int iEquipado) { int iLoTienes = FALSE; object oItem; string sTagoItem; int i; if (iEquipado==TRUE) { for (i = 0; i < NUM_INVENTORY_SLOTS; ++i) { oItem = GetItemInSlot(i, oQuien); sTagoItem = GetTag(oItem); if (sTagoItem==sTagItem){iLoTienes=TRUE;} } } else if (iEquipado<=0) { oItem = GetItemPossessedBy(oQuien, sTagItem); if (GetIsObjectValid(oItem)){iLoTienes=TRUE;} } //if (iLoTienes==TRUE){SendMessageToPC(GetFirstPC(), "Tienes el item");} return iLoTienes; } //::////////////////////////////////////////////// void AplicarEfectoDMG(object oAreaEfecto, effect eDam, effect eVis, int iEquipado, int iChanceFrase = 0, string sFraseDmg = "", string sItemEscudo = "") { int iVar; int iCurrent = GetTimeSecond() + 1; //object oItemEscudo; object oInTrig = GetFirstInPersistentObject(oAreaEfecto, OBJECT_TYPE_CREATURE); while (oInTrig!=OBJECT_INVALID) { if (sItemEscudo!=""){ if (CheckForItem(oInTrig, sItemEscudo, iEquipado)==TRUE){return;}} iVar = GetLocalInt(oInTrig, "EfectoAreaEfecto"+GetTag(oAreaEfecto)); //SendMessageToPC(GetFirstPC(), "Nombre oIntrig: "+GetName(oInTrig)+", Tag: ["+GetTag(oInTrig)+"]"); if ((iVar < 0) || ((iVar > 0) && ((iCurrent + 60 - iVar) > 10))) { if (-iCurrent != iVar) { if (d100()<=iChanceFrase && sFraseDmg != ""){ FloatingTextStringOnCreature(sFraseDmg, oInTrig, TRUE); } ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam, oInTrig); ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis, oInTrig); } } oInTrig = GetNextInPersistentObject(oAreaEfecto, OBJECT_TYPE_CREATURE); } } //::////////////////////////////////////////////// void AplicarEfectoFX(object oAreaEfecto, effect eFX) { object oInTrig = GetFirstInPersistentObject(oAreaEfecto, OBJECT_TYPE_CREATURE); while (oInTrig!=OBJECT_INVALID) { ApplyEffectToObject(DURATION_TYPE_INSTANT, eFX, oInTrig); oInTrig = GetNextInPersistentObject(oAreaEfecto, OBJECT_TYPE_CREATURE); } } //::////////////////////////////////////////////// void main() { //SendMessageToPC(GetFirstPC(), "Oh_Area: "+GetName(GetArea(OBJECT_SELF))); if (GetLocalInt(OBJECT_SELF, "ControladorDesactivado")==TRUE){return;} object oArea = GetArea(OBJECT_SELF); if( CheckForPCInArea( oArea ) == FALSE ){return;} int iTipoDado = GetLocalInt(OBJECT_SELF, "TipoDado"); int iNumDados = GetLocalInt(OBJECT_SELF, "NumDados"); int iTipoDmg = GetLocalInt(OBJECT_SELF, "TipoDmg"); int iFXDMG = GetLocalInt(OBJECT_SELF, "FXDmg"); int iFXVisual = GetLocalInt(OBJECT_SELF, "FXVisual"); string sFraseDmg = GetLocalString(OBJECT_SELF, "FraseDmg"); int iChanceFrase = GetLocalInt(OBJECT_SELF, "ChanceFraseDmg"); string sTagAreaEfecto = GetLocalString(OBJECT_SELF, "TagAreaEfecto"); int iNumAreasEfecto = GetLocalInt(OBJECT_SELF, "NumAreasEfecto"); string sTagItemEscudo = GetLocalString(OBJECT_SELF, "TagItemEscudo"); int iItemEscudoEquipado = GetLocalInt(OBJECT_SELF, "ItemEscudoEquipado"); effect eFXDMG = EffectVisualEffect(iFXDMG); effect eFXVisual = EffectVisualEffect(iFXVisual);//VFX_DUR_BUBBLES effect eDam; int iDmg; string sTagLoop; object oAreaEfecto; if (iNumDados <= 0) { iNumDados = 1; } if (iTipoDado<=0) {iTipoDado = 6; } switch (iTipoDado) { case 2: iDmg = d2(iNumDados); break; case 3: iDmg = d3(iNumDados); break; case 4: iDmg = d4(iNumDados); break; case 6: iDmg = d6(iNumDados); break; case 8: iDmg = d8(iNumDados); break; case 10: iDmg = d10(iNumDados); break; case 12: iDmg = d12(iNumDados); break; case 20: iDmg = d20(iNumDados); break; case 100: iDmg = d100(iNumDados); break; } eDam = EffectDamage(iDmg,iTipoDmg,DAMAGE_POWER_PLUS_TWENTY); // -- Loop en Area *viejo y mas costoso en CPU /* while (oAreaEfecto!=OBJECT_INVALID) { sTagLoop = GetTag(oAreaEfecto); if (sTagLoop==sTagAreaEfecto) { //Si area activa... AplicarEfectoDMG(oAreaEfecto, eDam, eVis, iChanceFrase, sFraseDmg); } oAreaEfecto = GetNextObjectInArea(oArea); } */ // -- Fin Loop en Area //Optimizacion int i; for (i=1;i<=iNumAreasEfecto;i++) { oAreaEfecto = GetNearestObjectByTag(sTagAreaEfecto, OBJECT_SELF, i); if (GetIsObjectValid(oAreaEfecto)) { AplicarEfectoDMG(oAreaEfecto, eDam, eFXDMG, iItemEscudoEquipado, iChanceFrase, sFraseDmg, sTagItemEscudo); if (iFXVisual!=0){ AplicarEfectoFX(oAreaEfecto, eFXVisual); } } } }
Módulo de ejemplo:
https://mega.nz/file...je82_AGGJPmi8P8
Clave:
W5VlyavpWFMAH3-Es2MwZmGMpmQMje82_AGGJPmi8P8
¡Que lo disfrutéis!
Cualquier idea o mejora es bienvenida.
*Para la versión 2, se podrá aplicar más de un efecto por trigger*
Editado por Avernum, 03 May 2020 - 10:25 AM.