overload119
New Member
- Reaction score
- 5
I made this post originally on WC3C, but I'm starting to this this forum is a lot more helpful.
Spell code:
I've been working on this map for a long while, but for the last week I've stopped progress because I've come across a bug that I just can't fix.
In the map there is a hero with a Cleave ability. All it does is knockback enemies. At a certain point in the map (always different) the spell still does damage, but stops knocking back enemies. I've done BJDebugMsg checks to see what the problem is, but it hasn't helped much. At a certain point the PolarProjection functions I'm using just stop working (they move the unit forward, then back, with a net result of 0 displacement, over and over again).
I know the timer is working because part of the spell adds a knockback graphic to the moving unit, and that effect is being displayed and then removed when the knockback is supposed to end.
The spell itself utilizes TimerUtils and structs. I'll post the code as soon as I can.
It's just so frustrating having a spell that works fine until a random time in the map. Any help or tips regarding this would be greatly appreciated.
Spell code:
JASS:
function PolarProjectionX takes real x, real dist, real angle returns real
return x + dist * Cos(angle)
endfunction
function PolarProjectionY takes real y, real dist, real angle returns real
return y + dist * Sin(angle)
endfunction
function AngleBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2 - y1, x2 - x1)
endfunction
JASS:
scope Cleave
private struct data
unit target = null
unit caster = null
group knockGroup = null
real v = 0.
real angle = 0.
endstruct
function Trig_Cleave_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 039;A00N039;
endfunction
private function Filt takes nothing returns boolean
local data d = GetTimerData(GetExpiredTimer())
local unit t = GetFilterUnit()
if( IsUnitEnemy(t, tempPlayer) and GetWidgetLife(t)>0.405 and not IsUnitType(t, UNIT_TYPE_MECHANICAL)and not IsUnitInGroup(t, d.knockGroup) and GetUnitMoveSpeed(t)>10 ) then
call GroupAddUnit(d.knockGroup, t)
call UnitAddAbility(t, 039;A00O039;)
endif
return FALSE
endfunction
private function KnockbackGroup takes nothing returns nothing
local data d = GetTimerData(GetExpiredTimer())
local unit u = GetEnumUnit()
local real dx = 0.
local real dy = 0.
set dx = PolarProjectionX(GetUnitX(u), d.v, d.angle)
set dy = PolarProjectionY(GetUnitY(u), d.v, d.angle)
if IsTerrainWalkable(dx, dy) then
call SetUnitX(u, dx)
call SetUnitY(u, dy)
endif
endfunction
private function Callback takes nothing returns nothing
local timer myTimer = GetExpiredTimer()
local data d = GetTimerData(myTimer)
local group g = NewGroup() // Check to see if nearby units can be added to the knockback
local boolexpr filter = Condition(function Filt)
local unit target = null
set d.v = d.v*0.925
// Enum and add new units to the knockback group
call GroupEnumUnitsInRange(g, GetUnitX(d.target), GetUnitY(d.target), 125, filter)
// Knockback the entire group
call ForGroup(d.knockGroup, function KnockbackGroup)
// Cleanup filter and group
call ReleaseGroup(g)
call DestroyBoolExpr(filter)
if d.v < 5 then
loop
set target = FirstOfGroup(d.knockGroup)
exitwhen target == null
call UnitRemoveAbility(target, 039;A00O039;)
call GroupRemoveUnit(d.knockGroup, target)
endloop
call ReleaseGroup(d.knockGroup)
call d.destroy()
call PauseTimer(myTimer)
call ReleaseTimer(myTimer)
endif
endfunction
function Trig_Cleave_Actions takes nothing returns nothing
local timer myTimer = NewTimer()
local unit u = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local real amount = 50+GetHeroLevel(u)*10+GetUnitStat(u, ATTACK_POWER)*0.4*BarbarianDamageModifier(u,t)
local boolexpr filter = Condition(function Filt)
local data d = data.create()
// Healing variables
local real healSkill = GetPlayerTechCount(GetOwningPlayer(u), 039;R00I039;, true)*0.05
local real healAmount = 0.
// tempVariables
call GroupClear(tempGroup)
set tempPlayer = GetOwningPlayer(u)
set d.caster = u
set d.target = t
set d.knockGroup = NewGroup()
set d.angle = AngleBetweenPointsXY(GetUnitX(u), GetUnitY(u), GetUnitX(t), GetUnitY(t))
set d.v = 40.
call GroupAddUnit(d.knockGroup, t)
call UnitAddAbility(t, 039;A00O039;)
if healSkill > 0 then
set healSkill = healSkill + 0.1
set healAmount = amount*healSkill
call HealUnit(u, u, healAmount)
endif
call UnitDamage(u, t, PHYSICAL, amount)
call SetTimerData(myTimer, d)
call TimerStart(myTimer, 0.03, true, function Callback)
endfunction
//===========================================================================
function InitTrig_Cleave takes nothing returns nothing
set gg_trg_Cleave = CreateTrigger( )
call TriggerRegisterAnyUnitEventNL( gg_trg_Cleave, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Cleave, Condition( function Trig_Cleave_Conditions ) )
call TriggerAddAction( gg_trg_Cleave, function Trig_Cleave_Actions )
endfunction
endscope
JASS:
function BarbarianDamageModifier takes unit u, unit t returns real
local player p = GetOwningPlayer(u)
local real mod = GetPlayerTechCount(GetOwningPlayer(u), 039;R00G039;, true)*0.05
local real targetLifePercent = GetUnitState(u, UNIT_STATE_LIFE)/GetUnitState(u, UNIT_STATE_MAX_LIFE)*100
if targetLifePercent <= 30 and mod > 0 then
set mod = mod+1
else
set mod = 1
endif
return mod
endfunction