//===================================================================== //Spell: Twister //Author: paskovich // //If you want to use this spell in your map, //copy this trigger to your map, //and set the options below! // //Be sure to compile your map with NewGenWorldEditor! // //Give credit if you use it! // //Note: the game may lag if 10+ units are cought by the twister! //===================================================================== scope paskovichTwister //============================= //==========OPTIONS============ //============================= private constant function AbilityId takes nothing returns integer return 'A000' //The spell's raw code endfunction private constant function TwisterDummyId takes nothing returns integer return 'e000' //The twister unit's raw code endfunction private constant function Distance takes nothing returns real return 900. //How far the twister moves endfunction private constant function BigRadius takes nothing returns real return 300. //The radius in which the units are whipped up by the twister endfunction private constant function SmallRadius takes nothing returns real return 150. //Inside this range, units will be trapped in the twister's cone endfunction private constant function BigDamage takes integer level returns real return 10. + level * 35 //Damage taken outside the cone endfunction private constant function BigDamageLand takes integer level returns real return 50. //Damage taken when a unit outside the cone lands endfunction private constant function SmallDamage takes integer level returns real return 25. + level * 35 //Damage taken inside the cone endfunction private constant function SmallDamageLand takes integer level returns real return 100. //Damage taken when a unit inside the cone lands endfunction private constant function DoLightningEffect takes nothing returns boolean return true //An additional lightning effect can appear on trapped units endfunction //============================= //=========SPELL CODE========== //============================= private struct data unit tw unit u real tx real ty real height real maxheight real heightdif real angle real maxdist real dist real time = 0 real overtime = 0 integer level effect fx boolean picked = false boolean destroystruct = false endstruct globals private data array DataArray private integer Total = 0 private timer Timer = CreateTimer() endglobals private function NewTimerInstance takes data whichdata, real period, code func returns nothing if Total == 0 then call TimerStart(Timer, period, true, func) endif set Total = Total + 1 set DataArray[Total-1] = whichdata endfunction private function TwisterTimer takes nothing returns nothing local integer i = 0 local data d local real x local real y local real h loop exitwhen i == Total set d = DataArray[i] if d.destroystruct then set DataArray[i] = DataArray[Total-1] set Total = Total - 1 call d.destroy() set i = i - 1 else if d.overtime > 1 then set d.destroystruct = true call SetUnitPathing(d.u,true) call DestroyEffect(d.fx) if d.picked then call UnitDamageTarget(d.tw,d.u,BigDamageLand(d.level),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null) else call UnitDamageTarget(d.tw,d.u,SmallDamageLand(d.level),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null) endif else set x = GetUnitX(d.tw) set y = GetUnitY(d.tw) if ModuloReal(d.time,0.06) == 0 then call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",x+GetRandomReal(-100,100),y+GetRandomReal(-100,100))) endif if d.picked then if GetWidgetLife(d.tw) > 1 then set d.angle = d.angle - 6 //*** if SquareRoot((x-GetUnitX(d.u))*(x-GetUnitX(d.u))+(y-GetUnitY(d.u))*(y-GetUnitY(d.u))) > d.maxdist then set d.dist = d.dist - 4 //*** endif if d.time < 1 then set d.height = d.height + d.heightdif call SetUnitFlyHeight(d.u,d.height,0) endif set x = x + d.dist * Cos(d.angle*bj_DEGTORAD) set y = y + d.dist * Sin(d.angle*bj_DEGTORAD) set d.tx = x set d.ty = y if DoLightningEffect() and 1 >= GetRandomInt(1,300) then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl",d.u,"origin")) endif else set d.dist = d.dist + 3 //*** set d.height = d.height - d.heightdif set d.heightdif = d.heightdif * 1.05 call SetUnitFlyHeight(d.u,d.height,0) set d.overtime = d.overtime + 0.02 //*** set x = d.tx + d.dist * Cos((d.angle-120)*bj_DEGTORAD) set y = d.ty + d.dist * Sin((d.angle-120)*bj_DEGTORAD) if d.height < 5 and ModuloReal(d.time,0.08) == 0 then call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(d.u),GetUnitY(d.u))) endif endif if IsUnitType(d.u, UNIT_TYPE_FLYING) then call SetUnitX(d.u,x) call SetUnitY(d.u,y) else call SetUnitPosition(d.u,x,y) endif call UnitDamageTarget(d.tw,d.u,BigDamage(d.level)*0.01,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null) else set h = (d.overtime*2)/ 1.0 -1 set h = (-h*h+1)*d.maxheight call SetUnitFlyHeight(d.u,h,0) set d.angle = d.angle - 1.4 //*** set x = x + d.dist * Cos(d.angle*bj_DEGTORAD) set y = y + d.dist * Sin(d.angle*bj_DEGTORAD) call SetUnitPosition(d.u,x,y) call UnitDamageTarget(d.tw,d.u,SmallDamage(d.level)*0.01,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null) if h < 5 and d.overtime > 0.5 then call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(d.u),GetUnitY(d.u))) endif set d.overtime = d.overtime + 0.01 //*** endif set d.time = d.time + 0.02 //*** endif endif set i = i + 1 endloop if Total == 0 then call PauseTimer(Timer) endif endfunction private function Trig_Twister_Actions takes nothing returns nothing local unit caster = GetTriggerUnit() local location loc = GetSpellTargetLoc() local group g = CreateGroup() local group picked = CreateGroup() local unit u = null local data d local real angle = Atan2(GetLocationY(loc)-GetUnitY(caster),GetLocationX(loc)-GetUnitX(caster)) local unit twister = CreateUnit(GetOwningPlayer(caster),TwisterDummyId(),GetUnitX(caster),GetUnitY(caster),angle*bj_RADTODEG) local real dist local real tx local real ty local real a call SetUnitPathing(u,false) call IssuePointOrder(twister,"move",GetUnitX(twister)+Distance()*Cos(angle),GetUnitY(twister)+Distance()*Sin(angle)) call UnitApplyTimedLife(twister,'BTLF',Distance()/GetUnitMoveSpeed(twister)-0.5) loop exitwhen GetWidgetLife(twister) < 1 call TriggerSleepAction(0) set tx = GetUnitX(twister) set ty = GetUnitY(twister) call GroupClear(g) call GroupEnumUnitsInRange(g,tx,ty,BigRadius(),null) loop set u = FirstOfGroup(g) call GroupRemoveUnit(g,u) exitwhen u == null if GetWidgetLife(u) > 0 and IsUnitEnemy(u,GetOwningPlayer(caster)) and not ( IsUnitInGroup(u,picked) or IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(u,UNIT_TYPE_STRUCTURE) ) then set a = Atan2((GetUnitY(u)-ty),(GetUnitX(u)-tx)) if not (angle-bj_PI/4 < a and angle+bj_PI/4 > a) then set dist = SquareRoot( (tx-GetUnitX(u))*(tx-GetUnitX(u)) + (ty-GetUnitY(u))*(ty-GetUnitY(u)) ) set d = data.create() set d.level = GetUnitAbilityLevel(caster, GetSpellAbilityId()) set d.tw = twister set d.u = u set d.fx = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl",u,"origin") if IsUnitType(u, UNIT_TYPE_FLYING) then set d.picked = true set d.height = GetUnitFlyHeight(u) set d.maxheight = GetUnitFlyHeight(u) set d.heightdif = 0 set d.angle = a * bj_RADTODEG set d.dist = dist set d.maxdist = d.maxheight*0.5 else if dist <= SmallRadius() then //pick up set d.picked = true set d.height = GetUnitFlyHeight(u) set d.maxheight = GetRandomReal(200,400) set d.heightdif = (d.maxheight - d.height) * 0.02 //*** set d.angle = a * bj_RADTODEG set d.dist = dist set d.maxdist = d.maxheight*0.5 else //throw set d.height = GetUnitFlyHeight(u) set d.maxheight = GetRandomReal(200,400) set d.angle = a * bj_RADTODEG set d.dist = dist endif call UnitAddAbility(u,'Arav') call UnitRemoveAbility(u,'Arav') endif call SetUnitPathing(u,false) call NewTimerInstance(d,0.02,function TwisterTimer) //*** call GroupAddUnit(picked,u) endif endif endloop endloop call DestroyGroup(g) call DestroyGroup(picked) set caster = null set twister = null set g = null set picked = null set u = null endfunction private function Trig_Twister_Conditions takes nothing returns boolean return GetSpellAbilityId() == AbilityId() endfunction //=========================================================================== function InitTrig_Twister takes nothing returns nothing set gg_trg_Twister = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_Twister, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(gg_trg_Twister, Condition( function Trig_Twister_Conditions)) call TriggerAddAction(gg_trg_Twister, function Trig_Twister_Actions) endfunction endscope