| 07-12-2008, 09:18 AM | #1 |
So, I've seen a person or two ask for continued help on making a spell work/coded better, and I thought "hell, why not try it?" BEFORE WE BEGIN: Can channeling spells be picked up by "Unit starts the effect of an ability"? (I'm almost 100% sure they can, I've used it for other channeling spells before) So, I went about making a (IMO) cool spell. Problem is, something must be crashing the thread before it even starts (wut?), because nothing happens when I cast it, and the BJDebugMsg's don't appear (not even the first one). So, a little spell background first: Breath of the Dragons Spell is based on Starfall (for the channeling). What the spell is supposed to do is summon a large dragon over the caster's head (just for show). After that happens, all the units along an area (line segment, actually) are damaged over and over (thanks Ammorth for the GroupEnumUnitsInRangeOfSeg scripts), and... stuff. I use Acid Bomb for a missile (thanks to Callahan for his dragon head missile models), and also a detection; it leaves a buff on the target(s) long enough to be detected so the unit can be damaged (I have to trigger all spell damage for my map). Yes, I use constant functions. It's because they're easy to edit and get inlined by Vex's optimizer anyways. BotD_Type is the "element" for this spell. You don't need to worry about it for any reason. I just started going a little farther in-depth with structs and stuff, so if you see ways I might be messing up or ways to work it better, don't hesitate to let me know. Finally, any optimizations (besides inlining the constants) you find, point them out to me. Well, with that aside, here's the code: JASS:constant function BotD_Ability_ID takes nothing returns integer return 'A001' endfunction constant function BotD_Dummy_ID takes nothing returns integer return 'A005' endfunction constant function BotD_Buff_ID takes nothing returns integer return 'B003' endfunction constant function BotD_Dragon_ID takes nothing returns integer return 'e001' endfunction constant function BotD_DummyCaster_ID takes nothing returns integer return 'e002' endfunction constant function BotD_Range takes nothing returns real return 500. //+ (level * 50) endfunction constant function BotD_Width takes nothing returns real return 300. endfunction constant function BotD_Damage takes nothing returns real return 30. //+ (level * 15) endfunction constant function BotD_Type takes nothing returns integer return 1 //Fire endfunction constant function BotD_Interval takes nothing returns real return .5 //Interval between waves endfunction constant function BotD_Check_Interval takes nothing returns real return .25 //Interval between checking units in the major group endfunction constant function BotD_Effect takes nothing returns string return "Abilities\\Spells\\Other\\Awaken\\Awaken.mdl" endfunction struct BotDDamage unit caster unit dragon integer level real facing real endpointX real endpointY static method create takes unit caster, integer lvl, real endX, real endY returns BotDDamage local BotDDamage data = BotDDamage.allocate() set data.caster = caster set data.level = lvl set data.endpointX = endX set data.endpointY = endY return data endmethod endstruct globals group BotD_Targets = CreateGroup() endglobals function Breath_of_the_Dragons_Filter takes nothing returns boolean local unit u = GetFilterUnit() local boolean b1 = IsUnitEnemy(u, GetOwningPlayer(GetTriggerUnit())) local boolean b2 = GetWidgetLife(u) > .405 local boolean b3 = GetUnitAbilityLevel(u, 'Avul') == 0 local boolean b4 = IsUnitInGroup(u, BotD_Targets) == false set u = null return b1 and b2 and b3 and b4 endfunction function Breath_of_the_Dragons_Grouping takes nothing returns nothing local BotDDamage data = GetHandleInt(GetExpiredTimer(), "BotDWave") local unit u = data.caster local real x = data.endpointX local real y = data.endpointY local group g = CreateGroup() local unit f local real x2 = GetUnitX(u) local real y2 = GetUnitY(u) call BJDebugMsg("Grouping enemies") if OrderId2String(GetUnitCurrentOrder(u)) == "starfall" then call GroupEnumUnitsInRangeOfSegNoCurveA(g, x2, y2, x, y, BotD_Width(), Condition(function Breath_of_the_Dragons_Filter)) call SetUnitAnimation(data.dragon, "attack" ) loop set f = FirstOfGroup(g) exitwhen f == null call IssueTargetOrder(CreateDummyUnit(GetOwningPlayer(u), BotD_DummyCaster_ID(), x2, y2, BotD_Dummy_ID(), data.level, true), "acidbomb", f) call GroupAddUnit(BotD_Targets, f) call GroupRemoveUnit(g, f) endloop else call DestroyEffect(AddSpecialEffect(BotD_Effect(), x2, y2)) call PauseTimer(GetExpiredTimer()) call DestroyTimer(GetExpiredTimer()) call KillUnit(data.dragon) endif call BJDebugMsg("Enemies Grouped: " + I2S(CountUnitsInGroup(g))) call DestroyGroup(g) set u = null set g = null set f = null call data.destroy() endfunction function Breath_of_the_Dragons_Filter2 takes nothing returns boolean local unit u = GetFilterUnit() local boolean b1 = GetUnitAbilityLevel(u, BotD_Buff_ID()) > 0 local boolean b2 = GetWidgetLife(u) > .405 local boolean b3 = GetUnitAbilityLevel(u, 'Avul') == 0 set u = null return b1 and b2 and b3 endfunction function Breath_of_the_Dragons_Damage takes nothing returns nothing local timer t = GetExpiredTimer() local BotDDamage data = GetHandleInt(t, "BotDInter") local unit u = data.caster local integer lvl = data.level local group g = CreateGroup() local unit f call BJDebugMsg("Checking for damagable targets") if CountUnitsInGroup(BotD_Targets) > 0 then call GroupAddGroup(BotD_Targets, g) loop set f = FirstOfGroup(g) exitwhen f == null call UnitDamageTarget(u, f, ArmorDamage(f, BotD_Damage() + (lvl * 15), BotD_Type()), false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null) call GroupRemoveUnit(g, f) call GroupRemoveUnit(BotD_Targets, f) endloop endif call DestroyGroup(g) call data.destroy() set t = null set u = null set g = null set f = null endfunction function Breath_of_the_Dragons_Conditions takes nothing returns boolean return ( GetSpellAbilityId() == BotD_Ability_ID() ) endfunction function Breath_of_the_Dragons_Actions takes nothing returns nothing local unit u = GetTriggerUnit() local real x = GetUnitX(u) local real y = GetUnitY(u) local real facing = GetUnitFacing(u) local unit u2 local integer lvl = GetUnitAbilityLevel(u, BotD_Ability_ID()) local real distance = BotD_Range() + (lvl * 50) local timer DamageT = CreateTimer() local timer WaveT = CreateTimer() local real endX = x +(distance*Cos(facing)) local real endY = y +(distance*Sin(facing)) local BotDDamage Dam = BotDDamage.create(u, lvl, endX, endY) call BJDebugMsg("Casted... Summoning Dragon.") call DestroyEffect(AddSpecialEffect(BotD_Effect(), x, y)) call PolledWait(1.7) set u2 = CreateUnit(GetOwningPlayer(u), BotD_Dragon_ID(), x, y, facing) set Dam.dragon = u2 call BJDebugMsg("Dragon Summoned. Starting timers.") call SetUnitTimeScale(u2, 166.00 * .01 ) call TimerStart(WaveT, BotD_Interval(), true, function Breath_of_the_Dragons_Grouping) call TimerStart(DamageT, BotD_Check_Interval(), true, function Breath_of_the_Dragons_Damage) call BJDebugMsg("Timers Started.") call SetHandleInt(WaveT, "BotDWave", Dam) call SetHandleInt(DamageT, "BotDInter", Dam) call BJDebugMsg("Structs Applied.") call PolledWait(15.) call BJDebugMsg("Cleaning up") call PauseTimer(WaveT) call DestroyTimer(WaveT) call PauseTimer(DamageT) call DestroyTimer(DamageT) call Dam.destroy() call KillUnit(u2) set u = null set u2 = null set DamageT = null endfunction //=========================================================================== function InitTrig_Breath_of_the_Dragons takes nothing returns nothing local trigger t = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition(t, Condition( function Breath_of_the_Dragons_Conditions ) ) call TriggerAddAction(t, function Breath_of_the_Dragons_Actions ) set t = null endfunction Thanks to any and all who help. Knowing my luck, this'll be some stupid error right under my nose. |
| 07-12-2008, 12:42 PM | #2 |
Try this: Instead of "EVENT_PLAYER_UNIT_SPELL_EFFECT" use "EVENT_PLAYER_UNIT_SPELL_CHANNEL". Channel spells use a different event. Also, yes you can use "unit begins casting a spell" on any spell. If you are also wanting to make the channel spell be able to be interrupted let me know and I can show you how it's done. |
| 07-12-2008, 01:03 PM | #3 |
JASS:function Breath_of_the_Dragons_Actions takes nothing returns nothing local unit u = GetTriggerUnit() local real x = GetUnitX(u) local real y = GetUnitY(u) local real facing = GetUnitFacing(u) local unit u2 local integer lvl = GetUnitAbilityLevel(u, BotD_Ability_ID()) local real distance = BotD_Range() + (lvl * 50) local timer DamageT = CreateTimer() local real endX = x +(distance*Cos(facing)) local real endY = y +(distance*Sin(facing)) local BotDDamage Dam = BotDDamage.create(u, u2, lvl, endX, endY) //... Using an uninitialized variable is killing the thread. --- EVENT_PLAYER_UNIT_SPELL_EFFECT works fine for channeling spells. Please use a scope instead of prefixing, and use constant globals for values that won't need config calculations/similar (mainly Id's and model paths). It makes it easier to read. |
| 07-12-2008, 01:21 PM | #4 | ||
Quote:
Quote:
|
| 07-12-2008, 01:23 PM | #5 |
war3err from Grimoire spots that sort of stuff. |
| 07-12-2008, 01:25 PM | #6 |
Well, we can't use war3err cause of patch 1.22. Would've fixed this ages ago if we could =( |
| 07-12-2008, 01:48 PM | #7 |
Okay, so the spell is still crashing somewhere. I think I've pinpointed where, but I can't determine why. Here's the segments of code I believe may have something to do with it (full code still @ top) The BJDebugMsgs do not show from the first timer callback. The BJDebugMsg that displays after the timers (Timers Started) does show up, but the PolledWait never seems to happen, because "Cleaning Up" is never displayed. JASS:function Breath_of_the_Dragons_Grouping takes nothing returns nothing local BotDDamage data = GetHandleInt(BotD_WaveT, "BotDWave") local unit u = data.caster local real x = data.endpointX local real y = data.endpointY local group g = CreateGroup() local unit f local real x2 = GetUnitX(u) local real y2 = GetUnitY(u) call BJDebugMsg("Grouping enemies") if OrderId2String(GetUnitCurrentOrder(u)) == "starfall" then call GroupEnumUnitsInRangeOfSegNoCurveA(g, x2, y2, x, y, BotD_Width(), Condition(function Breath_of_the_Dragons_Filter)) call SetUnitAnimation(data.dragon, "attack" ) loop set f = FirstOfGroup(g) exitwhen f == null call IssueTargetOrder(CreateDummyUnit(GetOwningPlayer(u), BotD_DummyCaster_ID(), x2, y2, BotD_Dummy_ID(), data.level, true), "acidbomb", f) call GroupAddUnit(BotD_Targets, f) call GroupRemoveUnit(g, f) endloop else call DestroyEffect(AddSpecialEffect(BotD_Effect(), x2, y2)) call PauseTimer(BotD_WaveT) call KillUnit(data.dragon) endif call BJDebugMsg("Enemies Grouped: " + I2S(CountUnitsInGroup(g))) call DestroyGroup(g) set u = null set g = null set f = null call data.destroy() endfunction function Breath_of_the_Dragons_Damage takes nothing returns nothing local timer t = GetExpiredTimer() local BotDDamage data = GetHandleInt(t, "BotDInter") local unit u = data.caster local integer lvl = data.level local group g = CreateGroup() local unit f if CountUnitsInGroup(BotD_Targets) > 0 then call GroupAddGroup(BotD_Targets, g) loop set f = FirstOfGroup(g) exitwhen f == null call UnitDamageTarget(u, f, ArmorDamage(f, BotD_Damage() + (lvl * 15), BotD_Type()), false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null) call GroupRemoveUnit(g, f) call GroupRemoveUnit(BotD_Targets, f) endloop endif call DestroyGroup(g) call data.destroy() set t = null set u = null set g = null set f = null endfunction call TimerStart(BotD_WaveT, BotD_Interval(), true, function Breath_of_the_Dragons_Grouping) call TimerStart(DamageT, BotD_Check_Interval(), true, function Breath_of_the_Dragons_Damage) call BJDebugMsg("Timers Started.") call SetHandleInt(BotD_WaveT, "BotDWave", Dam) call SetHandleInt(DamageT, "BotDInter", Dam) call PolledWait(15.) call BJDebugMsg("Cleaning up") call PauseTimer(BotD_WaveT) call PauseTimer(DamageT) call DestroyTimer(DamageT) call Dam.destroy() call KillUnit(u2) |
| 07-12-2008, 02:19 PM | #8 |
Is the gamecache variable you're using pointing to something? I can't see any other reason why that script would fail. |
| 07-12-2008, 04:43 PM | #9 |
It's pointing to gamecache, like normal. My Get/SetHandleInt functions work, I've used them elsewhere without a problem. |
