/*=====================================================================*\
//====== SUICIDE SQUAD =====*\\
\\====== Version 1.0b ======//
\\====== by Kricz ======//
|| ||
|| ||
|| Requires: ||
\\ Table [Vexorian] //
\\ ListModule [grim001] //
\\ xebasic, xedamage & xefx [Vexorian] //
\\ ARGB [Vexorian] //
|| SoundUtils [Rising_Dusk] ||
|| GroupUtils [Rising_Dusk] ||
|| Z-Utils [Kricz] ||
// \\
// Optional: \\
|| AutoFly [Kricz] (requires AutoIndex) ||
|| AbilityPreload [grim001] ||
|| ||
|| Please give credits if you use this spell in your map. ||
|| ||
\*==============================================================?=*/
scope SuicideSquad initializer onInit
/*Main Setup*/
globals
//The Spell-Id of the SuicideSquad Ability
private constant integer SPELL_ID = 'A000'
//The Timer-Interval of timers for movements and checks
//Default Value: 0.05
private constant real TIMER_INTERVAL = 0.05
//If true, the system will use sounds using Rising_Dusk's SoundUtils Library.
//You can manually disable specific sounds, by setting their path to "".
private constant boolean USE_SOUNDS = true
endglobals
/*Sapper Setup*/
globals
//The Unit-Id of the Sapper
private constant integer SAPPER_UNIT_ID = 'sapp'
//The speed of the down-falling sappers
//Default Value: 375.00
private constant real SAPPER_DROP_SPEED = 375.00
//The radius, in where sappers search valid targets
//Default Value: 700.00
private constant real SAPPER_TARGET_SEARCH_AREA = 700.00
//If this is true, the sapper will walk to the position of the target unit once it dies
//and search for new targets while walking. If false, the sapper will stop walking and
//then search for new targets
//Default Value: false
private constant boolean SAPPER_STOP_WHEN_TARGET_DIES = false
//This is the distance a sapper has to be with its target to make suicide.
//Default Value: 150.00
private constant real SAPPER_SUICIDE_RANGE = 150.00
//If true, the sappers are invulnerable while falling down and become normal once reaching the gorund
//Default Value: true
private constant boolean SAPPER_INVULNERABLE_WHILE_FALLING = true
//This is the animation-id which is played indstead of the normal death-animation.
//Information: 3 is the "spell death" animation, which shows, that the sapper does suicide
//4 is the normal death animation. Ofcourse you could use any other number, if you are funny :D
//Default Value: 3
private constant integer SAPPER_SUICIDE_ANIMATION_ID = 3
//This is the effect that is created when a sapper is dropped by a zeppeling and falling down
//Use "" for no effect.
//Default Value: "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
private constant string SAPPER_DROP_EFFECT = "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
//This is the attachment point of the drop effect above.
//Default Value: "chest"
private constant string SAPPER_DROP_EFFECT_ATTACHPOINT = "chest"
//This is the effect that is created once a sapper reaches the ground and kindles himself
//Default Value: "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
private constant string SAPPER_BURN_EFFECT = "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
//This is the attachment point of the burn effect above
//Default Value: "chest"
private constant string SAPPER_BURN_EFFECT_ATTACHPOINT = "chest"
//This is the effect that is displayed, when a sapper found a target
//Set it to "" if you want no effect.
//Default Value: "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
private constant string SAPPER_TARGET_FOUND_EFFECT = "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
//This is the attachment point of the target-found effect above
//Default Value: "overhead"
private constant string SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT = "overhead"
//The effect created by the explosion. Set it to "" for no effect
//Default Value: "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
private constant string SAPPER_EXPLOSION_EFFECT = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
//This boolean decides, whether the movespeed of a sapper should be changed using
//the native SetUnitMoveSpeed or not. In some maps, changing the movespeed via trigger
//may cause some bugs with other systems/spells.
//If you dont want, that the movespeed is changed using SetUnitMoveSpeed, change it in the OE.
//Default Value: true
private constant boolean SAPPER_ENABLE_MOVESPEED_CHANGE = true
//This is the movespeed of sappers. It's only used, if the value above is set to true
//Default Value: 250.00
private constant real SAPPER_MOVEMENT_SPEED = 250.00
//If this boolean is set a true, a texttag is created above each sapper, showing when it will
//explode. Please note, that you can only have max. 100 Texttags active at the same time, so
//disable it, when you think you could reach more than 100.
//Default Value: true
private constant boolean SAPPER_SHOW_EXPLOSION_INDICATOR = true
//This is the color of the texttag. Read the ARGB Readme for mroe information about how to use it.
//Default Value: 0xFFFF0000 (red)
private ARGB SAPPER_EXPLOSION_TIME_INDICATOR_COLOR = 0xFFFF0000
//This is the size of the texttag.
//Default Value: 10.00
private constant real SAPPER_EXPLOSION_TIME_INDICATOR_SIZE = 10.00
//This is the height of the texttag.
//Default Value: 75.00
private constant real SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT = 75.00
//If this boolean is set to true, the damage will be done by the caster, not by the sapper
//that exploded. Result of that is, the each unit, that received damage through the explosion
//will attack the caster. If false, they will just do like nothing, cause they cannnot attack
//dead units (the sapper).
//Default Value: true
private constant boolean SAPPER_EXPLOSION_USE_CASTER_AS_SOURCE = true
//This is the attack type which xedamage uses once a sapper does suicide or explodes
//Default Value: ATTACK_TYPE_MAGIC
private constant attacktype SAPPER_EXPLOSION_ATTACK_TYPE = ATTACK_TYPE_MAGIC
//This is the damage type which xedamage uses once a sapper does suicide or explodes
//Default Value: DAMAGE_TYPE_FIRE
private constant damagetype SAPPER_EXPLOSION_DAMAGE_TYPE = DAMAGE_TYPE_FIRE
//This is the radius of the explosion.
//Default Value: 250.00
private constant real SAPPER_EXPLOSION_RADIUS = 250.00
//If true, the explosion will also deal damage to destructables in the explosion area
//Default Value: true
private constant boolean SAPPER_EXPLOSION_DAMAGE_DESTRUCTS = true
//If this boolean is set to true, the explosion will also damage allied unit.
//Default Value: false
private constant boolean SAPPER_EXPLOSION_DAMAGE_ALLIED = false
//If this boolean is true, sappers will play a random sound,
//which you can add/remove/change in the SAPPER_INIT_SOUNDS textmacro below
//Default Value: true
private constant boolean SAPPER_ENABLE_FUNNY_SOUNDS = true
//This value is only important, if funny sounds of sappers are enabled.
//Because it may sounds stupid, when 5 sappers speak at the same time,
//there is this possibility to give each sapper only a chance to tell something
//which you can setup with this value.
//Default Value: 0.33 (33%)
private constant real SAPPER_FUNNY_SOUND_CHANCE = 0.30
endglobals
//in this macro, you can add funny sounds for sappers.
//the function you have to call is:
//call addSapperSound(string soundHandle, real duration)
//soundHandle is the path of the sound, you can get them i.e from the SoundEditor (F5)
//duration is the duration of the sound, you can also get this information in the SoundEditor
//Example: call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
//! textmacro SAPPER_INIT_SOUNDS
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes5.wav", 1.434)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperWhat2.wav", 1.694)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack3.wav", 2.026)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack4.wav", 1.091)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed1.wav", 1.515)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed2.wav", 2.776)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed4.wav", 2.554)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed5.wav", 0.592)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed6.wav", 2.201)
call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed7.wav", 2.374)
//! endtextmacro
//This is the amount of sappers dropped each level.
//Default Value: 3 + lvl
private constant function SAPPER_AMOUNT takes integer lvl returns integer
return 3 + lvl
endfunction
//This is the time, a sapper has until it will explode
//Default Value: 6.00 + lvl
private constant function SAPPER_EXPLOSION_TIMER takes integer lvl returns real
return 6.00 + lvl
endfunction
//This is the damage a explosion deals.
//Default Value: 25.00 + 25.00 * lvl
private constant function SAPPER_EXPLOSION_DAMAGE takes integer lvl returns real
return 15.00 * lvl
endfunction
//This is the filter used to get valid targets for sappers.
//Default Value: not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper))
private constant function SAPPER_TARGET_SEARCH_FILTER takes unit u, unit sapper returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper))
endfunction
/*Zeppelin Setup*/
globals
//The model of the zeppelin that drops the sappers
//Default Value: "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
private constant string ZEPPELIN_MODEL = "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
//The height of the zeppelin. Please note, that the higher this value is, the longer a sapper requires
//to reach the ground. If you change this value, you may should change the drop speed of the sappers too.
//Default Value: 500.00
private constant real ZEPPELIN_HEIGHT = 500.00
//The model-size of the zeppelin.
//Default Value: 0.80
private constant real ZEPPELIN_SIZE = 0.80
//The speed the zeppelin is moving with. This does not effect the distance, when a sapper is dropped
//The formula for the distance for a sapper drop is:
//ZEPPELIN_MOVE_DISTANCE / (SAPPER_DROP_AMOUNT(lvl) + 1)
//Default Value: 400.00
private constant real ZEPPELIN_SPEED = 400.00
//This is the distance the zeppelin moves until is expires.
//Default Value: 1000.00
private constant real ZEPPELIN_MOVE_DISTANCE = 1000.00
//If this boolean is set to true, the zeppelin will display its death animation
//If false, it will be just removed without any animation
//Default Value: false
private constant boolean ZEPPELIN_DESTROY_ON_END = false
//Zeppelin Sounds
//This is the sound which is played when the spell is cast. Set this to "" if you want no sound.
//Default Value: "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
private constant string ZEPPELIN_SUMMON_SOUND = "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
//This is the duration of the sound above
//Default Value: 1.838
private constant real ZEPPELIN_SUMMON_SOUND_DUR = 1.838
//This sound is played whenever a zeppelin drops a sapper. Set it to "" if you want no sound.
//Default Value: "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
private constant string ZEPPELIN_SAPPER_DROP_SOUND = "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
//This is the duration of the sound above
//Default Value: 0.74
private constant real ZEPPELIN_SAPPER_DROP_SOUND_DUR = 0.74
endglobals
//=================================================================//
// Do not touch anything below unless you know what you are doing! //
//=================================================================//
private keyword Main
private keyword Zeppelin
private keyword Sapper
private struct Sapper
unit caster = null
unit target = null
unit sapper = null
real time = 0.00
real x = 0.00
real y = 0.00
real tx = 0.00
real ty = 0.00
real z = 0.00
real explosion = 0.00
texttag explosionIndicator = null
integer lvl = 0
effect dropEffect = null
effect burnEffect = null
player owner = null
boolean onGround = false
boolean oldTargetDied = false
static trigger onDeath = CreateTrigger()
static trigger onOrder = CreateTrigger()
static timer ticker = CreateTimer()
static thistype temp = 0
static HandleTable sapperTable = 0
static HandleTable targetTable = 0
static delegate xedamage dmg = 0
static boolean ignoreOrders = false
static real dropSpeed = SAPPER_DROP_SPEED * TIMER_INTERVAL
static integer array sapperSound
static integer sapperSoundAmount = 0
implement List
static method addSapperSound takes string soundHandle, real duration returns nothing
set sapperSound[sapperSoundAmount] = DefineSound(soundHandle, R2I(duration * 1000), false, true)
set sapperSoundAmount = sapperSoundAmount + 1
endmethod
static method unitFilter takes nothing returns boolean
return SAPPER_TARGET_SEARCH_FILTER(GetFilterUnit(), temp.sapper)
endmethod
method onDestroy takes nothing returns nothing
call sapperTable.flush(sapper)
call listRemove()
if count == 0 then
call PauseTimer(ticker)
endif
static if SAPPER_SHOW_EXPLOSION_INDICATOR then
call DestroyTextTag(explosionIndicator)
endif
endmethod
method searchForTarget takes nothing returns boolean
set temp = this
call GroupEnumUnitsInArea(ENUM_GROUP, x, y, SAPPER_TARGET_SEARCH_AREA, Condition(function thistype.unitFilter))
//These are valid BJ's which SHOULD be used...
if CountUnitsInGroup(ENUM_GROUP) > 0 then
set target = GroupPickRandomUnit(ENUM_GROUP)
//Using the table to save whether a unit is already registred to the trigger or not
if targetTable[target] == 0 then
call TriggerRegisterUnitEvent(onDeath, target, EVENT_UNIT_DEATH)
set targetTable[target] = 1
endif
set tx = GetUnitX(target)
set ty = GetUnitY(target)
call IssueTargetOrder(sapper, "attack", target)
if SAPPER_TARGET_FOUND_EFFECT != "" then
call DestroyEffect(AddSpecialEffectTarget(SAPPER_TARGET_FOUND_EFFECT, sapper, SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT))
endif
static if SAPPER_ENABLE_FUNNY_SOUNDS then
if GetRandomReal(0.00, 1.00) <= SAPPER_FUNNY_SOUND_CHANCE then
call RunSoundOnUnit(sapperSound[GetRandomInt(0, sapperSoundAmount - 1)], sapper)
endif
endif
else
set target = null
endif
return target != null
endmethod
method moveSapper takes nothing returns nothing
if target == null then
static if not SAPPER_STOP_WHEN_TARGET_DIES then
if oldTargetDied then
call IssuePointOrder(sapper, "smart", tx, ty)
else
call PauseUnit(sapper, true)
call IssueImmediateOrder(sapper, "stop")
call PauseUnit(sapper, false)
endif
else
call PauseUnit(sapper, true)
call IssueImmediateOrder(sapper, "stop")
call PauseUnit(sapper, false)
endif
else
if not IsUnitVisible(target, owner) then
if GetUnitCurrentOrder(sapper) == 851983 then
//if target becomes invisible or gets out of sight, the sapper will
//run to the position, where the target was last seen.
call IssuePointOrder(sapper, "smart", tx, ty)
endif
else
if IsUnitType(target, UNIT_TYPE_DEAD) then
if not searchForTarget() then
set oldTargetDied = true
static if not SAPPER_STOP_WHEN_TARGET_DIES then
call IssuePointOrder(sapper, "smart", tx, ty)
else
call PauseUnit(sapper, true)
call IssueImmediateOrder(sapper, "stop")
call PauseUnit(sapper, false)
endif
else
set oldTargetDied = false
endif
elseif GetUnitCurrentOrder(sapper) != 851983 then
call IssueTargetOrder(sapper, "attack", target)
endif
endif
endif
endmethod
static method onLoop takes nothing returns nothing
local thistype this = first
local real dx = 0.00
local real dy = 0.00
set ignoreOrders = true
loop
exitwhen this == 0
if not onGround then
call SetUnitZ(sapper, GetUnitZ(sapper) - dropSpeed)
if GetUnitZ(sapper) <= 0.01 then
static if SAPPER_INVULNERABLE_WHILE_FALLING then
call SetUnitInvulnerable(sapper, false)
endif
if dropEffect != null then
call DestroyEffect(dropEffect)
endif
if SAPPER_BURN_EFFECT != "" then
set burnEffect = AddSpecialEffectTarget(SAPPER_BURN_EFFECT, sapper, SAPPER_BURN_EFFECT_ATTACHPOINT)
endif
static if SAPPER_SHOW_EXPLOSION_INDICATOR then
set explosionIndicator = CreateTextTag()
call SetTextTagVisibility(explosionIndicator, true)
call SetTextTagPermanent(explosionIndicator, true)
call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
call SetTextTagColor(explosionIndicator, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.red, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.green, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.blue, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.alpha)
call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
endif
set onGround = true
endif
else
set x = GetUnitX(sapper)
set y = GetUnitY(sapper)
set explosion = explosion - TIMER_INTERVAL
static if SAPPER_SHOW_EXPLOSION_INDICATOR then
call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
endif
if explosion <= 0 then
call SetUnitExploded(sapper, true)
call KillUnit(sapper)
call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
call destroy()
endif
if target == null then
call searchForTarget()
else
call moveSapper()
if IsUnitVisible(target, owner) then
set tx = GetUnitX(target)
set ty = GetUnitY(target)
set dx = x - tx
set dy = y - ty
if (dx * dx + dy * dy) <= SAPPER_SUICIDE_RANGE * SAPPER_SUICIDE_RANGE then
call SetUnitExploded(sapper, true)
call KillUnit(sapper)
call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
call destroy()
endif
endif
endif
endif
set this = next
endloop
set ignoreOrders = false
endmethod
static method create takes Zeppelin data returns thistype
local thistype this = allocate()
set caster = data.caster
set y = data.y
set x = data.x
set z = data.z
set lvl = data.lvl
set explosion = SAPPER_EXPLOSION_TIMER(lvl)
set sapper = CreateUnit(GetOwningPlayer(caster), SAPPER_UNIT_ID, x, y, data.xyangle * bj_RADTODEG)
set owner = GetOwningPlayer(sapper)
static if not LIBRARY_AutoFly then
call UnitAddAbility(sapper, XE_HEIGHT_ENABLER)
call UnitRemoveAbility(sapper, XE_HEIGHT_ENABLER)
endif
static if SAPPER_INVULNERABLE_WHILE_FALLING then
call SetUnitInvulnerable(sapper, true)
endif
if SAPPER_DROP_EFFECT != "" then
set dropEffect = AddSpecialEffectTarget(SAPPER_DROP_EFFECT, sapper, SAPPER_DROP_EFFECT_ATTACHPOINT)
endif
call SetUnitZ(sapper, z)
call TriggerRegisterUnitEvent(onDeath, sapper, EVENT_UNIT_DEATH)
set sapperTable[sapper] = integer(this)
call listAdd()
if count == 1 then
call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
endif
return this
endmethod
static method onUnitDeath takes nothing returns boolean
local unit killed = GetDyingUnit()
local thistype this = thistype(sapperTable[killed])
if this != 0 then
static if SAPPER_EXPLOSION_USE_CASTER_AS_SOURCE then
call damageAOE(caster, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
else
call damageAOE(sapper, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
endif
static if SAPPER_EXPLOSION_DAMAGE_DESTRUCTS then
call damageDestructablesAOE(caster, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
endif
if SAPPER_EXPLOSION_EFFECT != "" then
call DestroyEffect(AddSpecialEffect(SAPPER_EXPLOSION_EFFECT, x, y))
endif
else
//loop through everything and check targets. if the dying unit is a target of any sapper, find a new one
//or order it to move to the target's location if enabled
set this = first
loop
exitwhen this == 0
if killed == target then
set oldTargetDied = true
if not searchForTarget() then
static if not SAPPER_STOP_WHEN_TARGET_DIES then
set tx = GetUnitX(killed)
set ty = GetUnitY(killed)
call IssuePointOrder(sapper, "smart", tx, ty)
else
call PauseUnit(sapper, true)
call IssueImmediateOrder(sapper, "stop")
call PauseUnit(sapper, false)
endif
endif
endif
set this = next
endloop
endif
set killed = null
return false
endmethod
static method onUnitOrder takes nothing returns boolean
local thistype this = thistype(sapperTable[GetOrderedUnit()])
if this != 0 and not ignoreOrders then
set ignoreOrders = true
call moveSapper()
set ignoreOrders = false
endif
return false
endmethod
static method onInit takes nothing returns nothing
set sapperTable = HandleTable.create()
set targetTable = HandleTable.create()
set dmg = xedamage.create()
set dtype = SAPPER_EXPLOSION_DAMAGE_TYPE
set atype = SAPPER_EXPLOSION_ATTACK_TYPE
set damageAllies = SAPPER_EXPLOSION_DAMAGE_ALLIED
//! runtextmacro SAPPER_INIT_SOUNDS()
call TriggerAddCondition(onDeath, Condition(function thistype.onUnitDeath))
call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER)
call TriggerAddCondition(onOrder, Condition(function thistype.onUnitOrder))
endmethod
endstruct
private struct Zeppelin
unit caster = null
real cos = 0.00
real sin = 0.00
real moved = 0.00
delegate xefx model = 0
sound summonSound = null
integer lvl = 0
integer sapperDropped = 0
integer sapperToDrop = 0
real sapperDropCounter = 0.00
static integer zeppelinSummonSound = 0
static integer zeppelinDropSound = 0
static timer ticker = CreateTimer()
static real speed = TIMER_INTERVAL * ZEPPELIN_SPEED
implement List
method onDestroy takes nothing returns nothing
static if not ZEPPELIN_DESTROY_ON_END then
call model.hiddenDestroy()
else
call model.destroy()
endif
call listRemove()
if count == 0 then
call PauseTimer(ticker)
endif
endmethod
static method onLoop takes nothing returns nothing
local thistype this = first
loop
exitwhen this == 0
set x = x + cos
set y = y + sin
static if USE_SOUNDS then
if summonSound != null then
call SetSoundPosition(summonSound, x, y, z)
endif
endif
set moved = moved + speed
set sapperDropCounter = sapperDropCounter + speed
if sapperDropCounter >= ZEPPELIN_MOVE_DISTANCE / (sapperToDrop + 1) then
set sapperDropCounter = 0.00
call Sapper.create(this)
static if USE_SOUNDS then
if zeppelinDropSound != 0 then
call RunSoundAtPoint(zeppelinDropSound, x, y, z)
endif
endif
endif
if moved >= ZEPPELIN_MOVE_DISTANCE then
call destroy()
endif
set this = next
endloop
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set sin = ZEPPELIN_SPEED * TIMER_INTERVAL * Sin(Main.angle)
set cos = ZEPPELIN_SPEED * TIMER_INTERVAL * Cos(Main.angle)
set caster = Main.caster
set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
set sapperToDrop = SAPPER_AMOUNT(lvl)
set model = xefx.create(Main.cx, Main.cy, Main.angle)
set fxpath = ZEPPELIN_MODEL
set z = ZEPPELIN_HEIGHT
set scale = ZEPPELIN_SIZE
set teamcolor = GetPlayerColor(GetOwningPlayer(caster))
set owner = GetOwningPlayer(caster)
static if USE_SOUNDS then
if ZEPPELIN_SUMMON_SOUND != "" then
call RunSoundAtPoint(zeppelinSummonSound, x, y, z)
endif
endif
call listAdd()
if count == 1 then
call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
endif
return this
endmethod
static method onInit takes nothing returns nothing
static if USE_SOUNDS then
if ZEPPELIN_SUMMON_SOUND != "" then
set zeppelinSummonSound = DefineSound(ZEPPELIN_SUMMON_SOUND, R2I(ZEPPELIN_SUMMON_SOUND_DUR * 1000), false, true)
endif
if ZEPPELIN_SAPPER_DROP_SOUND != "" then
set zeppelinDropSound = DefineSound(ZEPPELIN_SAPPER_DROP_SOUND, R2I(ZEPPELIN_SAPPER_DROP_SOUND_DUR * 1000), false, true)
endif
endif
endmethod
endstruct
private struct Main extends array
static unit caster = null
static integer lvl = 0
static real cx = 0.00
static real cy = 0.00
static real angle = 0.00
static method onCast takes nothing returns boolean
if GetSpellAbilityId() != SPELL_ID then
return false
endif
set caster = GetSpellAbilityUnit()
set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
set cx = GetUnitX(caster)
set cy = GetUnitY(caster)
set angle = Atan2(GetSpellTargetY() - cy, GetSpellTargetX() - cx)
call Zeppelin.create()
return false
endmethod
private static trigger cast = CreateTrigger()
static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(cast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(cast, Condition(function thistype.onCast))
static if LIBRARY_AbilityPreload then
call AbilityPreload(SPELL_ID)
endif
endmethod
endstruct
endscope