| 07-09-2007, 04:06 AM | #1 |
Hi: From now on I'm going to fill this section with my problems in JASS for my project Power of Corruption. I've developed one spell called Water shield, as a replacement of frost armor. This spell gives to the allied a shield which absorbs a random percentage of damage, up to 50% of the damage dealt. Because I'm using dynamic triggers, I decided to test one Vex's experiments, where you use the conditional function instead of the action function. You can see here. After hours of testing, it doesn't work, and I don't know if I'm skipping something or what. If somebody ask me: "why aren't you using structs" the answer is simple: this is one spell that I did some months ago as a testing, and I'm on the conversion process. In fact, it worked before I did the modifications with the conditionals. Here's the code. The yellow parts shows where the script creates the dymamic triggers: JASS://*************************************************************************************************************** //* * //* Water Shield Spell. * //* By Moyack. * //* V.1.0. * //* * //*************************************************************************************************************** library WaterShield initializer InitTrig_WaterShield requires CSSafety, HandleVars //*************************************************************************************************************** //* The constant functions where you can modify the ability properties //* private constant function WaterShield_SpellID takes nothing returns integer // Dummy Ability Rawcode. Spell based on FROST ARMOR return 'A01F' endfunction private constant function WaterShield_BuffID takes nothing returns integer // Dummy buff Rawcode. Buff based on FROST ARMOR return 'B00T' endfunction private constant function WaterShield_dt takes nothing returns real // number of times that verify return 0.1 endfunction private constant function WaterShield_Chance takes integer level returns real // Returns the chance of absorbing any damage return 0.5 + 0.25 * (level - 1) endfunction //*************************************************************************************************************** //* The custom functions //* private function WaterShield_Damage takes nothing returns boolean // Shows the effect and control the damage dealt to the shield's owner local unit c = GetTriggerUnit() local timer t = GetHandleTimer(c, "timer") local integer l = GetHandleInt(t, "level") local real ch = GetRandomReal(0., WaterShield_Chance(l) * 100.) local real dam = (100. - ch) * GetEventDamage() / 100. local texttag tx = CreateTextTag() call SetWidgetLife(GetTriggerUnit(), GetWidgetLife(GetTriggerUnit()) + dam) call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById(WaterShield_SpellID(), EFFECT_TYPE_SPECIAL, 0), GetTriggerUnit(), "chest")) call SetTextTagText(tx, I2S(R2I(ch)) + "%", 0.023) call SetTextTagPosUnit(tx, c, 5.) call SetTextTagColor(tx, 0, 174, 239, 0) call SetTextTagVelocity(tx, 0., 120. * 0.071 / 128.) call SetTextTagPermanent(tx, false) call SetTextTagLifespan(tx, 3.) call SetTextTagFadepoint(tx, 2.) call SetTextTagVisibility(tx, true) set c = null set t = null return false endfunction private function WaterShield_loop takes nothing returns nothing //Checks when the spell ends so it can clean the variables local timer tm = GetExpiredTimer() if GetUnitAbilityLevel(GetHandleUnit(tm, "target"), WaterShield_BuffID()) == 0 then call DestroyTrigger(GetHandleTrigger(tm, "trigger")) call FlushHandleLocals(GetHandleUnit(tm, "target")) call FlushHandleLocals(tm) call ReleaseTimer(tm) endif set tm = null endfunction //*************************************************************************************************************** //* * //* Water Shield Casting Functions * //* * //*************************************************************************************************************** //*************************************************************************************************************** //* Water Shield Control casting condition //* private function WaterShield_Conditions takes nothing returns boolean return GetSpellAbilityId() == WaterShield_SpellID() endfunction private function WaterShield_Actions takes nothing returns nothing // Creates the trigger that will detect the damage to the target unit local timer tm = NewTimer() local boolexpr Cnd = Condition(function WaterShield_Damage) call SetHandleHandle(GetSpellTargetUnit(), "timer", tm) call SetHandleHandle(tm, "caster", GetTriggerUnit()) call SetHandleHandle(tm, "target", GetSpellTargetUnit()) call SetHandleInt(tm, "level", GetUnitAbilityLevel(GetSpellAbilityUnit(), WaterShield_SpellID())) call SetHandleHandle(tm, "trigger", CreateTrigger()) call TriggerRegisterUnitEvent(GetHandleTrigger(tm, "trigger"), GetSpellTargetUnit(), EVENT_UNIT_DAMAGED) call TriggerAddCondition(GetHandleTrigger(tm, "trigger"), Cnd) call TimerStart(tm, WaterShield_dt(), true, function WaterShield_loop) call DestroyBoolExpr(Cnd) set tm = null set Cnd = null endfunction //=========================================================================== function InitTrig_WaterShield takes nothing returns nothing local trigger t = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( t, Condition( function WaterShield_Conditions ) ) call TriggerAddAction(t, function WaterShield_Actions) call Preload(GetAbilityEffectById(WaterShield_SpellID(), EFFECT_TYPE_SPECIAL, 0)) set t = null endfunction endlibrary Thanks for your help |
| 07-09-2007, 05:34 AM | #2 |
You shouldn't the destroy the condition if you don't want to corrupt the trigger. Remove the line JASS:call DestroyBoolExpr(Cnd) |
| 07-10-2007, 02:10 AM | #3 |
Lovely!!! it works!!! thanks PitzerMike :) Because I needed to keep the Boolexpr until the spell is finished, I implemented the structs so we can handle better that handle. Here's the code of this spell so far, working in the best way XD Water Shield converted totally to vJASS://*************************************************************************************************************** //* * //* Water Shield Spell. * //* By Moyack. * //* V.2.0. * //* * //*************************************************************************************************************** library WaterShield initializer InitTrig_WaterShield requires CSSafety, HandleVars struct watershield unit c unit t integer lvl trigger trg boolexpr b static method create takes unit caster, unit target, integer SpellLevel, code DamFunc returns watershield local watershield w = watershield.allocate() set w.c = caster set w.t = target set w.lvl = SpellLevel set w.trg = CreateTrigger() set w.b = Condition(DamFunc) return w endmethod method onDestroy takes nothing returns nothing call DestroyTrigger(.trg) call DestroyBoolExpr(.b) set .trg = null set .b = null endmethod endstruct struct wscatcher watershield ws timer t static method create takes watershield w returns wscatcher local wscatcher wc = wscatcher.allocate() set wc.ws = w set wc.t = NewTimer() return wc endmethod method onDestroy takes nothing returns nothing call watershield.destroy(.ws) call ReleaseTimer(.t) endmethod endstruct globals //*************************************************************************************************************** //* The constant functions where you can modify the ability properties //* private constant integer WaterShield_SpellID = 'A01F' // Dummy Ability Rawcode. Spell based on FROST ARMOR private constant integer WaterShield_BuffID = 'B00T' // Dummy buff Rawcode. Buff based on FROST ARMOR private constant real WaterShield_dt = 0.1 // number of times that the spell verify the buff endglobals private constant function WaterShield_Chance takes integer level returns real // Returns the chance of absorbing any damage return 0.75 + 0.25 * (level - 1) endfunction //*************************************************************************************************************** //* The custom functions //* private function WaterShield_Damage takes nothing returns boolean local unit c = GetTriggerUnit() local timer tm = GetHandleTimer(c, "timer") local wscatcher wc = wscatcher(GetHandleInt(tm, "wc")) local integer l = wc.ws.lvl local real ch = GetRandomReal(0., WaterShield_Chance(l) * 100.) local real dam = ch * GetEventDamage() / 100. local texttag tx = CreateTextTag() call SetWidgetLife(c, GetWidgetLife(c) + dam) call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById(WaterShield_SpellID, EFFECT_TYPE_SPECIAL, 0), GetTriggerUnit(), "chest")) call SetTextTagText(tx, I2S(R2I(ch)) + "%", 0.023) call SetTextTagPosUnit(tx, c, 5.) call SetTextTagColor(tx, 0, 174, 239, 0) call SetTextTagVelocity(tx, 0., 350. * 0.071 / 128.) call SetTextTagPermanent(tx, false) call SetTextTagLifespan(tx, 3.) call SetTextTagFadepoint(tx, 2.) call SetTextTagVisibility(tx, true) set c = null set tm = null return false endfunction private function WaterShield_loop takes nothing returns nothing local timer tm = GetExpiredTimer() local wscatcher wc = wscatcher(GetHandleInt(tm, "wc")) if GetUnitAbilityLevel(wc.ws.t, WaterShield_BuffID) == 0 then call wc.destroy() endif set tm = null endfunction //*************************************************************************************************************** //* * //* Water Shield Casting Functions * //* * //*************************************************************************************************************** //*************************************************************************************************************** //* Water Shield Control casting condition //* private function WaterShield_Conditions takes nothing returns boolean return GetSpellAbilityId() == WaterShield_SpellID endfunction private function WaterShield_Actions takes nothing returns nothing local watershield ws = watershield.create(GetTriggerUnit(), GetSpellTargetUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), WaterShield_SpellID), function WaterShield_Damage) local wscatcher wc = wscatcher.create(ws) call TriggerRegisterUnitEvent(ws.trg, ws.t, EVENT_UNIT_DAMAGED) call TriggerAddCondition(ws.trg, ws.b) call SetHandleInt(wc.t, "wc", wc) call SetHandleHandle(ws.t, "timer", wc.t) call TimerStart(wc.t, WaterShield_dt, true, function WaterShield_loop) endfunction //=========================================================================== function InitTrig_WaterShield takes nothing returns nothing local trigger t = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( t, Condition( function WaterShield_Conditions ) ) call TriggerAddAction(t, function WaterShield_Actions) call Preload(GetAbilityEffectById(WaterShield_SpellID, EFFECT_TYPE_SPECIAL, 0)) set t = null endfunction endlibrary Now with this, this spell creates and releases the timer easily. I have now other questions: Is there any way to replace the GetHandleInt / SetHandleInt functions, so I can say bye to HandleVars?? |
| 07-10-2007, 11:48 AM | #4 |
Good to see PoC advancing. |
| 07-10-2007, 06:16 PM | #5 |
Yeah, let's just hope the league of anti corruption won't step in. |
| 07-10-2007, 06:34 PM | #6 |
All BoolExprs created from a particular condition are the same handle. They are odd creatures. Destroying a 'local' boolexpr can destroy others. |
| 07-10-2007, 07:31 PM | #7 | |
Quote:
JASS:globals //*************************************************************************************************************** //* The constant functions where you can modify the ability properties //* private constant integer WaterShield_SpellID = 'A01F' // Dummy Ability Rawcode. Spell based on FROST ARMOR private constant integer WaterShield_BuffID = 'B00T' // Dummy buff Rawcode. Buff based on FROST ARMOR private constant real WaterShield_dt = 0.1 // number of times that the spell verify the buff // Become this boolexpr a glbal variable which should be initialized at the beginning and not destroyed. private boolexpr ShieldScript endglobals ... function InitTrig_WaterShield takes nothing returns nothing local trigger t = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( t, Condition( function WaterShield_Conditions ) ) call TriggerAddAction(t, function WaterShield_Actions) call Preload(GetAbilityEffectById(WaterShield_SpellID, EFFECT_TYPE_SPECIAL, 0)) set ShieldScript = Condition(function WaterShield_Damage) set t = null endfunction |
| 07-10-2007, 08:18 PM | #8 |
does the alot of "stars" (*) making your script more awesome ? ... xD well boolexpr are like strings they are stored in some table and they need to be inited only 1 time per function name. to destroy them it's a pure imbecility :freak: |
| 07-10-2007, 08:54 PM | #9 | |
Quote:
I like how it looks, that's all, plus it helps me to separate parts of the code, making more readable to me. |
| 07-11-2007, 06:49 AM | #10 | |
moyack ;) Quote:
|
