//TESH.scrollpos=0
//TESH.alwaysfold=0
native UnitAlive takes unit u returns boolean
globals
/***********************************************************
* Allows Testing
************************************************************/
constant boolean ENABLE_TEST = false //false
/***********************************************************
* Configurables
************************************************************/
constant integer FIRE_GUN = 'A00E' //no target, main attack
constant integer FIRE_GUN_PASSIVE = 'A00B' //passive, needs reload
constant integer RELOAD = 'A001'
constant integer RELOAD_PASSIVE = 'A00D'
constant integer MAX_RELOAD = 20 //max reload for bullets
constant integer MAX_MAGAZINE_CLIPS = 20
constant integer MAX_GRENADE = 10
constant integer MAX_LAND_MINE = 5
constant integer MAX_HEALING = 5
constant integer MAX_ADRENALINE = 10
constant integer BULLETS = 'bull'
constant integer PLAYER_12_COUNT = 30
constant integer ZOMBIE_ID = 'Z001' //Hero type zombie for leveling purposes
constant player ZOMBIE_OWNER = Player(5) //player 6 in GUI
timer ZOMBIE_SPAWN_TIMER = CreateTimer()
real ALLY_ENTER_TIMER = 120 //2 minutes
real COLD_WEATHER_STARTS = 60 //60 seconds
//From SurviveTimer, called after acquiring barricade
real SURVIVE_DURATION = 1800 //should be 1800 = 30 minutes
real ZOMBIE_LEVEL_UP = SURVIVE_DURATION/10
/***********************************************************
* Used by Dialog and ZombieSpawns
************************************************************/
integer MAX_ZOMBIE_LEVEL = 20
integer MAX_ZOMBIE_COUNT = 50
integer MAX_ZOMBIE_SPEED = 350
integer ZOMBIE_COUNT = 12
integer ZOMBIE_LEVEL_UP_DELAY = 250
integer ZOMBIE_LEVEL = 1
real ZOMBIE_SPEED = 140
integer TERMINATOR_LEVEL = 50
/***********************************************************
* Misc
************************************************************/
boolean ALLY_ENTER = false
unit BARREL
group ALLYGROUP = CreateGroup()
group EnumG = CreateGroup()
endglobals
function SuggestionsH takes nothing returns nothing
local integer i = 0
loop
//call QMessageHint(Player(i), STitle, SMgs)
set i = i+1
exitwhen i==4
endloop
endfunction
//===Setup Allied Units
function SetupAlliedUnits takes nothing returns nothing
set udg_P12InfantryUnits[1] = 'h004'
set udg_P12InfantryUnits[2] = 'h005'
set udg_P12InfantryUnits[3] = 'h00D'
set udg_P12InfantryUnits[4] = 'h00E'
set udg_P12InfantryUnits[5] = 'e000'
set udg_P12TankUnits[1] = 'h008'
set udg_P12TankUnits[2] = 'h009'
set udg_P12AirUnits[1] = 'h006'
set udg_P12AirUnits[2] = 'h007'
endfunction
//===Starting Units/Player
function StartingUnit takes nothing returns nothing
local integer i = 0
local integer id
local unit u
local item it
local real x
local real y
//call BJDebugMsg(R2S(ZOMBIE_LEVEL_UP))
call SetupAlliedUnits()
if ENABLE_TEST then
//inside the town
set udg_Hero = CreateUnit(Player(0), 'hero', 547, -144, 0) //normal
//set udg_Hero = CreateUnit(Player(0), 'H000', 547, -144, 0) //hero
else
set udg_Hero = CreateUnit(Player(0), 'hero', -316, -1655, 0) //normal
//set udg_Hero = CreateUnit(Player(0), 'H000', -316, -1655, 0) //hero
endif
set udg_HeroName = "Benny"
call DH.register(udg_Hero) //dummy hero system
//set udg_HeroName = GetHeroProperName(udg_Hero)
set u = udg_Hero
set id = GetHandleId(u)
set x = GetUnitX(u)
set y = GetUnitY(u)
set it = CreateItem(BULLETS, x, y) //Bullets
call UnitAddItem(u, it)
call SetItemCharges(it, MAX_RELOAD)
//call SaveInteger(udg_HASH, id, 100, MAX_RELOAD) //Loads Starting Bullet Amount
set it = CreateItem('I000', x, y) //magazine clips
call UnitAddItem(u, it)
call SetItemCharges(it, 15)
call SaveInteger(udg_HASH, id, 100, MAX_MAGAZINE_CLIPS)
set it = CreateItem('I002', x, y) //Grenade
call UnitAddItem(u, it)
call SetItemCharges(it, 3)
set it = CreateItem('I006', x, y) //Land Mine
call UnitAddItem(u, it)
call SetItemCharges(it, 7)
call UnitRemoveAbility(u, RELOAD)
call UnitAddAbility(u, RELOAD_PASSIVE)
call ItemChargesMerger_AddItem('I000', MAX_MAGAZINE_CLIPS)
call ItemChargesMerger_AddItem('I002', MAX_GRENADE)
call ItemChargesMerger_AddItem('I006', MAX_LAND_MINE)
call ItemChargesMerger_AddItem('sreg', MAX_HEALING)
call ItemChargesMerger_AddItem('hslv', MAX_ADRENALINE)
set u = null
endfunction
//===Ally Enters
function AL_LOOP takes nothing returns nothing
call DestroyTimerDialog(LoadTimerDialogHandle(udg_HASH, GetHandleId(GetExpiredTimer()), 1))
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
call TriggerExecute(gg_trg_AllyEnter)
endfunction
function AllyComesIn takes nothing returns nothing
local timer t = CreateTimer()
local integer tID = GetHandleId(t)
local timerdialog dia = CreateTimerDialog(t)
call TimerDialogDisplay(dia, true)
call TimerDialogSetTitle(dia, "Ally Arrived In")
call SaveTimerDialogHandle(udg_HASH, tID, 1, dia)
call TimerStart(t, ALLY_ENTER_TIMER, false, function AL_LOOP)
set t = null
set dia = null
endfunction
//===Xybot Enter
function XybotEnter takes nothing returns nothing
set udg_HeroXybot = CreateUnit(Player(0), 'H00C', 7256, -5200, 0)
call SetHeroLevel(udg_HeroXybot, 20, false)
call IssuePointOrder(udg_HeroXybot, "move", 5830, -4703)
endfunction
Name | Type | is_array | initial_value |
Barricade | unitcode | No | |
BM_Damage | real | No | |
BM_Missile | unit | No | |
CA_Caster | unit | No | |
CA_Damage | real | No | |
CameraZ | real | No | |
CB | integervar | No | |
CheckColdDam | boolean | No | |
CheckZombie | boolean | No | false |
CK_Caster | unit | No | |
CK_Damage | real | No | |
ColdDamage | group | No | |
ColdEffect | effect | No | |
CommnaderBrawl | unit | No | |
DisableTest | boolean | No | |
DUMID | integer | Yes | |
DUMMYCAM | unit | Yes | |
DummyHero | unit | No | |
FirstZombie | unit | No | |
GDD_DamageSource | unit | No | |
GR_Caster | unit | No | |
GR_Damage | real | No | |
GR_Peasant | unit | No | |
GraveRect1 | rect | No | |
GraveRect2 | rect | No | |
GroupPlayer7 | group | No | |
HASH | hashtable | No | |
Hero | unit | No | |
HeroName | string | No | |
HeroXybot | unit | No | |
ID | integer | No | |
InsideTown | rect | No | |
LM_Damage | real | No | |
LM_Mine | unit | No | |
M8_Helicopter | unit | No | |
MegaDeth | sound | No | SoundNull |
OffMapDestruction | location | No | |
P12AirUnits | integer | Yes | |
P12Appear | rect | Yes | |
P12InfantryUnits | integer | Yes | |
P12TankUnits | integer | Yes | |
ReloadAmt | integer | No | 10 |
SfxWeatherHeavySnow | weathereffect | No | |
SfxWeatherLightSnow | weathereffect | No | |
SfxWeatherWind | weathereffect | No | |
SkipCinematics | boolean | No | |
tempgroup | group | No | |
tempint | integer | No | |
temploc | location | No | |
temploc2 | location | No | |
tempunit | unit | No | |
Terminator | unit | No | |
TownRect1 | rect | No | |
TownRect2 | rect | No | |
XB_Caster | unit | No | |
XB_Damage | real | No | |
XybotTimer | timer | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
DONE - The hotkeys for each of the hero's skills are too far away at each other. Try fixing the hotkeys and make them near for convenience's sake.
Items in-game are preset and is warcraft-ish. Try enlarging your imagination and add some items that fits
this Futuristic map of your such as make healing items, First Aid and such. Unit models are too warcraft-ish too.
Try making them more Futiristic also that will go with the hero you have that is futuristic also.
Terrain Improvements. Try making it go with the type and make it more realistic.
Change the unit models into something more Futuristic enough.
Items are all preset. try making something more fitting for a Futuristic map like this such as make healing items, First Aid and such...
Ensnare no good
//TESH.scrollpos=0
//TESH.alwaysfold=0
[center][IMG]http://www.hiveworkshop.com/forums/members/167625-albums6621-picture73244.gif[/IMG]
[indent][FONT="Comic Sans MS"][COLOR="Cyan"][COLOR="Pink"]
The town of Berg is a very remote place and it’s known for its very cold weather. Suddenly, all communications
from this place vanished.
The military headquarters 100 miles from away from Berg has sent you, an elite ranger
to find out what happen.[/COLOR][/COLOR][/FONT][/indent]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums6621-picture73243.gif[/IMG]
[indent][FONT="Comic Sans MS"][COLOR="Pink"]
Survive waves of attacking zombies and optionally repair nearby defenses to keep zombies out.
Solve the mystery of this town until your ally comes.
[/COLOR][/FONT][/indent]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums6621-picture73246.gif[/IMG][/center]
[hidden=]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73274.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73275.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73276.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73277.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73278.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73279.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73280.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73281.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73282.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture73283.jpg[/IMG]
[/hidden]
[center][IMG]http://www.hiveworkshop.com/forums/members/167625-albums6621-picture73247.gif[/IMG][/center]
[hidden=]
v2.5
- Fixed a bug that game does not start
- Attack is now instant target instead of point target
- Hero is now a normal unit, so leveling is removed
- Difficulty settings removed
- Skippable cinematics added
- Items for heroes drops reduced
v2.4
- Systems and Spells improved.
- Camera lock removed
- Skippable cinematics removed to focus on the story.
- Difficulty modes added
- Hotkeys fixed and more easy to use
- Added adrenaline item
v 2.3
- Cinematics option to skip or not.
- Barricade changed to item instead of add ability.
- Quests messages created.
- Boost ability removed.
- Combat knife is now a default ability.
- Camera System fixed.
- Attack and Combat knife attacks fast.
v 2.2
- New multiplayer mode, 4 players maximum.
- New AI option if you play with computer as your ally.
- New Camera system.
- New Item item merger system which removes the item storage.
- New item drop system, removes tomes bacause it leaks.
- New cinematics and quests changes.
- A total of 8 new spells added.
[/hidden]
[center][IMG]http://www.hiveworkshop.com/forums/members/167625-albums6621-picture73245.gif[/IMG][/center]
[hidden=]
[COLOR="Yellow"]Models:[/COLOR]
US Ranger by qassamzed
GLA Rebel by qassamzed
UTN Grenadier by Cavman
Chaos Terminator by Pyramidhe@d
M-8 Helicopter by Kofi_Banan
T-72 Tank by Kofi_Banan
Grenade by Illidan(Evil)X
T-80 Tank by Illidan(Evil)X
Cobra Helicopter by Illidan(Evil)X
Apache Helicopter by Illidan(Evil)X
GroundWalker_Minigun by jk2pach
Snowpine tree by Gottfrei
FirstAid By Em!
MEDKIT by ZEEP
PotionHealingSmall By epsilon
[COLOR="yellow"]Icons:[/COLOR]
BTNM249 by zombie2279
BTNammo by AlienArsonist
BTNammodump by zombie2279
BTNCombatknife by oh_snap
BTNGrenadeF1 by ANdROnIQ
BTNGunFire by NFWar
BTNreload by zombie2279
BTNMedikit By -JonNny
BTNAdrenalin By -JonNny
[COLOR="yellow"]Music boss theme:[/COLOR]
Duke Nukem Theme by Megadeth
[COLOR="yellow"]Programs used:[/COLOR]
Button Manager v1.8.2 by Shadow Daemon (for icons)
[COLOR="yellow"]Systems:[/COLOR]
Bribe, Magtheridon96, Jesus4Lyf, Vexorian, Spinnaker
[COLOR="yellow"]Spells:[/COLOR]
ElectricCharge by Hanky
[/hidden]
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SetupThings initializer init
globals
private integer count = 0
endglobals
private function Run takes nothing returns nothing
local unit first
call MeleeStartingVisibility( )
call RemoveAllGuardPositions( Player(1) )
call RemoveAllGuardPositions( Player(2) )
call RemoveAllGuardPositions( Player(3) )
call RemoveAllGuardPositions( Player(4) )
call RemoveAllGuardPositions( Player(5) )
call RemoveAllGuardPositions( Player(6) )
call EnableMinimapFilterButtons( false, false )
//setting the zombies invulnerable at the beginning of the game
call GroupEnumUnitsOfPlayer(EnumG, Player(6), null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) then
call ShowUnit(first, false)
call PauseUnit(first, true)
call GroupAddUnit(udg_GroupPlayer7, first)
endif
call GroupRemoveUnit(EnumG, first)
endloop
call SetUnitInvulnerable( gg_unit_usep_0198, true )
call SetTerrainFogEx(0, 1500.00, 2500.00, 10, 75, 100, 75)
call SetSkyModel( "Environment\\Sky\\LordaeronWinterSky\\LordaeronWinterSky.mdl" )
set udg_SfxWeatherWind = AddWeatherEffect(GetWorldBounds(), 'WNcw') //Heavy Wind
//set udg_SfxWeatherWind = AddWeatherEffect(GetWorldBounds(), 'SNbs') //Northern Blizzard
set udg_SfxWeatherHeavySnow = AddWeatherEffect(GetWorldBounds(), 'SNhs') //Heavy Snow
set udg_SfxWeatherLightSnow = AddWeatherEffect(GetWorldBounds(), 'SNls') //Light Snow
call EnableWeatherEffect( udg_SfxWeatherWind, true )
endfunction
//===========================================================================
private function init takes nothing returns nothing
call TimerStart(CreateTimer(), 0., false, function Run)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function EBCOND takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h002'
endfunction
function EBRANGE takes nothing returns boolean
call UnitDamageTarget(BARREL, GetFilterUnit(), 300.00, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
return false
endfunction
function EBEX takes nothing returns nothing
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
set BARREL = GetTriggerUnit()
call DestroyEffect(AddSpecialEffect("Units\\NightElf\\Wisp\\WispExplode.mdl", x, y))
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, 300, Filter(function EBRANGE))
endfunction
function InitTrig_ExplosiveBarrels takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function EBCOND))
call TriggerAddAction(t, function EBEX)
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SimpleEvents initializer init
//===Learn Skill
private function GainAction takes nothing returns boolean
local unit u
if GetPlayerController(GetOwningPlayer(GetTriggerUnit()))==MAP_CONTROL_COMPUTER then
set u = GetTriggerUnit()
call SelectHeroSkill(u, 'A007') //Grenade
call SelectHeroSkill(u, 'A003') //Land Mine
endif
set u = null
return false
endfunction
//===Win & Defeat Conditions
private function DefeatActions takes player p returns nothing
call CustomDefeatBJ(p, "You Lost!")
endfunction
private function WinActions takes nothing returns nothing
local integer i = 0
loop
call CustomVictoryBJ(Player(i), true, true)
set i = i+1
exitwhen i==3
endloop
endfunction
private function WinConditions takes nothing returns boolean
if GetTriggerUnit() == udg_Terminator then
call WinActions()
elseif GetUnitTypeId(GetTriggerUnit())=='H000' or GetUnitTypeId(GetTriggerUnit())=='H00C' then
call DefeatActions(GetTriggerPlayer())
endif
return false
endfunction
private function init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function WinConditions)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_LEVEL, function GainAction)
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
//see ZombieSpawns
library Dialog initializer Init requires DialogBox
globals
private DialogBox cine
private button yes
private button no
//private boolean SkipIntroCinematic = false
endglobals
/******************************************
Intro Cinematic Skip
*******************************************/
private function Skip takes nothing returns nothing
local boolean skip = false
if (cine.clickedButton(yes)) then //yes
set udg_SkipCinematics = true
endif
call TriggerExecute( gg_trg_Intro )
endfunction
private function RunDialog takes nothing returns nothing
set cine = cine.create("Skip Cinematics?", function Skip)
set yes = cine.addButton("Yes", 1)
set no = cine.addButton("No", 1)
call cine.displayForPlayer(Player(0))
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer(), 0., false, function RunDialog)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function ITEMDROP takes nothing returns boolean
local unit u = GetTriggerUnit()
local item it
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local integer random = GetRandomInt(0, 20)
if random==0 then
set it = CreateItem('I000', x, y) //Magazine Clips
call SetItemCharges(it, GetRandomInt(5, 15))
elseif random==4 then
call CreateItem('sreg', x, y) //Scroll of Regeneration, Heal
elseif random==8 then
call CreateItem('hslv', x, y) //Healing Salve, Adrenaline
elseif random==12 then
set it = CreateItem('I006', x, y) //Land Mine
elseif random==16 then
set it = CreateItem('I002', x, y) //Grenade
endif
set u = null
set it = null
return false
endfunction
function InitTrig_ZombieDropItem takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t, Player(4), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(t, Player(5), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(t, Player(6), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(t, Condition(function ITEMDROP))
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Cold initializer init
globals
private string SFX = "Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorDamage.mdl"
private boolean CHECK = true
//First timer usage only for quest
private timer tim = CreateTimer()
private timerdialog tdia
//Used for survival
private timer ColdTimer = CreateTimer()
private group ColdGroup = CreateGroup()
private integer ColdIndex = 0
endglobals
private function DamageThem takes nothing returns nothing
local unit u = GetEnumUnit()
if UnitAlive(u) and udg_CheckColdDam then
call SetWidgetLife(u, GetWidgetLife(u)-GetRandomReal(10,35))
call DestroyEffect(AddSpecialEffectTarget(SFX, u, "chest"))
else
call SetUnitMoveSpeed(u, GetUnitDefaultMoveSpeed(u))
call GroupRemoveUnit(ColdGroup, u)
endif
set u = null
endfunction
private function GrpLooper takes nothing returns nothing
call ForGroup(ColdGroup, function DamageThem)
endfunction
private function ColdAddCond takes nothing returns boolean
if udg_CheckColdDam then
if GetTriggerUnit()==udg_Hero then
call GroupAddUnit(ColdGroup, GetTriggerUnit())
call SetUnitMoveSpeed(udg_Hero, 130.00)
call TimerStart(ColdTimer, 0.5, true, function GrpLooper)
endif
endif
return false
endfunction
private function ColdRemoveCond takes nothing returns boolean
if udg_CheckColdDam then
if GetTriggerUnit()==udg_Hero then
call SetUnitMoveSpeed(GetTriggerUnit(), GetUnitDefaultMoveSpeed(GetTriggerUnit()))
call GroupRemoveUnit(ColdGroup, GetTriggerUnit())
endif
endif
return false
endfunction
private function ColdSetup takes nothing returns nothing
local trigger t = CreateTrigger()
local region re = CreateRegion()
call RegionAddRect(re, udg_InsideTown)
call TriggerRegisterEnterRegion(t, re, null)
call TriggerAddCondition(t, Condition(function ColdRemoveCond))
set t = CreateTrigger()
call TriggerRegisterLeaveRegion(t, re, null)
call TriggerAddCondition(t, Condition(function ColdAddCond))
call DestroyTimer(GetExpiredTimer())
set t = null
endfunction
private function init takes nothing returns nothing
call TimerStart(CreateTimer(), 1.0, false, function ColdSetup)
endfunction
//=====================================================================================
//Code for first cold damage
private function FirstCold takes unit hero returns nothing
call GroupAddUnit(ColdGroup, hero)
call SetUnitMoveSpeed(hero, 130.00)
call TimerStart(ColdTimer, 0.5, true, function GrpLooper)
endfunction
private function ColdSurviveStop takes nothing returns nothing
local region insideT = CreateRegion()
call RegionAddRect(insideT, udg_InsideTown)
//This enables the cold region damage in case hero goes out
set udg_CheckColdDam = true
//QUEST MESSAGE FOR BARRICADE:
if CHECK==true then
set CHECK = false
call BJDebugMsg("|cffffcc00Soldier:" + "|r" + " It's very cold, I bet those Zombies will return...I better block the entrances with a barricades.")
endif
if IsUnitInRegion(insideT, udg_Hero) then
call Quests.rushEx(2)
else
call FirstCold(udg_Hero)
endif
//Rush quest has finished
call Quests.rush(false)
//Survive quest starts
call Quests.survive(true)
call PauseTimer(tim)
call DestroyTimer(tim)
call DestroyTimerDialog(tdia)
endfunction
function StartColdSurvive takes nothing returns nothing
call CreateItem('I001', -1382, 1017)
set tdia = CreateTimerDialog(tim)
call TimerDialogDisplay(tdia, true)
call TimerDialogSetTitle(tdia, "Very Cold Weather")
call TimerStart(tim, COLD_WEATHER_STARTS, false, function ColdSurviveStop)
endfunction
endlibrary
//TESH.scrollpos=42
//TESH.alwaysfold=0
library ZombieSpawns initializer init uses Dialog
//===ATTACKING: THIS SHOULD BE EDITED
globals
private integer ZOMBIE_WAVE_INDEX = 0 //1+1 only
private unit ZOMBIE
private boolean STOP_LEVELING = false
private group SpawnGroup = CreateGroup()
endglobals
//===Remove from SpawnGroup
private function RemoveFromGroup takes nothing returns boolean
if IsUnitInGroup(GetTriggerUnit(), SpawnGroup) then
call GroupRemoveUnit(SpawnGroup, GetTriggerUnit())
endif
return false
endfunction
//===STAT BONUSES FOR ZOMBIES:
private function GiveBonus takes nothing returns nothing
call SetHeroLevel(GetEnumUnit(), ZOMBIE_LEVEL, false)
call SetUnitMoveSpeed(GetEnumUnit(), ZOMBIE_SPEED)
endfunction
private function init takes nothing returns nothing
call RegisterPlayerUnitEventForPlayer(EVENT_PLAYER_UNIT_DEATH, function RemoveFromGroup, Player(5))
endfunction
private function ZombieCreate takes nothing returns nothing
local unit u
local real x1
local real y1
local real x2
local real y2
//Zombies are Player(5)
//Default ZombieCount is 8
if GetPlayerUnitCount(ZOMBIE_OWNER, false) < ZOMBIE_COUNT then
set x1 = GetRandomReal(GetRectMinX(udg_GraveRect1), GetRectMaxY(udg_GraveRect1))
set y1 = GetRandomReal(GetRectMinX(udg_GraveRect1), GetRectMaxY(udg_GraveRect1))
set x2 = GetRandomReal(GetRectMinX(udg_GraveRect2), GetRectMaxY(udg_GraveRect2))
set y2 = GetRandomReal(GetRectMinX(udg_GraveRect2), GetRectMaxY(udg_GraveRect2))
//Create from top
set u = CreateUnit(ZOMBIE_OWNER, ZOMBIE_ID, x1, y1, 0)
call EngageLite.add(u, GetUnitX(u), GetUnitY(u), false, false)
call SetHeroLevel(u, ZOMBIE_LEVEL, false)
call GroupAddUnit(SpawnGroup, u)
call IssuePointOrder(u, "attack", 0, 0)
//Create from bottom
set u = CreateUnit(ZOMBIE_OWNER, ZOMBIE_ID, x2, y2, 0)
call EngageLite.add(u, GetUnitX(u), GetUnitY(u), false, false)
call SetHeroLevel(u, ZOMBIE_LEVEL, false)
call GroupAddUnit(SpawnGroup, u)
call IssuePointOrder(u, "attack", 0, 0)
set u = null
endif
//Stops when zombie level is MAX_ZOMBIE_LEVEL
if STOP_LEVELING then
call ForGroup(SpawnGroup, function GiveBonus)
else
if ZOMBIE_LEVEL==MAX_ZOMBIE_LEVEL then
set STOP_LEVELING = true
else
set ZOMBIE_WAVE_INDEX = ZOMBIE_WAVE_INDEX + 1
//call BJDebugMsg(I2S(ZOMBIE_WAVE_INDEX))
//Each ZOMBIE_WAVE_DELAY will make the zombies more powerful
if ZOMBIE_WAVE_INDEX==ZOMBIE_LEVEL_UP_DELAY then
set ZOMBIE_WAVE_INDEX = 0
if MAX_ZOMBIE_SPEED > ZOMBIE_SPEED then
set ZOMBIE_SPEED = ZOMBIE_SPEED + 20
endif
if MAX_ZOMBIE_COUNT > ZOMBIE_COUNT then
set ZOMBIE_COUNT = ZOMBIE_COUNT + 4
endif
if MAX_ZOMBIE_LEVEL > ZOMBIE_LEVEL then
set ZOMBIE_LEVEL = ZOMBIE_LEVEL + 1
endif
call ForGroup(SpawnGroup, function GiveBonus)
endif
endif
endif
endfunction
/*******************************************************
* Spawning zombies here, runs every 1 second
* from SurviveTimer code
********************************************************/
public function StartZombieSpawns takes nothing returns nothing
call TimerStart(ZOMBIE_SPAWN_TIMER, 1.0, true, function ZombieCreate)
endfunction
public function PauseZombieTimer takes nothing returns nothing
call PauseTimer(ZOMBIE_SPAWN_TIMER)
endfunction
endlibrary
//TESH.scrollpos=27
//TESH.alwaysfold=0
/******************************************************************
* Terminator is NOT YET here, this is only for ZOMBIES
*******************************************************************/
library SurviveTimer uses ZombieSpawns
globals
private real HALF_TIME //cold damage will be gone
integer Interval = 0
timerdialog TID
boolean Check1 = true
endglobals
//===Loops every 1 seconds
private function SurviveTimeLoop takes nothing returns nothing
set Interval = Interval + 1
//Disables the Cold region
if Interval >= HALF_TIME and Check1 then
//call BJDebugMsg("COLD OVER")
set Check1 = false
set udg_CheckColdDam=false
call SetUnitMoveSpeed(udg_Hero, GetUnitDefaultMoveSpeed(udg_Hero))
call StopSound(gg_snd_Wind, true, true)
call RemoveWeatherEffect(udg_SfxWeatherWind)
call RemoveWeatherEffect(udg_SfxWeatherHeavySnow)
call EnableWeatherEffect(udg_SfxWeatherLightSnow, true)
call DisableTrigger( gg_trg_Sound_Wind )
call DisableTrigger(gg_trg_ColdRegions)
call SetSkyModel("Environment\\Sky\\FoggedSky\\FoggedSky.mdl")
call SetTerrainFogEx(0, 1500.00, 2500.00, 20, 45, 75, 60) //normal
//call SetTerrainFogEx(0, 1500.00, 2500.00, 10, 75, 100, 75) //windy
endif
//Ends the Loop
if Interval >= SURVIVE_DURATION then
//call BJDebugMsg("TIMER OVER")
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endif
endfunction
//===Expires 45 minutes
private function SurviveTimeEnd takes nothing returns nothing
call DestroyTimerDialog(TID)
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
call ZombieSpawns_PauseZombieTimer()
call TriggerExecute(gg_trg_HelicopterEnter)
//Run the TerminatorCreate and Rescue enters
endfunction
//===Called after acquiring the Barricade Item
function SurviveTimer takes nothing returns nothing
local timer t = CreateTimer()
set TID = CreateTimerDialog(t)
call TimerDialogDisplay(TID, true)
call TimerDialogSetTitle(TID, "Survive In")
//half time is to destroy the weather
set HALF_TIME = SURVIVE_DURATION / 2
call TimerStart(t, SURVIVE_DURATION, false, function SurviveTimeEnd)
call TimerStart(CreateTimer(), 1.0, true, function SurviveTimeLoop)
call ZombieSpawns_StartZombieSpawns()
set t = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function ALLY_ACTIONS takes nothing returns nothing
local integer i = 0
local integer ran = GetRandomInt(3, 5)
local integer infantry //
local integer copterandtank
local integer reg //region P12
local integer randomunits = GetRandomInt(1,3)
local rect r
local unit u
local location loc
loop
set i = i+1
set reg = GetRandomInt(1, 8)
set infantry = GetRandomInt(1, 5)
set copterandtank = GetRandomInt(1, 2)
set loc = Location(GetRectCenterX(udg_P12Appear[reg]), GetRectCenterY(udg_P12Appear[reg]))
if randomunits==1 then
set u = CreateUnitAtLoc(Player(11), udg_P12InfantryUnits[infantry], loc, 90)
elseif randomunits==2 then
set u = CreateUnitAtLoc(Player(11), udg_P12AirUnits[copterandtank], loc, 90)
elseif randomunits==3 then
set u = CreateUnitAtLoc(Player(11), udg_P12TankUnits[copterandtank], loc, 90)
endif
call RemoveGuardPosition(u)
call RemoveLocation(loc)
//Orders ally to attack the terminator
call SE.summoned(udg_Terminator, u)
exitwhen i >= ran
endloop
set u = null
set r = null
set loc = null
endfunction
function ALLY_COND takes nothing returns boolean
return ALLY_ENTER and GetPlayerUnitCount(Player(11), false) <= PLAYER_12_COUNT
endfunction
//===========================================================================
function InitTrig_AllyHelping takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 4.00 )
call TriggerAddCondition(t, Condition(function ALLY_COND))
call TriggerAddAction(t, function ALLY_ACTIONS)
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
module Alloc
private static integer array recycler
private static integer instanceCount = 0
debug private static boolean enabled = true
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
debug if (not enabled) then
debug return 1/0
debug endif
if (this == 0) then
debug if (instanceCount == 8191) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"OVERFLOW")
debug set enabled = false
debug set this = 1/0
debug endif
set this = instanceCount + 1
set instanceCount = this
else
set recycler[0] = recycler[this]
endif
debug set recycler[this] = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug if (not enabled) then
debug set this = 1/0
debug endif
debug if (recycler[this] != -1) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ATTEMPT TO DEALLOCATE NULL STRUCT INSTANCE")
debug set enabled = false
debug set this = 1/0
debug endif
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
endmodule
//TESH.scrollpos=170
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The standard T32 module with added safety checks on .startPeriodic() and
// .stopPeriodic(), T32xs.
//
module T32xs
private thistype next
private thistype prev
private boolean runningPeriodic
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
if not this.runningPeriodic then
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
set this.runningPeriodic=true
endif
endmethod
method stopPeriodic takes nothing returns nothing
if this.runningPeriodic then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
set this.runningPeriodic=false
endif
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The original T32 module, for backwards compatability only.
//
module T32 // deprecated.
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
if this.periodic() then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endif
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SimError initializer init
//**************************************************************************************************
//*
//* SimError
//*
//* Mimic an interface error message
//* call SimError(ForPlayer, msg)
//* ForPlayer : The player to show the error
//* msg : The error
//*
//* To implement this function, copy this trigger and paste it in your map.
//* Unless of course you are actually reading the library from wc3c's scripts section, then just
//* paste the contents into some custom text trigger in your map.
//*
//**************************************************************************************************
//==================================================================================================
globals
private sound error
endglobals
//====================================================================================================
function SimError takes player ForPlayer, string msg returns nothing
set msg="\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00"+msg+"|r"
if (GetLocalPlayer() == ForPlayer) then
call ClearTextMessages()
call DisplayTimedTextToPlayer( ForPlayer, 0.52, 0.96, 2.00, msg )
call StartSound( error )
endif
endfunction
private function init takes nothing returns nothing
set error=CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
//call StartSound( error ) //apparently the bug in which you play a sound for the first time
//and it doesn't work is not there anymore in patch 1.22
endfunction
endlibrary
//TESH.scrollpos=33
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
//TESH.scrollpos=31
//TESH.alwaysfold=0
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.0
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 260 + 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key)
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb)
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=33
//TESH.alwaysfold=0
/*****************************************************************************
*
* Get Closest Widget
* by Spinnaker v2.0.0.0
*
* Special thanks to Troll-Brain
*
******************************************************************************
*
* This snippet contains several functions which returns closest
* widget to given coordinates and passed filter.
*
******************************************************************************
*
* Requirements:
* Snippet optionaly requires IsDestructableTree,
* enabling user to choose if enumerated should be all destructables
* or only tree-type ones, therefore gives option to get closest tree.
*
******************************************************************************
*
* Important:
* Performance drop depends on amount of objects currently on the map
* Snippet functions are designed to reduce the search time as much as
* posible, although it's recommended to use non specific functions
* wisely, especialy if your map contains large numbers of widgets.
*
******************************************************************************
*
* Functions:
* function GetClosestItem takes real x, real y, boolexpr filter returns item
* - Gets single item, nearest passed coordinates
* function GetClosestItemInRange takes real x, real y, real radius, boolexpr filter returns item
* - Returns single item, closest to coordinates in given range
*
* function GetClosestDestructable takes real x, real y, boolean treeOnly, boolexpr filter returns destructable
* - Gets single destructable, nearest passed coordinates
* function GetClosestDestructableInRange takes real x, real y, real radius, boolean treeOnly, boolexpr filter returns destructable
* - Retrieves single destructable, closest to coordinates in given range
*
* function GetClosestUnit takes real x, real y, boolexpr filter returns unit
* - Returns closest unit matching specific filter
* function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
* - Gets nearest unit in range matching specific filter
* function GetClosestUnitInGroup takes real x, real y, group g returns unit
* - Retrieves closest unit in given group
*
* function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
* - Returns up to N nearest units in range of passed coordinates
* function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
* - Retrieves up to N closest units in passed group
*
*****************************************************************************/
library GetClosestWidget uses optional IsDestructableTree
private keyword Init
globals
private unit array Q
private real array V
private integer C=0
endglobals
struct ClosestWidget extends array
readonly static destructable cDest=null
readonly static item cItem=null
readonly static real distance=0
readonly static real cX=0
readonly static real cY=0
readonly static unit cUnit=null
static boolean cTree=false
static rect initRect=null
static method resetData takes real x, real y returns nothing
set cDest=null
set distance=100000
set cItem=null
set cUnit=null
set cX=x
set cY=y
endmethod
static method enumItems takes nothing returns nothing
local item i=GetEnumItem()
local real dx=GetWidgetX(i)-cX
local real dy=GetWidgetY(i)-cY
set dx = (dx*dx+dy*dy)/10000.
if dx<distance then
set cItem=i
set distance=dx
endif
set i =null
endmethod
static method enumDestructables takes nothing returns nothing
local destructable d=GetEnumDestructable()
local real dx
local real dy
static if LIBRARY_IsDestructableTree then
if cTree and not IsDestructableTree(d) then
return
endif
endif
set dx=GetWidgetX(d)-cX
set dy=GetWidgetY(d)-cY
set dx=(dx*dx+dy*dy)/10000.
if dx<distance then
set cDest=d
set distance=dx
endif
set d=null
endmethod
static method enumUnits takes nothing returns nothing
local unit u=GetEnumUnit()
local real dx=GetUnitX(u)-cX
local real dy=GetUnitY(u)-cY
set dx=(dx*dx+dy*dy)/10000.
if dx<distance then
set cUnit=u
set distance=dx
endif
set u=null
endmethod
static method sortUnits takes integer l, integer r returns nothing
local integer i=l
local integer j=r
local real v=V[(l+r)/2]
loop
loop
exitwhen V[i]>=v
set i=i+1
endloop
loop
exitwhen V[j]<=v
set j=j-1
endloop
if i<=j then
set V[0]=V[i]
set V[i]=V[j]
set V[j]=V[0]
set Q[0]=Q[i]
set Q[i]=Q[j]
set Q[j]=Q[0]
set i=i+1
set j=j-1
endif
exitwhen i>j
endloop
if l<j then
call sortUnits(l,j)
endif
if r>i then
call sortUnits(i,r)
endif
endmethod
static method saveGroup takes nothing returns nothing
local real dx
local real dy
set C=C+1
set Q[C]=GetEnumUnit()
set dx=GetUnitX(Q[C])-cX
set dy=GetUnitY(Q[C])-cY
set V[C]=(dx*dx+dy*dy)/10000.
endmethod
implement Init
endstruct
private module Init
private static method onInit takes nothing returns nothing
set thistype.initRect=Rect(0,0,0,0)
endmethod
endmodule
function GetClosestItem takes real x, real y, boolexpr filter returns item
local real r=800.
call ClosestWidget.resetData(x,y)
loop
if r>3200. then
call EnumItemsInRect(bj_mapInitialPlayableArea, filter, function ClosestWidget.enumItems)
exitwhen true
else
call SetRect(ClosestWidget.initRect,x-r,y-r,x+r,y+r)
call EnumItemsInRect(ClosestWidget.initRect, filter, function ClosestWidget.enumItems)
exitwhen ClosestWidget.cItem!=null
endif
set r=2*r
endloop
return ClosestWidget.cItem
endfunction
function GetClosestItemInRange takes real x, real y, real radius, boolexpr filter returns item
call ClosestWidget.resetData(x,y)
if radius>=0 then
call SetRect(ClosestWidget.initRect,x-radius,y-radius,x+radius,y+radius)
call EnumItemsInRect(ClosestWidget.initRect, filter, function ClosestWidget.enumItems)
endif
return ClosestWidget.cItem
endfunction
function GetClosestDestructable takes real x, real y, boolean treeOnly, boolexpr filter returns destructable
local real r=800.
call ClosestWidget.resetData(x,y)
set ClosestWidget.cTree=treeOnly
loop
if r>3200. then
call EnumDestructablesInRect(bj_mapInitialPlayableArea, filter, function ClosestWidget.enumDestructables)
exitwhen true
else
call SetRect(ClosestWidget.initRect,x-r,y-r,x+r,y+r)
call EnumDestructablesInRect(ClosestWidget.initRect, filter, function ClosestWidget.enumDestructables)
exitwhen ClosestWidget.cDest!=null
endif
set r=2*r
endloop
return ClosestWidget.cDest
endfunction
function GetClosestDestructableInRange takes real x, real y, real radius, boolean treeOnly, boolexpr filter returns destructable
call ClosestWidget.resetData(x,y)
if radius>=0 then
set ClosestWidget.cTree=treeOnly
call SetRect(ClosestWidget.initRect,x-radius,y-radius,x+radius,y+radius)
call EnumDestructablesInRect(ClosestWidget.initRect, filter, function ClosestWidget.enumDestructables)
endif
return ClosestWidget.cDest
endfunction
function GetClosestUnit takes real x, real y, boolexpr filter returns unit
local real r=800.
call ClosestWidget.resetData(x,y)
loop
if r>3200. then
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, filter)
exitwhen true
else
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, r, filter)
exitwhen FirstOfGroup(bj_lastCreatedGroup)!=null
endif
set r=2*r
endloop
call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
return ClosestWidget.cUnit
endfunction
function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
call ClosestWidget.resetData(x,y)
if radius>=0 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
endif
return ClosestWidget.cUnit
endfunction
function GetClosestUnitInGroup takes real x, real y, group g returns unit
call ClosestWidget.resetData(x,y)
call ForGroup(g, function ClosestWidget.enumUnits)
return ClosestWidget.cUnit
endfunction
function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
local integer q=n+1
call ClosestWidget.resetData(x,y)
if radius>=0 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
call ForGroup(bj_lastCreatedGroup, function ClosestWidget.saveGroup)
call ClosestWidget.sortUnits(1,C)
loop
exitwhen n==0 or Q[-n+q]==null
call GroupAddUnit(g, Q[-n+q])
set n =n-1
endloop
endif
set C=0
endfunction
function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
local integer q=n+1
call ClosestWidget.resetData(x,y)
call ForGroup(sourceGroup, function ClosestWidget.saveGroup)
call ClosestWidget.sortUnits(1,C)
loop
exitwhen n==0 or Q[-n+q]==null
call GroupAddUnit(destGroup, Q[-n+q])
set n=n-1
endloop
set C=0
endfunction
endlibrary
//TESH.scrollpos=16
//TESH.alwaysfold=0
/**************************************
*
* IsUnitChanneling
* v2.1.0.0
* By Magtheridon96
*
* - Tells whether a unit is channeling or not.
*
* Requirements:
* -------------
*
* - RegisterPlayerUnitEvent by Magtheridon96
* - hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/
*
* Optional:
* ---------
*
* - UnitIndexer by Nestharus
* - hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/
* - Table by Bribe
* - hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
* API:
* ----
*
* - function IsUnitChanneling takes unit whichUnit returns boolean
* - Tells whether a unit is channeling or not.
*
* - function IsUnitChannelingById takes integer unitIndex returns boolean
* - Tells whether a unit is channeling or not given the unit index.
* (This function is only available if you have UnitIndexer)
*
**************************************/
library IsUnitChanneling requires optional UnitIndexer, optional Table, RegisterPlayerUnitEvent
private struct OnChannel extends array
static if LIBRARY_UnitIndexer then
static boolean array channeling
else
static if LIBRARY_Table then
static key k
static Table channeling = k
else
static hashtable hash = InitHashtable()
endif
endif
private static method onEvent takes nothing returns nothing
static if LIBRARY_UnitIndexer then
local integer id = GetUnitUserData(GetTriggerUnit())
set channeling[id] = not channeling[id]
else
static if LIBRARY_Table then
local integer id = GetHandleId(GetTriggerUnit())
set channeling.boolean[id] = not channeling.boolean[id]
else
local integer id = GetHandleId(GetTriggerUnit())
call SaveBoolean(hash, 0, id, not LoadBoolean(hash, 0, id))
endif
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.onEvent)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_ENDCAST, function thistype.onEvent)
endmethod
endstruct
static if LIBRARY_UnitIndexer then
function IsUnitChannelingById takes integer id returns boolean
return OnChannel.channeling[id]
endfunction
endif
function IsUnitChanneling takes unit u returns boolean
static if LIBRARY_UnitIndexer then
return OnChannel.channeling[GetUnitUserData(u)]
else
static if LIBRARY_Table then
return OnChannel.channeling.boolean[GetHandleId(u)]
else
return LoadBoolean(OnChannel.hash, 0, GetHandleId(u))
endif
endif
endfunction
endlibrary
//TESH.scrollpos=113
//TESH.alwaysfold=0
library SimpleFunctions initializer init
globals
private location LOC = Location(0,0)
private group TempG = CreateGroup()
private unit dummy = null
endglobals
private function init takes nothing returns nothing
set dummy = CreateUnit(Player(15), 'ewsp', 0, 0, 0)
call UnitAddAbility(dummy, 'Aloc')
call ShowUnit(dummy, false)
call PauseUnit(dummy, true)
endfunction
function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
function AngularHeightDrop takes real height, real distance, real speed returns real
return (distance/height) * speed
endfunction
function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)//Standard parabola
endfunction
function GetUnitZ takes unit u, real height returns real
call MoveLocation(LOC, GetUnitX(u), GetUnitY(u))
return GetLocationZ(LOC) + height
endfunction
function GetAngle takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2-y1, x2-x1)
endfunction
function GetDistance takes real x1, real y1, real x2, real y2 returns real
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
endfunction
function GetDistanceEx takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction
function GetDistanceFromUnit takes unit u, unit u2 returns real
return GetDistance(GetUnitX(u), GetUnitY(u), GetUnitX(u2), GetUnitY(u2))
endfunction
function SetUnitXY takes unit u, real xPoint, real yPoint, real speed, real angle returns nothing
call SetUnitX(u, xPoint + speed * Cos(angle))
call SetUnitY(u, yPoint + speed * Sin(angle))
endfunction
function GetAngleUnitFacing takes unit u returns real
return GetUnitFacing(u) * bj_DEGTORAD
endfunction
function MakeUnitFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
function UnitRemoveLocust takes unit u returns nothing
call ShowUnit(u, false)
call UnitRemoveAbility(u, 'Aloc')
call ShowUnit(u, true)
endfunction
function UnitAddLocust takes unit u returns nothing
call UnitAddAbility(u, 'Aloc')
endfunction
function UnitRemoveLocust takes unit u returns nothing
call ShowUnit(u, false)
call UnitRemoveAbility(u, 'Aloc')
call ShowUnit(u, true)
endfunction
function SpecialEffectXY takes string sfx, real x, real y returns nothing
call DestroyEffect(AddSpecialEffect(sfx, x, y))
endfunction
function SpecialEffectTarget takes unit u, string sfx, string attachment returns nothing
call DestroyEffect(AddSpecialEffectTarget(sfx, u, attachment))
endfunction
function IsUnitOrganic takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MECHANICAL) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and UnitAlive(u)
endfunction
function LifeTaken takes unit u returns boolean
return (GetWidgetLife(u)) < (GetUnitState(u, UNIT_STATE_MAX_LIFE))
endfunction
function DamageEnemyUnits takes unit source, unit target, real d, attacktype atk, damagetype dmg, boolean air returns nothing
if IsUnitEnemy(source, GetOwningPlayer(target)) and UnitAlive(target) then
if air and IsUnitType(target, UNIT_TYPE_FLYING) then
call UnitDamageTarget(source, target, d, false, false, atk, dmg, null)
else
call UnitDamageTarget(source, target, d, false, false, atk, dmg, null)
endif
endif
endfunction
function DamageTarget takes unit source, unit target, real d, attacktype atk, damagetype dmg returns nothing
call UnitDamageTarget(source, target, d, false, false, atk, dmg, null)
endfunction
function AngularHeightDrop takes real height, real distance, real speed returns real
return (distance/height) * speed
endfunction
function NoEnemyUnits takes unit u, real radius returns boolean
local unit first
call GroupEnumUnitsInRange(TempG, GetUnitX(u), GetUnitY(u), radius, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(u)) or IsUnitType(first, UNIT_TYPE_STRUCTURE) then
return false
endif
call GroupRemoveUnit(TempG, first)
endloop
return true
endfunction
function CreateUnitAtRect takes integer unitID, rect r, player owner, real facing, boolean center returns unit
local unit u
local integer x
local integer y
if center then
set u = CreateUnit(owner, unitID, GetRectCenterX(r), GetRectCenterY(r), facing)
else
set x = GetRandomInt(R2I(GetRectMinX(r)), R2I(GetRectMaxX(r)))
set y = GetRandomInt(R2I(GetRectMinY(r)), R2I(GetRectMaxY(r)))
set u = CreateUnit(owner, unitID, I2R(x), I2R(y), facing)
endif
return u
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//System: Fundamentals
//Made by Mckill2009
//These are simple conversions, easy to use functions compilation
library Fundamentals
globals
private location LOC = Location(0,0)
private real Z
private real ANGLE
private real DISTANCE
private real SET_X
private real SET_Y
private boolean B
private unit FIRST_UNIT
private unit CASTER
endglobals
function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)//Standard parabola
endfunction
function GetUnitZ takes unit u, real height returns real
call MoveLocation(LOC, GetUnitX(u), GetUnitY(u))
set Z = GetLocationZ(LOC)
return Z + height
endfunction
function GetAngle takes real x1, real y1, real x2, real y2 returns real
set ANGLE = Atan2(y2-y1, x2-x1)
return ANGLE
endfunction
function GetAngleUnitFacing takes unit u returns real
return GetUnitFacing(u) * bj_DEGTORAD
endfunction
function GetDistance takes real x1, real y1, real x2, real y2 returns real
set DISTANCE = SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
return DISTANCE
endfunction
function SetDummyX takes real xPoint, real speed, real angle returns real
set SET_X = xPoint + speed * Cos(angle)
return SET_X
endfunction
function SetDummyY takes real yPoint, real speed, real angle returns real
set SET_Y = yPoint + speed * Sin(angle)
return SET_Y
endfunction
function MakeUnitFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
function UnitAddLocust takes unit u returns nothing
call UnitAddAbility(u, 'Aloc')
endfunction
function UnitRemoveLocust takes unit u returns nothing
call ShowUnit(u, false)
call UnitRemoveAbility(u, 'Aloc')
call ShowUnit(u, true)
endfunction
//===GET FIRST UNIT:
//Sample >>> local unit tar = GetFirstUnitInRange(u, x1, y1, 1000, 1)
function GetFirstEnemyUnit takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(CASTER)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MECHANICAL)
set u = null
return b
endfunction
function GetFirstAllyUnit takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and not IsUnitEnemy(u, GetOwningPlayer(CASTER)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MECHANICAL)
set u = null
return b
endfunction
function GetFirstAllyStructure takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and not IsUnitEnemy(u, GetOwningPlayer(CASTER)) and IsUnitType(u, UNIT_TYPE_STRUCTURE)
set u = null
return b
endfunction
function GetFirstEnemyStructure takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(CASTER)) and IsUnitType(u, UNIT_TYPE_STRUCTURE)
set u = null
return b
endfunction
function GetFirstUnitInRange takes unit u, real x, real y, real aoe, integer id returns unit
set CASTER = u
if id==1 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, Filter(function GetFirstEnemyUnit))
elseif id==2 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, Filter(function GetFirstAllyUnit))
elseif id==3 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, Filter(function GetFirstAllyStructure))
elseif id==4 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, Filter(function GetFirstEnemyStructure))
endif
set FIRST_UNIT = FirstOfGroup(bj_lastCreatedGroup)
return FIRST_UNIT
endfunction
//===DUMMY TARGET SPELL:
function IssueTargetSpell takes unit caster, unit target, integer spellId, integer dummyspellId, integer dummyId, integer orderId returns nothing
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local integer level = GetUnitAbilityLevel(caster, spellId)
local unit dummy = CreateUnit(GetOwningPlayer(caster), dummyId, x, y, 0)
call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
call UnitAddAbility(dummy, dummyspellId)
call SetUnitAbilityLevel(dummy, dummyspellId, level)
call IssueTargetOrderById(dummy, orderId, target)
endfunction
//===DUMMY POINT SPELL:
//Sample >>> call IssuePointSpell(u, x, y, 'A000', 'ACca', 'h002', 852218)
function IssuePointSpell takes unit caster, real x, real y, integer spellId, integer dummyspellId, integer dummyId, integer orderId returns nothing
local unit dummy = CreateUnit(GetOwningPlayer(caster), dummyId, x, y, 0)
local integer level = GetUnitAbilityLevel(caster, spellId)
local real x1 = SetDummyX(x, 100, GetAngleUnitFacing(caster))
local real y1 = SetDummyY(y, 100, GetAngleUnitFacing(caster))
call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
call UnitAddAbility(dummy, dummyspellId)
call SetUnitAbilityLevel(dummy, dummyspellId, level)
call IssuePointOrderById(dummy, orderId, x1, y1)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DummyHero uses T32, RegisterPlayerUnitEvent
struct DH
private unit dummy
private unit c
private method periodic takes nothing returns nothing
call SetUnitX(.dummy, GetUnitX(.c))
call SetUnitY(.dummy, GetUnitY(.c))
endmethod
implement T32x
static method register takes unit u returns nothing
local thistype this = allocate()
set .c = u
set .dummy = CreateUnit(GetOwningPlayer(u), 'H000', 0, 0, 0)
call UnitRemoveAbility(.dummy, 'Amov')
set udg_DummyHero = .dummy
call .startPeriodic()
endmethod
private static method deselect takes nothing returns nothing
if GetTriggerUnit()==udg_DummyHero then
call ClearSelection()
call SelectUnit(udg_Hero, true)
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEventForPlayer(EVENT_PLAYER_UNIT_SELECTED, function thistype.deselect, Player(0))
endmethod
endstruct
endlibrary
//TESH.scrollpos=78
//TESH.alwaysfold=0
library QuestUtils /* v1.5
****************************************************************************
* by mckill2009
*
* A simple quest wrapper for Quest creation
*
****************************************************************************
*
* API:
* struct QuestUtils extends array
* static method create takes boolean required returns thistype
* method operator []= takes string title, string description returns nothing
* method operator questIcon= takes string iconPath returns nothing
* method operator completed= takes boolean b returns nothing
* method operator failed= takes boolean b returns nothing
* method operator enable= takes boolean b returns nothing
* method operator discover= takes boolean b returns nothing
* method operator completed takes nothing returns boolean
* method operator discovered takes nothing returns boolean
* method operator enabled takes nothing returns boolean
* method operator required takes nothing returns boolean
* method destroy takes nothing returns nothing
*
* struct QuestItem extends array
* static method create takes QuestUtils index, string text returns thistype
* method operator text= takes string text returns nothing
* method operator completed= takes boolean b returns nothing
* method operator completed takes nothing returns boolean
* method destroy takes nothing returns nothing
*
****************************************************************************/
globals
private constant integer QUEST_LIMIT = 100
endglobals
struct QuestUtils extends array
quest q
private static thistype instance = 0
static method create takes boolean required returns thistype
local thistype this
if instance==QUEST_LIMIT then
debug call BJDebugMsg("QuestUtils ERROR: Maximum quest is: "+I2S(QUEST_LIMIT))
else
set this = instance + 1
set instance = this
set .q = CreateQuest()
call QuestSetRequired(.q, required)
endif
return this
endmethod
method operator []= takes string title, string description returns nothing
call QuestSetTitle(.q, title)
call QuestSetDescription(.q, description)
call FlashQuestDialogButton()
endmethod
method operator questIcon= takes string iconPath returns nothing
call QuestSetIconPath(.q, iconPath)
endmethod
method operator completed= takes boolean b returns nothing
call QuestSetCompleted(.q, b)
call FlashQuestDialogButton()
endmethod
method operator failed= takes boolean b returns nothing
call QuestSetFailed(.q, b)
call FlashQuestDialogButton()
endmethod
method operator enable= takes boolean b returns nothing
call QuestSetEnabled(.q, b)
call FlashQuestDialogButton()
endmethod
method operator discover= takes boolean b returns nothing
call QuestSetDiscovered(.q, b)
call FlashQuestDialogButton()
endmethod
method operator completed takes nothing returns boolean
return IsQuestCompleted(.q)
endmethod
method operator discovered takes nothing returns boolean
return IsQuestDiscovered(.q)
endmethod
method operator enabled takes nothing returns boolean
return IsQuestEnabled(.q)
endmethod
method operator required takes nothing returns boolean
return IsQuestRequired(.q)
endmethod
method destroy takes nothing returns nothing
call DestroyQuest(.q)
set .q = instance.q
set instance = instance - 1
endmethod
endstruct
struct QuestItem extends array
questitem qi
private static thistype instance = 0
static method create takes QuestUtils index, string text returns thistype
local thistype this = instance + 1
set instance = this
set .qi = QuestCreateItem(index.q)
call QuestItemSetDescription(.qi, text)
call FlashQuestDialogButton()
return this
endmethod
method operator text= takes string text returns nothing
call QuestItemSetDescription(.qi, text)
call FlashQuestDialogButton()
endmethod
method operator completed= takes boolean b returns nothing
call QuestItemSetCompleted(.qi, b)
call FlashQuestDialogButton()
endmethod
method operator completed takes nothing returns boolean
return IsQuestItemCompleted(.qi)
endmethod
method destroy takes nothing returns nothing
set .qi = instance.qi
set instance = instance - 1
endmethod
endstruct
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
/*
===QuestSounds v1.0
===By Mckill2009
Sounds should be in Mp3 format
*/
library QuestSounds
//sample: call PlayCompletedSound()
//! textmacro Sound takes Func, Snd
function Play$Func$Sound takes nothing returns nothing
call StartSound(bj_quest$Snd$Sound)
endfunction
//! endtextmacro
//! runtextmacro Sound("Completed","Completed")
//! runtextmacro Sound("Discovered","Discovered")
//! runtextmacro Sound("Failed","Failed")
//! runtextmacro Sound("Hint","Hint")
//! runtextmacro Sound("ItemAcquired","ItemAcquired")
//! runtextmacro Sound("Secret","Secret")
//! runtextmacro Sound("Updated","Updated")
//! runtextmacro Sound("Warning","Warning")
//sample: call PlaySound(gg_snd_SOUNDFILENAME, false)
//if killWheDone is true, it will destroy the sound and clears the leak but
//if you use the sound again, then you should set it to false
function PlayCustomSound takes sound soundHandle, boolean killWhenDone returns nothing
call StartSound(soundHandle)
if killWhenDone then
call KillSoundWhenDone(soundHandle)
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DialogBox /* v1.0
****************************************************************************
* by mckill2009
* A Dialog Box wrapper
****************************************************************************
*
* API:
* static method create takes string title, code whichFunction returns thistype
* method operator setTitle= takes string messageText returns nothing
* method addButton takes string buttonText, integer hotkey returns button
* method addQuitButton takes boolean showScores, string buttonText, integer hotkey returns nothing
* method clickedButton takes button whichButton returns boolean
* method clickedBy takes player whichPlayer returns boolean
* method displayForAll takes nothing returns nothing
* method displayForPlayer takes player forPlayer, boolean b returns nothing
* method clear takes nothing returns nothing
* method destroy takes nothing returns nothing
*
****************************************************************************/
struct DialogBox
trigger t
dialog dia
static method create takes string title, code whichFunction returns thistype
local thistype this = allocate()
set .dia = DialogCreate()
set .t = CreateTrigger()
call TriggerRegisterDialogEvent(.t, .dia)
call TriggerAddCondition(.t, Filter(whichFunction))
call DialogSetMessage(.dia, title)
return this
endmethod
method operator setTitle= takes string messageText returns nothing
call DialogSetMessage(.dia, messageText)
endmethod
method addButton takes string buttonText, integer hotkey returns button
return DialogAddButton(.dia, buttonText, hotkey)
endmethod
method addQuitButton takes boolean showScores, string buttonText, integer hotkey returns nothing
call DialogAddQuitButton(.dia, showScores, buttonText, hotkey)
endmethod
method clickedButton takes button whichButton returns boolean
return GetClickedButton()==whichButton
endmethod
method clickedBy takes player whichPlayer returns boolean
return GetTriggerPlayer()==whichPlayer
endmethod
method displayForAll takes nothing returns nothing
local integer i = 0
loop
call DialogDisplay(Player(i), .dia, true)
set i = i+1
exitwhen i==bj_MAX_PLAYERS
endloop
endmethod
method displayForPlayer takes player forPlayer returns nothing
call DialogDisplay(forPlayer, .dia, true)
endmethod
method clear takes nothing returns nothing
call DialogClear(.dia)
endmethod
method destroy takes nothing returns nothing
local integer i
if .dia==null then
debug call BJDebugMsg("DialogBox ERROR: Attempt to destroy an invalid instance.")
else
set i = 0
loop
call DialogDisplay(Player(i), .dia, false)
set i = i+1
exitwhen i==bj_MAX_PLAYERS
endloop
call DialogClear(.dia)
call DialogDestroy(.dia)
call DestroyTrigger(.t)
set .dia = null
set .t = null
call .deallocate()
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=19
//TESH.alwaysfold=0
library ItemChargesMerger initializer init /* v1.1
*************************************************************************************
* by mckill2009
* A simple but useful to use item merger system.
************************************************************************************
*
* */ uses /*
*
* */ Table /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
* */ RegisterPlayerUnitEvent /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/
* */ optional SimError /* http://www.wc3c.net/showthread.php?t=101260
*
************************************************************************************/
globals
private Table tb
private Table sz
private item PickedItem = null
endglobals
private function PickUp takes nothing returns nothing
local unit u
local item itSlot
local integer i
local integer itemID = GetItemTypeId(GetManipulatedItem())
local integer pickedItemCharges
local integer pickedItemDropCharge
local integer chargesInSlot
local integer maxCharge
local integer totalCharges
if tb.has(itemID) then
set u = GetTriggerUnit()
set PickedItem = GetManipulatedItem()
set pickedItemCharges = GetItemCharges(PickedItem)
set i = 0
loop
set itSlot = UnitItemInSlot(u, i) //item already in slot
if GetItemTypeId(itSlot)==itemID and not (itSlot==PickedItem) then
set maxCharge = sz[itemID]
set chargesInSlot = GetItemCharges(itSlot)
set totalCharges = chargesInSlot + pickedItemCharges
set pickedItemDropCharge = totalCharges - maxCharge
if maxCharge > chargesInSlot then
if totalCharges > maxCharge then
call SetItemCharges(itSlot, maxCharge) //set to max
call SetItemCharges(PickedItem, pickedItemDropCharge) //reducing pick item charges
else
call SetItemCharges(itSlot, totalCharges) //set to max
endif
call UnitDropItemPoint(u, PickedItem, GetUnitX(u), GetUnitY(u))
if pickedItemDropCharge <= 0 then
call RemoveItem(PickedItem)
endif
else
call UnitDropItemPoint(u, PickedItem, GetUnitX(u), GetUnitY(u))
static if LIBRARY_SimError then
//call BJDebugMsg("you cant do this")
call SimError(GetTriggerPlayer(), "Maximum item of this type is only "+I2S(maxCharge))
endif
endif
exitwhen true
endif
set i = i+1
exitwhen i==6
endloop
set u = null
endif
endfunction
private function init takes nothing returns nothing
set tb = Table.create()
set sz = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function PickUp)
endfunction
/********************************************************
* API
*********************************************************/
public function AddItem takes integer itemID, integer maxSize returns nothing
if not tb.has(itemID) then
set tb[itemID] = 0
set sz[itemID] = maxSize
else
call BJDebugMsg("[ItemChargesMerger_AddItem] ERROR: You cannot register the same item type! ")
endif
endfunction
public function Remove takes integer itemID returns nothing
call tb.remove(itemID)
call sz.remove(itemID)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitHasItemType
function UnitHasItemType takes unit u, integer itemId returns boolean
local integer i = 0
local item it
loop
set it = UnitItemInSlot(u, i)
if GetItemTypeId(it)==itemId then
return true
endif
set i = i+1
exitwhen i==6
endloop
return false
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ItemTypeToItem
globals
private item it = null
endglobals
function ItemTypeToItem takes unit u, integer itemId returns item
local integer i = 0
local item it
loop
set it = UnitItemInSlot(u, i)
if GetItemTypeId(it)==itemId then
return it
endif
set i = i+1
exitwhen i==6
endloop
return null
endfunction
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
library DestroyTrees initializer init
globals
private unit dummy
private rect rct
endglobals
private function init takes nothing returns nothing
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hpea', 0, 0, 0)
call UnitAddAbility(dummy, 'Aloc')
call ShowUnit(dummy, false)
call PauseUnit(dummy, true)
endfunction
private function IsTree takes destructable d returns boolean
local boolean b
if GetWidgetLife(d)>0.405 then
call PauseUnit(dummy, false)
set b = IssueTargetOrderById(dummy, 852018, d)
call PauseUnit(dummy, true)
return b
endif
return false
endfunction
private function FilterTrees takes nothing returns boolean
if IsTree(GetFilterDestructable()) then
call KillDestructable(GetFilterDestructable())
endif
return false
endfunction
function DestroyTrees takes real x, real y, real aoe returns nothing
set rct = Rect(-aoe, -aoe, aoe, aoe)
call MoveRectTo(rct, x, y)
call EnumDestructablesInRect(rct, Filter(function FilterTrees), null)
call RemoveRect(rct)
endfunction
endlibrary
//TESH.scrollpos=18
//TESH.alwaysfold=0
library BallisticMissile /* v1.0
*********************************************************************
* by mckill2009
*********************************************************************
*
* */ uses /*
* */ T32 /* http://www.thehelper.net/threads/timer32.118245/
*
*********************************************************************
*
* Credits:
* Timer32 by Jesus4Lyf
*
********************************************************************/
globals
private constant integer MissileID = 'h00I'
private constant real COLLISION = 50
private group enumG = CreateGroup()
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
private function GetDistance takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction
struct BallisticMissile
private unit missile
private unit target
private real aoe
private real damage
private real height
private real speed
private real xTarget
private real yTarget
private string explodeEffect
private attacktype attack
private damagetype damageT
private effect sfx
private boolean traveling
private boolean enemy
private boolean targetAllUnitType
private static unit first
private method filtermore takes nothing returns nothing
if .targetAllUnitType then
call UnitDamageTarget(.missile, first, .damage, false, false, .attack, .damageT, null)
else
if not IsUnitType(first, UNIT_TYPE_FLYING) then
call UnitDamageTarget(.missile, first, .damage, false, false, .attack, .damageT, null)
endif
endif
endmethod
private method destroy takes nothing returns nothing
set .missile = null
set .target = null
set .sfx = null
call .deallocate()
endmethod
private method periodic takes nothing returns nothing
local real x1 = GetUnitX(.missile)
local real y1 = GetUnitY(.missile)
local real x2
local real y2
local real angle
local real distance
if .traveling then
if UnitAlive(.target) then
set .xTarget = GetUnitX(.target)
set .yTarget = GetUnitY(.target)
endif
set angle = Atan2(.yTarget - y1, .xTarget - x1)
set distance = GetDistance(x1, y1, .xTarget, .yTarget)
if distance > COLLISION then
call SetUnitX(.missile, x1 + .speed * Cos(angle))
call SetUnitY(.missile, y1 + .speed * Sin(angle))
call SetUnitFacing(.missile, angle*bj_RADTODEG)
else
set .traveling = false
endif
else
call DestroyEffect(.sfx)
call DestroyEffect(AddSpecialEffectTarget(.explodeEffect, .missile, "origin"))
call GroupEnumUnitsInRange(enumG, x1, y1, .aoe, null)
loop
set first = FirstOfGroup(enumG)
exitwhen first==null
if UnitAlive(first) then
if .enemy then
if IsUnitEnemy(first, GetOwningPlayer(.missile)) then
call .filtermore()
endif
else
call .filtermore()
endif
endif
call GroupRemoveUnit(enumG, first)
endloop
call UnitApplyTimedLife(.missile, 'BTLF', 2.0)
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method create takes player pl, string model, unit target, real xFrom, real yFrom, real facing returns thistype
local thistype this = allocate()
set .missile = CreateUnit(pl, MissileID, xFrom, yFrom, facing)
set .sfx = AddSpecialEffectTarget(model, .missile, "chest")
set .target = target
set .xTarget = 0
set .yTarget = 0
set .traveling = true
set .enemy = true
set .targetAllUnitType = true
call UnitAddAbility(.missile, 'Arav')
return this
endmethod
method setup takes real aoe, real damage, real height, real scale, real speed returns nothing
set .aoe = aoe
set .damage = damage
set .height = height
set .speed = speed
call SetUnitScale(.missile, scale, scale, scale)
endmethod
method setupDamageTypes takes attacktype attack, damagetype damageT returns nothing
set .attack = attack
set .damageT = damageT
endmethod
method setupTargets takes boolean enemy, boolean targetAllUnitType returns nothing
set .enemy = enemy
set .targetAllUnitType = targetAllUnitType
endmethod
method launch takes string explodeEffect returns nothing
set .explodeEffect = explodeEffect
call .startPeriodic()
endmethod
endstruct
endlibrary
//TESH.scrollpos=17
//TESH.alwaysfold=0
library IsUnitEngageable /* v1.2
************************************************************************************
* by mckill2009
************************************************************************************
*
* Installation:
* - Copy this script to your trigger editor via custom text
* - Copy the custom abilty from the object editor named 'IsUnitEngageable' to your map
* - Make sure you change also the rawID below (SPELL_ID) if you change the rawID of your imported ability
*
************************************************************************************
*
* function IsUnitEngageable takes unit u returns boolean
* Undetects units that is:
* - Invulnerable
* - Burrowed
* - Invisible
* - Ethereal
* - Have locust
*
************************************************************************************/
globals
/************************************************************************************
*
* Change the SPELL_ID according to the ability object named 'IsUnitEngageable'
*
*************************************************************************************/
private constant integer SPELL_ID = 'isun' //based on chain lightning
/************************************************************************************
*
* Never touch anything below this block
*
*************************************************************************************/
private constant integer DUMMY_ID = 'hmpr'
private unit DUMMY
endglobals
struct onInit
static method onInit takes nothing returns nothing
set DUMMY = CreateUnit(Player(15), DUMMY_ID, 0,0,0)
call UnitAddAbility(DUMMY, SPELL_ID)
call UnitAddAbility(DUMMY, 'Aloc')
call ShowUnit(DUMMY, false)
endmethod
endstruct
function IsUnitEngageable takes unit u returns boolean
call SetUnitPosition(DUMMY, GetUnitX(u), GetUnitY(u))
return IssueTargetOrderById(DUMMY, 852119, u) and not IsUnitType(u,UNIT_TYPE_ETHEREAL)
endfunction
endlibrary
//TESH.scrollpos=34
//TESH.alwaysfold=0
library SummonedEscort /* v1.5
***************************************************************************
* by mckill2009
***************************************************************************
*
* */ uses /*
* */ GetClosestWidget /* www.hiveworkshop.com/forums/jass-resources-412/snippet-getclosestwidget-204217
* */ Table /* www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084
*
***************************************************************************
*
* Features:
* - Allows your summoned units to follow and guards the summoner.
* - If the summoner dies, the summoned unit searches for a new ally or
* returns to it's original location.
* - Used also to focus attack an enemy hero or unit.
*
***************************************************************************
*
* Installation:
* Copy and paste the required libraries and this code to your map
*
***************************************************************************
*
* API:
* static method summoned takes unit summoningUnit, unit summonedUnit returns nothing
* - call SE.summoned(GetSummoningUnit(),GetTriggerUnit())
* - If AUTO is true, it will do automatically for you.
* - AUTO only works for summoned unit
*
* static method remove takes unit escortUnit returns nothing
* - Removes the escort from the system
*
***************************************************************************/
globals
/**************************************************************************
* Auto registers ALL summoned units in map, it is recommended to set this
* to false if you want a unit to escort an ally or attack an enemy hero/unit
***************************************************************************/
private constant boolean AUTO = false
/**************************************************************************
* Searches for closest ally hero if main hero is dead, if FOLLOW_ONLY_HEROES
* is false, the escort will follow a closest ally
***************************************************************************/
private constant boolean ALLY_IN_RANGE = false
/**************************************************************************
* The unit only follows heroes when the main unit dies
***************************************************************************/
private constant boolean FOLLOW_ONLY_HEROES = true
/**************************************************************************
* This is the offset distance from the unit to his master
***************************************************************************/
private constant real OFFSET = 300
/**************************************************************************
* Searches for closest ally if main ally unit is dead
* ALLY_IN_RANGE must be true
***************************************************************************/
private constant real CLOSEST_ALLY = 600
/**************************************************************************
* Targets/attacks closest enemy in range of master
***************************************************************************/
private constant real CLOSEST_ENEMY = 1500
endglobals
struct SE
private unit master
private unit sum
private real xUnit
private real yUnit
private static integer DATA
private static constant integer ATTACK = 851983
private static timer t = CreateTimer()
private static integer instance = 0
private static integer array insAR
private static unit TempUnit = null
private static Table tb
private static method UnitAlive takes unit u returns boolean
return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null
endmethod
private static method closestEnemy takes nothing returns boolean
local thistype this = DATA
set TempUnit = GetFilterUnit()
return UnitAlive(TempUnit) and IsUnitEnemy(TempUnit, GetOwningPlayer(.sum))
endmethod
private static method closestAlly takes nothing returns boolean
local thistype this = DATA
set TempUnit = GetFilterUnit()
if UnitAlive(TempUnit) and GetOwningPlayer(TempUnit)==GetOwningPlayer(.sum) and TempUnit!=.sum /*
*/ and not IsUnitType(TempUnit,UNIT_TYPE_STRUCTURE) and GetUnitMoveSpeed(TempUnit)>0 then
static if FOLLOW_ONLY_HEROES then
return IsUnitType(TempUnit, UNIT_TYPE_HERO)
endif
return true
endif
return false
endmethod
private method destroy takes nothing returns nothing
set .master = null
set .sum = null
call .deallocate()
endmethod
private static method looper takes nothing returns nothing
local thistype this
local unit target
local integer orderSum
local integer index = 0
local real angle
local real xMaster
local real yMaster
local real xSummoned
local real ySummoned
loop
set index = index+1
set this = insAR[index]
if UnitAlive(.sum) and tb.has(GetHandleId(.sum)) then
set angle = GetRandomReal(0,6.28)
set orderSum = GetUnitCurrentOrder(.sum)
if UnitAlive(.master) then
if orderSum==0 then
set xMaster = GetUnitX(.master)+OFFSET*Cos(angle)
set yMaster = GetUnitY(.master)+OFFSET*Sin(angle)
call IssuePointOrderById(.sum,ATTACK,xMaster,yMaster)
set DATA = this
set target = GetClosestUnitInRange(xMaster,yMaster,CLOSEST_ENEMY,Filter(function thistype.closestEnemy))
if target!=null then
if IsUnitType(target,UNIT_TYPE_SLEEPING) then
call IssueTargetOrderById(.sum,ATTACK,target)
else
call IssuePointOrderById(.sum,ATTACK,GetUnitX(target),GetUnitY(target))
endif
set target = null
endif
endif
else
set DATA = this
set xSummoned = GetUnitX(.sum)
set ySummoned = GetUnitY(.sum)
static if ALLY_IN_RANGE then
set .master = GetClosestUnitInRange(xSummoned,ySummoned,CLOSEST_ALLY,Filter(function thistype.closestAlly))
else
set .master = GetClosestUnit(xSummoned,ySummoned,Filter(function thistype.closestAlly))
endif
if .master==null and orderSum==0 then
call IssuePointOrderById(.sum,ATTACK,.xUnit+OFFSET*Cos(angle),.yUnit+OFFSET*Sin(angle))
endif
endif
else
call .destroy()
set insAR[index] = insAR[instance]
set insAR[instance] = this
set index = index - 1
set instance = instance - 1
if instance==0 then
call PauseTimer(t)
endif
endif
exitwhen index==instance
endloop
endmethod
private static method create takes unit summoningUnit, unit summonedUnit returns thistype
local thistype this
if instance==8190 then
call BJDebugMsg("Library_SummonedEscort ERROR: Too many instances!")
else
set this = allocate()
set .master = summoningUnit
set .sum = summonedUnit
set .xUnit = GetUnitX(summonedUnit)
set .yUnit = GetUnitY(summonedUnit)
set tb[GetHandleId(.sum)] = 0
if instance==0 then
call TimerStart(t,1.0,true,function thistype.looper)
endif
set instance = instance + 1
set insAR[instance] = this
call RemoveGuardPosition(summonedUnit)
endif
return this
endmethod
private static method fire takes nothing returns boolean
call thistype.create(GetSummoningUnit(),GetTriggerUnit())
return false
endmethod
private static method onInit takes nothing returns nothing
static if AUTO then
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SUMMON)
call TriggerAddCondition(t,function thistype.fire)
set t = null
endif
set tb = Table.create()
endmethod
//API:======================================
static method summoned takes unit summoningUnit, unit summonedUnit returns nothing
call thistype.create(summoningUnit,summonedUnit)
endmethod
static method remove takes unit escortUnit returns nothing
call tb.remove(GetHandleId(escortUnit))
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SimpleTextTag
function SimTTLoc takes string s, real x, real y, real position, real size returns nothing
local texttag tag = CreateTextTag()
call SetTextTagPos(tag, x, y, position)
call SetTextTagText(tag, s, size) //base: 0.01
call SetTextTagPermanent(tag, false)
call SetTextTagVelocity(tag, 0.03, 0.03)
call SetTextTagLifespan(tag, 3)
call SetTextTagFadepoint(tag, 0.01)
set tag = null
endfunction
function SimTTUnit takes string s, unit u, real heightoffset, real size returns nothing
local texttag tag = CreateTextTag()
call SetTextTagPosUnit(tag, u, heightoffset)
call SetTextTagText(tag, s, size) //base: 0.01
call SetTextTagPermanent(tag, false)
call SetTextTagVelocity(tag, 0.03, 0.03)
call SetTextTagLifespan(tag, 3)
call SetTextTagFadepoint(tag, 0.01)
set tag = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library EngageSystemLite/* v1.0
********************************************************************
* by mckill2009
**********************************************************************
*
* */ uses /*
* */ Table /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
* */ IsUnitEngageable /* http://www.hiveworkshop.com/forums/jass-resources-412/isunitengageable-220436/
* */ IsUnitChanneling /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-isunitchanneling-211254/
*
**********************************************************************
*
* API:
* static method add takes unit engager, real xReturn, real yReturn, boolean retreat, boolean pickItem returns nothing
*
* static method remove takes unit engager returns nothing
*
**********************************************************************/
globals
private constant integer ATTACK = 851983
private constant integer MOVE = 851986
private timer t
private integer index = 0
private integer array indexAR
private group enumG = CreateGroup()
private Table tb
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
struct EngageLite
unit u
unit target
real xReturn
real yReturn
boolean retreat
boolean pickItem //for heroes only
boolean notHero
boolean engage
private static method onInit takes nothing returns nothing
set tb = Table.create()
endmethod
private method searching takes nothing returns nothing
local unit first
call GroupEnumUnitsInRect(enumG, bj_mapInitialPlayableArea, null)
loop
set first = FirstOfGroup(enumG)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.u)) and IsUnitEngageable(first) then
set .target = first
exitwhen true
endif
call GroupRemoveUnit(enumG, first)
endloop
endmethod
private static method attacking takes nothing returns nothing
local thistype this
local integer i = 0
loop
set i = i+1
set this = indexAR[i]
if .engage then
if UnitAlive(.u) then
if not UnitAlive(.target) or .target==null then
call .searching()
if not IsUnitChanneling(.u) and GetUnitCurrentOrder(.u)!=ATTACK then
call IssuePointOrderById(.u, ATTACK, .xReturn, .yReturn)
endif
else
if IsUnitEngageable(.target) then
if not IsUnitChanneling(.u) and GetUnitCurrentOrder(.u)!=ATTACK then
call IssuePointOrderById(.u, ATTACK, GetUnitX(.target), GetUnitY(.target))
if IsUnitType(.target, UNIT_TYPE_SLEEPING) then
call IssueTargetOrderById(.u, ATTACK, .target)
endif
endif
else
set .target = null
endif
endif
else
if .notHero then
set .engage = false
endif
endif
else
set .u = null
set .target = null
call .deallocate()
set indexAR[i] = indexAR[index]
set indexAR[index] = this
set index = index - 1
set i = i-1
if index==0 then
call PauseTimer(t)
call DestroyTimer(t)
endif
endif
exitwhen i==index
endloop
endmethod
static method add takes unit engager, real xReturn, real yReturn, boolean retreat, boolean pickItem returns nothing
local thistype this
local integer id = GetHandleId(engager)
if tb.has(id) then
call BJDebugMsg("[EngageSystemLite][thistype.add] ERROR: "+GetUnitName(engager)+" cannot be added twice, remove it first!")
return
else
set this = thistype.allocate()
set .u = engager
set .target = null
set .xReturn = xReturn
set .yReturn = yReturn
set .retreat = retreat
set .pickItem = false
set .notHero = true
set .engage = true
call RemoveGuardPosition(engager)
if IsUnitType(engager, UNIT_TYPE_HERO) then
set tb[id] = this
set .pickItem = pickItem
set .notHero = false
endif
if index==0 then
set t = CreateTimer()
call TimerStart(t, 3.0, true, function thistype.attacking)
endif
set index = index + 1
set indexAR[index] = this
endif
endmethod
static method remove takes unit engager returns nothing
local integer id = GetHandleId(engager)
local thistype this
if tb.has(id) and IsUnitType(engager, UNIT_TYPE_HERO) then
set this = tb[id]
set .engage = false
else
call BJDebugMsg("[EngageSystemLite][thistype.remove] ERROR: "+GetUnitName(engager)+" is either not a hero or not added!")
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=54
//TESH.alwaysfold=0
library Quests uses QuestUtils
globals
private QuestUtils inv
private QuestItem array invI
private QuestUtils rus
private QuestItem array rusI
private QuestUtils sur
private QuestItem array surI
private QuestUtils ter
private QuestItem array terI
endglobals
struct Quests extends array
private static method onInit takes nothing returns nothing
set inv = inv.create(true)
set inv.discover = false
set rus = rus.create(true)
set rus.discover = false
set sur = sur.create(true)
set sur.discover = false
set ter = ter.create(true)
set ter.discover = false
endmethod
/******************************************************************
* Quest 1: Find Town, from Intro trigger
*******************************************************************/
static method findTown takes boolean b returns nothing
if b then
set inv.discover = true
set inv["Find Town"] = "Find and investigate the town."
set inv.questIcon = "ReplaceableTextures\\CommandButtons\\BTNKeep.blp"
set invI[1] = invI[1].create(inv, "Find the town")
set invI[2] = invI[2].create(inv, "Investigate")
else
set inv.completed = true
call PlayCompletedSound()
endif
endmethod
static method findTownEx takes integer instance returns nothing
set invI[instance].completed = true
endmethod
/******************************************************************
* Quest 2: Rush
*******************************************************************/
static method rush takes boolean b returns nothing
if b then
set rus.discover = true
set rus["Rush"] = "
You were surpised on what happened, and thinking of communicating to your base
but seems the weather is interfering the signal."
set rus.questIcon = "ReplaceableTextures\\CommandButtons\\BTNInvisibility.blp"
set rusI[1] = rusI[1].create(rus, "Find and go to higher ground")
set rusI[2] = rusI[2].create(rus, "Go back to town")
else
set rus.completed = true
call PlayCompletedSound()
endif
endmethod
static method rushEx takes integer instance returns nothing
set rusI[instance].completed = true
endmethod
/******************************************************************
* Quest 3: Get barricade and Survive
*******************************************************************/
static method survive takes boolean b returns nothing
if b then
set sur.discover = true
set sur["Survive"] = "Zombies smells your flesh, go back to the base and defend yourself, find barricades."
set sur.questIcon = "ReplaceableTextures\\CommandButtons\\BTNZombie.blp"
set surI[1] = surI[1].create(sur, "Acquire the barricades")
set surI[2] = surI[2].create(sur, "?????")
else
set sur.completed = true
call PlayCompletedSound()
endif
endmethod
static method surviveXX takes nothing returns nothing
set surI[2].text = "Survive for "+I2S(R2I(SURVIVE_DURATION/60))+" minutes."
endmethod
static method surviveEx takes integer instance returns nothing
set surI[instance].completed = true
endmethod
/******************************************************************
* Quest 4: Wait for allies and kill the terminator
*******************************************************************/
static method last takes boolean b returns nothing
if b then
set ter.discover = true
set ter["Go n Kill"] = "Wait for your allies to come to help you kill the Terminator."
set ter.questIcon = "ReplaceableTextures\\CommandButtons\\BTNMagicalSentry.blp"
set terI[1] = terI[1].create(ter, "Run and wait")
set terI[2] = terI[2].create(ter, "Kill the Terminator")
else
set ter.completed = true
call PlayCompletedSound()
endif
endmethod
static method lastEx takes integer instance returns nothing
set terI[instance].completed = true
endmethod
endstruct
endlibrary
//TESH.scrollpos=53
//TESH.alwaysfold=0
//Spell Name: FireBullet
//Made by Mckill2009
//===REQUIREMENTS:
//- Jass New Gen Pack (JNGP) by Vexorian
scope FireBullet initializer init
globals
//private constant integer BULLET_ID = 'h00I'
private constant string IMPACT_SFX = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl"
private constant real BULLET_SPEED = 70
private constant real AOE_AFFECT = 200
private constant attacktype ATK = ATTACK_TYPE_PIERCE
private constant damagetype DAM = DAMAGE_TYPE_NORMAL
endglobals
private struct DamageM
private unit caster
private real angle
private real distance
private real xT
private real yT
private real damage
private player pl
private method periodic takes nothing returns nothing
local unit first
if .distance > 0 then
set .distance = . distance - BULLET_SPEED
set .xT = .xT + BULLET_SPEED * Cos(.angle)
set .yT = .yT + BULLET_SPEED * Sin(.angle)
//call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", .xT, .yT))
call GroupEnumUnitsInRange(EnumG, .xT, .yT, AOE_AFFECT, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) and not (IsUnitType(first, UNIT_TYPE_FLYING) or GetOwningPlayer(first)==.pl) then
call UnitDamageTarget(.caster, first, GetRandomReal(1., .damage), false, false, ATK, DAM, null)
call DestroyEffect(AddSpecialEffectTarget(IMPACT_SFX, first, "chest"))
endif
call GroupRemoveUnit(EnumG, first)
endloop
else
set .caster = null
set .pl = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method run takes unit c, real x, real y, real d returns nothing
local thistype this = allocate()
set .caster = c
set .angle = GetUnitFacing(c) * bj_DEGTORAD
set .distance = 700.
set .xT = x
set .yT = y
set .damage = d
set .pl = GetOwningPlayer(c)
call .startPeriodic()
endmethod
endstruct
private function Fire takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit first
local integer id = GetHandleId(u)
local integer ammo = LoadInteger(udg_HASH, id, 100)
local item it
if LoadInteger(udg_HASH, id, 100)==0 then
call SimError(GetTriggerPlayer(), "You need to RELOAD!")
call UnitRemoveAbility(u, FIRE_GUN)
call UnitAddAbility(u, FIRE_GUN_PASSIVE)
call UnitRemoveAbility(u, RELOAD_PASSIVE)
call UnitAddAbility(u, RELOAD)
else
if ammo > 0 then
call SaveInteger(udg_HASH, id, 100, ammo - 1)
call DamageM.run(u, GetUnitX(u), GetUnitY(u), (GetUnitLevel(u) * 5.) * .2)
endif
endif
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(FIRE_GUN, function Fire)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Reload initializer init
globals
private constant integer MAGAZINE_CLIPS = 'I000'
private constant integer LOADED_BULLET = 'bull'
endglobals
private function Reload takes nothing returns nothing
local unit u = GetTriggerUnit()
local item it
if UnitHasItemType(u, MAGAZINE_CLIPS) then //bullets
set it = ItemTypeToItem(u, MAGAZINE_CLIPS)
if GetItemCharges(it) > 0 then
call SetItemCharges(it, GetItemCharges(it)-1)
call SaveInteger(udg_HASH, GetHandleId(u), 100, MAX_RELOAD)
call UnitRemoveAbility(u, FIRE_GUN_PASSIVE)
call UnitAddAbility(u, FIRE_GUN)
call UnitRemoveAbility(u, RELOAD)
call UnitAddAbility(u, RELOAD_PASSIVE)
else
call SimError(GetTriggerPlayer(), "You bullet stock is empty.")
endif
set it = null
else
call SimError(GetTriggerPlayer(), "You don't have bullets.")
endif
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(RELOAD, function Reload)
endfunction
endscope
//TESH.scrollpos=20
//TESH.alwaysfold=0
//Spell Name: Combat Knife
//Created by: Mckill2009
scope CombatKnife initializer init
globals
private constant integer SPELL_ID = 'A006'
private constant attacktype ATK = ATTACK_TYPE_PIERCE
private constant damagetype DMG = DAMAGE_TYPE_NORMAL
private constant string SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
private constant string ATTACHMENT = "chest"
private constant real AOE = 70
endglobals
private function GetDamageMin takes integer i returns real
return 1 + i * 2.
endfunction
//private function GetDamageMax takes integer i returns real
// return 3 + i * 9.
//endfunction
private function FilterUnits takes unit u returns boolean
return not (IsUnitType(u, UNIT_TYPE_MECHANICAL) or IsUnitType(u, UNIT_TYPE_ANCIENT) or /*
*/ IsUnitType(u, UNIT_TYPE_TOWNHALL) or IsUnitType(u, UNIT_TYPE_FLYING))
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local real facing = GetUnitFacing(u)*bj_DEGTORAD
local unit first
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x1 = x+90*Cos(facing)
local real y1 = y+90*Sin(facing)
local integer level = GetUnitAbilityLevel(u, SPELL_ID)
local real damage
call GroupEnumUnitsInRange(EnumG, x1, y1, AOE, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) and FilterUnits(first) and IsUnitEnemy(first, GetTriggerPlayer()) then
set damage = GetRandomReal(1., 5.)
call UnitDamageTarget(u, first, damage, false, false, ATK, DMG, null)
call DestroyEffect(AddSpecialEffectTarget(SFX, first, ATTACHMENT))
call SimTTUnit(I2S(R2I(damage)), first, 0, 0.025)
exitwhen true
endif
call GroupRemoveUnit(EnumG, first)
endloop
call IssueImmediateOrder(u, "stop")
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function Actions)
endfunction
endscope
//TESH.scrollpos=51
//TESH.alwaysfold=0
//Spell Name: FireBullet
//Made by Mckill2009
//===REQUIREMENTS:
//- Jass New Gen Pack (JNGP) by Vexorian
scope FireBullet initializer init
globals
//private constant integer BULLET_ID = 'h00I'
private constant string IMPACT_SFX = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl"
private constant real BULLET_SPEED = 70
private constant real AOE_AFFECT = 200
private constant attacktype ATK = ATTACK_TYPE_PIERCE
private constant damagetype DAM = DAMAGE_TYPE_NORMAL
endglobals
private struct DamageM
private unit caster
private real angle
private real distance
private real xT
private real yT
private real damage
private player pl
private method periodic takes nothing returns nothing
local unit first
if .distance > 0 then
set .distance = . distance - BULLET_SPEED
set .xT = .xT + BULLET_SPEED * Cos(.angle)
set .yT = .yT + BULLET_SPEED * Sin(.angle)
//call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", .xT, .yT))
call GroupEnumUnitsInRange(EnumG, .xT, .yT, AOE_AFFECT, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) and not (IsUnitType(first, UNIT_TYPE_FLYING) or GetOwningPlayer(first)==.pl) then
call UnitDamageTarget(.caster, first, GetRandomReal(1., .damage), false, false, ATK, DAM, null)
call DestroyEffect(AddSpecialEffectTarget(IMPACT_SFX, first, "chest"))
endif
call GroupRemoveUnit(EnumG, first)
endloop
else
set .caster = null
set .pl = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method run takes unit c, real x, real y, real d returns nothing
local thistype this = allocate()
set .caster = c
set .angle = GetUnitFacing(c) * bj_DEGTORAD
set .distance = 700.
set .xT = x
set .yT = y
set .damage = d
set .pl = GetOwningPlayer(c)
call .startPeriodic()
endmethod
endstruct
private function Fire takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit first
local integer id = GetHandleId(u)
local item it = ItemTypeToItem(u, BULLETS)
if GetItemCharges(it) > 0 then
call SetItemCharges(it, GetItemCharges(it)-1)
call DamageM.run(u, GetUnitX(u), GetUnitY(u), 5. * GetRandomReal(0.1, 0.7))
else
call SimError(GetTriggerPlayer(), "You need to RELOAD!")
call UnitRemoveAbility(u, FIRE_GUN)
call UnitAddAbility(u, FIRE_GUN_PASSIVE)
call UnitRemoveAbility(u, RELOAD_PASSIVE)
call UnitAddAbility(u, RELOAD)
endif
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(FIRE_GUN, function Fire)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Reload initializer init
globals
private constant integer MAGAZINE_CLIPS = 'I000'
private constant integer LOADED_BULLET = 'bull'
endglobals
private function Reload takes nothing returns nothing
local unit u = GetTriggerUnit()
local item it
if UnitHasItemType(u, MAGAZINE_CLIPS) then //bullets
set it = ItemTypeToItem(u, MAGAZINE_CLIPS)
if GetItemCharges(it) > 0 then
call SetItemCharges(it, GetItemCharges(it) - 1)
set it = ItemTypeToItem(u, BULLETS)
call SetItemCharges(it, MAX_RELOAD)
call SaveInteger(udg_HASH, GetHandleId(u), 100, MAX_RELOAD)
call UnitRemoveAbility(u, FIRE_GUN_PASSIVE)
call UnitAddAbility(u, FIRE_GUN)
call UnitRemoveAbility(u, RELOAD)
call UnitAddAbility(u, RELOAD_PASSIVE)
else
call SimError(GetTriggerPlayer(), "You dont have any magazine clips.")
endif
set it = null
else
call SimError(GetTriggerPlayer(), "You don't have bullets.")
endif
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(RELOAD, function Reload)
endfunction
endscope
//TESH.scrollpos=24
//TESH.alwaysfold=0
scope LandMine initializer init
globals
private constant integer SPELL_ID = 'A003'
private constant integer LAND_MINE_ID = 'n001'
private constant string SFX = "Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl"
endglobals
private function GetDamage takes integer i returns real
return 50 + i * 75.
endfunction
private struct Indexer
unit landmine
real damage
integer dur
static method create takes nothing returns thistype
return allocate()
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
endstruct
private function Looper takes nothing returns nothing
local timer t = GetExpiredTimer()
local Indexer hk = GetTimerData(t)
local real x = GetUnitX(hk.landmine)
local real y = GetUnitY(hk.landmine)
local unit first
if hk.dur==1 then
call GroupEnumUnitsInRange(EnumG, x, y, 200., null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) and not IsUnitType(first, UNIT_TYPE_FLYING) then
call UnitDamageTarget(hk.landmine, first, hk.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
endif
call GroupRemoveUnit(EnumG, first)
endloop
call DestroyTrees(x, y, 200)
call DestroyEffect(AddSpecialEffect(SFX, x, y))
call KillUnit(hk.landmine)
call ReleaseTimer(t)
call hk.destroy()
else
set hk.dur = hk.dur - 1
call SimTTLoc(I2S(hk.dur), x, y, 150, 0.025)
endif
set t = null
endfunction
private function Put takes nothing returns nothing
local Indexer lm
local item it
local unit u = GetTriggerUnit()
local unit landmine
local real x = GetUnitX(u)
local real y = GetUnitY(u)
if UnitHasItemType(u, 'I006') then
set it = ItemTypeToItem(u, 'I006')
if GetItemCharges(it) > 0 then
call SetItemCharges(it, GetItemCharges(it)-1)
call SetUnitAnimation(u, "spell")
set lm = Indexer.create()
set lm.landmine = CreateUnit(GetTriggerPlayer(), LAND_MINE_ID, x, y, 0)
set lm.damage = 100
set lm.dur = 6
call TimerStart(NewTimerEx(lm), 1.0, true, function Looper)
else
call SimError(GetTriggerPlayer(), "Land Mine stock is empty.")
endif
set it = null
else
call SimError(GetTriggerPlayer(), "You don't have Land Mines.")
endif
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function Put)
endfunction
endscope
//TESH.scrollpos=3
//TESH.alwaysfold=0
scope Grenade
globals
private constant real AOE = 200
private string sfx = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
endglobals
struct Grenade
unit grenade
real angle
real distance
real maxDist
method periodic takes nothing returns nothing
local unit first
local real x = GetUnitX(.grenade)
local real y = GetUnitY(.grenade)
if .distance > 0 then
set .distance = .distance - 10
call SetUnitPosition(.grenade, x + 10 * Cos(.angle), y + 10 * Sin(.angle))
call SetUnitFlyHeight(.grenade, GetParabolaZ(250, .maxDist, .distance)+75, 0)
else
call GroupEnumUnitsInRange(EnumG, x, y, AOE, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) then
call UnitDamageTarget(.grenade, first, 150, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
endif
call GroupRemoveUnit(EnumG, first)
endloop
call DestroyTrees(x, y, AOE)
call DestroyEffect(AddSpecialEffect(sfx, x, y))
call KillUnit(.grenade)
set .grenade = null
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method cast takes nothing returns nothing
local unit u = GetTriggerUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local thistype this
local item it
if UnitHasItemType(u, 'I002') then
set it = ItemTypeToItem(u, 'I002')
if GetItemCharges(it) > 0 then
call SetItemCharges(it, GetItemCharges(it)-1)
call SetUnitAnimation(u, "spell")
set this = allocate()
set .grenade = CreateUnit(GetTriggerPlayer(), 'o001', x, y, 0)
set .angle = Atan2(GetSpellTargetY()-y, GetSpellTargetX()-x)
set .distance = SquareRoot((GetSpellTargetX()-x)*(GetSpellTargetX()-x)+(GetSpellTargetY()-y)*(GetSpellTargetY()-y))
set .maxDist = .distance
call UnitAddAbility(.grenade, 'Arav')
call .startPeriodic()
else
call SimError(GetTriggerPlayer(), "Grenade stock is empty.")
endif
set it = null
else
call SimError(GetTriggerPlayer(), "You don't have grenades.")
endif
set u = null
endmethod
static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent('A007', function thistype.cast)
endmethod
endstruct
endscope
//TESH.scrollpos=8
//TESH.alwaysfold=0
//Spell Name: FireBullet
//Made by Mckill2009
//===REQUIREMENTS:
//- Jass New Gen Pack (JNGP) by Vexorian
scope XybotFire initializer init
globals
private constant integer SPELL_ID = 'A005'
private constant string IMPACT_SFX = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl"
private constant real AOE = 100
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DAM = DAMAGE_TYPE_DEATH
private constant boolean ENABLE_AOE_AFFECT = true
private unit FirstTarget
endglobals
private function Fire takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit first
call SetUnitAnimation(u, "attack")
call GroupEnumUnitsInRange(EnumG, GetSpellTargetX(), GetSpellTargetY(), AOE, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if (UnitAlive(first) and not IsUnitType(first, UNIT_TYPE_FLYING)) and IsUnitEnemy(first, GetTriggerPlayer()) or GetOwningPlayer(first)==Player(15) then
call UnitDamageTarget(u, first, 60, false, false, ATK, DAM, null)
call DestroyEffect(AddSpecialEffectTarget(IMPACT_SFX, first, "chest"))
set first = null
exitwhen true
endif
call GroupRemoveUnit(EnumG, first)
endloop
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function Fire)
endfunction
endscope
//TESH.scrollpos=66
//TESH.alwaysfold=0
scope ElectricCharge initializer init
globals
private constant integer SPELL_ID = 'A009'
private constant integer UNIT_ID = 'h00B'
private constant real OFFSET_FROM_CENTER = 175
private constant real THROW_HEIGHT = 400
private constant real SPEED = 10
private constant real AOE_DAMAGE = 175
private attacktype ATT = ATTACK_TYPE_CHAOS
private damagetype DAM = DAMAGE_TYPE_DEATH
/***************************************************************************
* Non-configurable block
****************************************************************************/
private unit array charge
private real array height
private real array unitHeight
private real array distance
private real array maxDistance
private real array angle
private real array offsets
private real array damage
private real array cos
private real array sin
private group enumG = CreateGroup()
//Dynamic indexing
private timer t
private integer index = 0
private integer array indexAR
endglobals
private struct EC extends array
implement Alloc
endstruct
private function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d) //Standard parabola
endfunction
/***************************************************************************
* End of non-configurable block
****************************************************************************/
private function ElectricCreatedCount takes integer level returns integer
return 6
endfunction
private function GetDamage takes integer level returns real
return 50.
endfunction
private function looper takes nothing returns nothing
local integer i = 0
local EC this
local unit first
loop
set i = i + 1
set this = indexAR[i]
if distance[this] > 0 then
set distance[this] = distance[this] - SPEED
call SetUnitX(charge[this], GetUnitX(charge[this])+SPEED*cos[this])
call SetUnitY(charge[this], GetUnitY(charge[this])+SPEED*sin[this])
call SetUnitFlyHeight(charge[this], GetParabolaZ(THROW_HEIGHT, maxDistance[this], distance[this]) + unitHeight[this] , 0)
else
call SetUnitFlyHeight(charge[this], GetUnitDefaultFlyHeight(charge[this]), 0)
call GroupEnumUnitsInRange(enumG, GetUnitX(charge[this]), GetUnitY(charge[this]), AOE_DAMAGE, null)
loop
set first = FirstOfGroup(enumG)
exitwhen first==null
if not IsUnitType(first, UNIT_TYPE_DEAD) and IsUnitEnemy(first, GetOwningPlayer(charge[this])) then
call UnitDamageTarget(charge[this], first, damage[this], false, false, ATT, DAM, null)
endif
call GroupRemoveUnit(enumG, first)
endloop
call KillUnit(charge[this])
set charge[this] = null
call this.deallocate()
set indexAR[i] = indexAR[index]
set index = index - 1
set i = i-1
if index==0 then
call PauseTimer(t)
call DestroyTimer(t)
endif
endif
exitwhen i==index
endloop
endfunction
private function onCast takes nothing returns nothing
local EC this
local unit u = GetTriggerUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real xU = GetUnitX(u)
local real yU = GetUnitY(u)
local real a
local real angles = 0
local real xRandom
local real yRandom
local integer level = GetUnitAbilityLevel(u, SPELL_ID)
local integer i = 0
local integer count = ElectricCreatedCount(level)
set a = (360 / count)*bj_DEGTORAD
loop
set this = EC.allocate()
set height[this] = THROW_HEIGHT
set unitHeight[this] = GetUnitFlyHeight(u)+100
set xRandom = x+OFFSET_FROM_CENTER*Cos(angles)
set yRandom = y+OFFSET_FROM_CENTER*Sin(angles)
set angle[this] = Atan2(yRandom-yU, xRandom-xU)
set maxDistance[this] = SquareRoot((xRandom-xU)*(xRandom-xU)+(yRandom-yU)*(yRandom-yU))
set distance[this] = maxDistance[this]
set damage[this] = GetDamage(level)
set charge[this] = CreateUnit(GetTriggerPlayer(), UNIT_ID, xU, yU, 0)
set cos[this] = Cos(angle[this])
set sin[this] = Sin(angle[this])
set angles = angles + a
call UnitAddAbility(charge[this], 'Arav')
if index==0 then
set t = CreateTimer()
call TimerStart(t, 0.03125, true, function looper)
endif
set index = index + 1
set indexAR[index] = this
set i = i + 1
exitwhen i==count
endloop
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function onCast)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BallisticMissileT initializer init
private function Cast takes nothing returns boolean
local unit u = GetTriggerUnit()
local string model = "Abilities\\Weapons\\CannonTowerMissile\\CannonTowerMissile.mdl"
local string explode = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
local BallisticMissile bm
set bm = bm.create(GetTriggerPlayer(), model, GetSpellTargetUnit(), GetUnitX(u), GetUnitY(u), GetUnitFacing(u))
call bm.setup(200, 500, 150, 2, 15)
call bm.setupDamageTypes(ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEATH)
call bm.setupTargets(false, true)
call bm.launch(explode)
set u = null
return false
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent('A004', function Cast)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TrampleGround uses T32
globals
private constant integer SPELL_ID = 'A008'
private constant string SFX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant real AOE = 125
private constant real BASE_DAMAGE = 50
private constant real GAP = 100
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DAM = DAMAGE_TYPE_DEATH
endglobals
private function GetDamage takes integer level returns real
return BASE_DAMAGE + level * 50.
endfunction
private struct TR
unit hero
real casterX
real casterY
real spellX
real spellY
real angle
real distance
real distx
real damage
private method periodic takes nothing returns nothing
local unit first
local real x
local real y
if .distance > .distx then
set .distx = .distx + GAP
set x = .casterX+.distx*Cos(.angle)
set y = .casterY+.distx*Sin(.angle)
call DestroyEffect(AddSpecialEffect(SFX, x, y))
call GroupEnumUnitsInRange(EnumG, x, y, AOE, null)
loop
set first = FirstOfGroup(EnumG)
exitwhen first==null
if UnitAlive(first) and not IsUnitType(first, UNIT_TYPE_FLYING) and first != .hero then
call UnitDamageTarget(.hero, first, .damage, false, false, ATK, DAM, null)
endif
call GroupRemoveUnit(EnumG, first)
endloop
else
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method onCast takes nothing returns nothing
local TR this = TR.allocate()
local real dx
local real dy
local integer level
set .hero = GetTriggerUnit()
set level = GetUnitAbilityLevel(.hero, SPELL_ID)
set .casterX = GetUnitX(.hero)
set .casterY = GetUnitY(.hero)
set .spellX = GetSpellTargetX()
set .spellY = GetSpellTargetY()
set .damage = GetDamage(level)
set .angle = Atan2(.spellY-.casterY, .spellX-.casterX)
set .distx = 0
set dx = .spellX - .casterX
set dy = .spellY - .casterY
set .distance = SquareRoot(dx*dx+dy*dy)
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary