//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
constant string GAME_VERSION = "The March v1.1"
constant integer STOP = 851972
constant integer MOVE = 851986
constant integer ATTACK = 851983
constant integer SMART = 851971
constant integer CENTAUR_ARMY_LIMIT = 10 //10, per wave
constant integer CENTAUR_ARMY_MAX = 18 //18
//8, used by CinematicFurbolgPickQuest(minus 3) and CenematicCentaurQuest
constant integer ARRIVED_REINFORCEMENTS = 7 //7, count
constant real CENTAUR_SURVIVE_TIMER = 600 //600, 10 minutes
//20, normal mode, ItemSetCreation
integer ITEM_DROP_CHANCE = 20
/**************************************
/ Used by CaravanMovement
***************************************/
//FALSE, caravan goes to end without condition
constant boolean CARAVAN_ROUTE_TEST = false
//TRUE, caravan and Lyric has escorts
constant boolean ENABLE_CARAVAN_ESCORTS = true
//800, if unit detects enemies it will not move
constant real NO_ENEMY_AOE = 800
constant group TempG = CreateGroup()
//FALSE, used only to cinematics
//boolean CARAVAN_MOVE = true
integer CAR_CHECKPOINT = 1 //1
player TempP = null
/**************************************
/ MISC
***************************************/
constant timer CentaurT = CreateTimer()
//player 12 in GUI
constant player ENEMY = Player(11)
timerdialog CentaurTD
integer furbolgArrives = 0
/**************************************
/ TEST VARIABLES
***************************************/
constant integer ALLY_TYPE = 'hfoo'
constant integer ENEMY_TYPE = 'ogru'
//FALSE, creates enemies at start, enables testing
constant boolean TEST_ENEMY = false
//FALSE, creates allies to control
constant boolean CREATE_ALLIES = false
integer countTest = 0
endglobals
function SetupUnitIDs takes nothing returns nothing
set udg_CentaurL2Type[1] = 'ncea'
set udg_CentaurL2Type[2] = 'ncer'
set udg_CentaurL4Type[1] = 'ncen'
set udg_CentaurL4Type[2] = 'ncim'
endfunction
//from CinematicCentaurQuest if Centaur Khan is alive
function CavalryArrives takes integer qty returns nothing
local integer i = 0
local unit u
loop
set u = CreateUnit(Player(0), 'hkni', 6870, -1200, 0)
call IssuePointOrderById(u, MOVE, 6580, 2280)
set i = i+1
exitwhen i==qty
endloop
set u = null
endfunction
function ChangeNow takes nothing returns nothing
call SetUnitOwner(GetEnumUnit(), TempP, false)
endfunction
function GroupChangeOwner takes group g, player p returns nothing
set TempP = p
call ForGroup(g, function ChangeNow)
endfunction
/*******************************************
/ Furbolg Younglings Out Cave
********************************************/
function FurbolgYounglingsOutCaveEx takes nothing returns nothing
local unit fur = CreateUnit(Player(2), 'n001', -1500, 4960, 267)
call RemoveGuardPosition(fur)
call GroupAddUnit(udg_FurbolgGroup, fur)
set furbolgArrives = furbolgArrives + 1
if furbolgArrives == 10 then
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endif
call IssuePointOrderById(fur, MOVE, 9290, 110)
set fur = null
endfunction
function FurbolgYounglingsOutCave takes nothing returns nothing
call TimerStart(CreateTimer(), 1.0, true, function FurbolgYounglingsOutCaveEx)
endfunction
/*******************************************
/ Centaur Attack Delay
********************************************/
function CentaurEngage takes nothing returns nothing
call EngageSingle(GetEnumUnit(), udg_Caravan)
endfunction
function CentaurAttackDelayEx takes nothing returns nothing
call ForGroup(udg_CentaurGroup, function CentaurEngage)
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endfunction
function CentaurAttackDelay takes nothing returns nothing
call TimerStart(CreateTimer(), 5, false, function CentaurAttackDelayEx)
endfunction
Name | Type | is_array | initial_value |
Ambiance | sound | No | |
AttackingEnemies | group | No | |
AW | integervar | No | |
AW_Angle | real | Yes | |
AW_AT_REA_Debug | integer | Yes | |
AW_AttractionSpeed_ReactionS_P | real | Yes | |
AW_AXES_Howmuch | integer | No | |
AW_Caster | unit | Yes | |
AW_Damage | boolean | Yes | |
AW_Damage_Time | integer | Yes | |
AW_DamageDone | real | Yes | |
AW_Debug_Distance_Border | real | Yes | |
AW_Distance_Attract_React | real | Yes | |
AW_Dummy | unit | Yes | |
AW_Duration_Effect | integer | No | |
AW_ExpirationTime | integer | Yes | |
AW_FallingSpeed | real | Yes | |
AW_Group | group | Yes | |
AW_Height | real | Yes | |
AW_Level | integer | No | |
AW_Off | boolean | Yes | |
AW_Point | location | Yes | |
AW_Real_Damage_Time_Caa | integer | Yes | |
AW_Real_Decoy_Formulas | real | Yes | |
AW_Skip | integer | No | |
AW_SpecialEffect1 | effect | Yes | |
AW_SpecialEffect2 | effect | Yes | |
AW_SpinSpeed | real | Yes | |
AW_StepLast | integer | Yes | |
AW_Steps | integer | Yes | |
AW_Times | integer | No | |
BanditGroup | group | No | |
Batushk | unit | No | |
CampaignFurbolgHelp | integer | No | |
Caravan | unit | No | |
CaravanMoving | boolean | No | |
CE_Ability_Level | integer | No | |
CE_Area_of_Effect | real | No | |
CE_Base_Damage | real | No | |
CE_Caster | unit | No | |
CE_Damage_Group | group | No | |
CE_Destroy_Trees | boolean | No | |
CE_Knock_Angle | real | No | |
CE_Knock_Distance | real | No | |
CE_Knock_Group | group | No | |
CE_Knock_Loc1 | location | No | |
CE_Knock_Loc2 | location | No | |
CE_Knock_Speed | real | No | |
CE_Knocktable | hashtable | No | |
CE_Location | location | No | |
CE_Location2 | location | No | |
CE_Pathing_On | boolean | No | |
CE_Special_Effect | effect | No | |
CE_Special_Effect1 | effect | No | |
CE_Total_Damage | real | No | |
CentaurAdded | boolean | No | true |
CentaurArmyLimit | integer | No | |
CentaurCount | integer | No | |
CentaurGroup | group | No | |
CentaurL2Type | unitcode | Yes | |
CentaurL4Type | integer | Yes | |
CentaurPickAttack | boolean | No | |
CentaurSurvive | timer | No | |
CentaurSurviveTimer | real | No | |
CentaurSurviveWindow | timerdialog | No | |
CentaurSuviveEnable | boolean | No | true |
Clawgrek | unit | No | |
Difficulty | integer | No | |
Dummy | unit | No | |
Emek | unit | No | |
ENEMY_PLAYER | player | No | |
ES_Ability_Level | integer | No | |
ES_Atribute_Damage | integer | No | |
ES_Atribute_Damage_Calculation | real | No | |
ES_Atribute_Factor | real | No | |
ES_Base_Damage | real | No | |
ES_Caster | unit | No | |
ES_Caster_Life | real | No | |
ES_Damage_Calculation | real | No | |
ES_Dummy_Ability_Slow | abilcode | No | |
ES_Dummy_Ability_Stun | abilcode | No | |
ES_Facing_Angle | real | No | |
ES_Level_Damage | real | No | |
ES_Owner | player | No | |
ES_SFX_Angle | real | No | |
ES_SFX_Duration | real | No | |
ES_SFX_Loc | location | No | |
ES_SFX_Loc_2 | location | No | |
ES_SFX_Loc_3 | location | No | |
ES_SFX_Loc_4 | location | No | |
ES_SFX_Offset | real | No | |
ES_SFX_Offset_Calculation | real | No | |
ES_SFX_Value | real | No | |
ES_SFX_Value_1 | real | No | |
ES_SFX_Value_2 | real | No | |
ES_SFX_Value_3 | real | No | |
ES_Spell_Loc | location | No | |
ES_Spell_Loc_2 | location | No | |
ES_Target | unit | No | |
ES_Target_Life | real | No | |
ES_Total_Damage | real | No | |
F_Integers | integer | Yes | |
F_ReachedFading | real | Yes | |
F_RFS_Caster | unit | Yes | |
F_RFS_MaxDamage | real | Yes | |
F_SetFadeValue | boolean | Yes | |
F_Time | real | Yes | |
F_Unit | unit | Yes | |
FogChangeSpeed | real | No | |
FogDown | boolean | No | |
FogSet | real | No | |
Footman | unit | Yes | |
FurbolgGroup | group | No | |
GameLevelDisplay | string | No | |
HarpyGroup | group | No | |
HASH | hashtable | No | |
hero | unit | No | |
Kalifas | unit | No | |
Knight | unit | Yes | |
LC_Cloud | unit | No | |
LC_Group | group | No | |
LC_Index | integer | No | |
LC_TargetGrp | group | No | |
LC_Timer | timer | No | |
Loc | location | No | |
Lyric | unit | No | |
P01Group | group | No | |
P02Group | group | No | |
QuestStatus | integer | No | |
RF_AoE | real | No | |
RF_DamagePoint | location | No | |
RF_DamageTrees | boolean | No | |
RF_FallingTime | real | No | |
RF_MaxDamagePerRock | real | No | |
RF_MinDamagePerRock | real | No | |
RF_RockfallSequenceTimer | real | No | |
RF_RocksPerLevel | integer | No | |
RF_SineReals | real | Yes | |
RF_UnitGroup | group | No | |
RFA_Angle | real | Yes | |
RFA_Caster | unit | Yes | |
RFA_Distances | real | Yes | |
RFA_Group | group | No | |
RFA_HighSettings | real | Yes | |
RFA_Integers | integer | Yes | |
RFA_JumpHigh | real | Yes | |
RFA_MaxDmg | real | Yes | |
RFA_ReachedDistance | real | Yes | |
RFA_RealTimer | real | Yes | |
RFA_SpeedUnits | real | Yes | |
RFA_TempPoint | location | Yes | |
RFA_Unit | unit | Yes | |
RFAA_JumpHigh_Distance | real | No | |
RFAA_Speed | real | No | |
RFAA_TargetPoint | location | No | |
RFAA_Unit | unit | No | |
RFS_Caster | unit | Yes | |
RFS_Conjuring | boolean | Yes | |
RFS_ConjurPoint | location | No | |
RFS_DummyIntegers | integer | Yes | |
RFS_MaxDamage | real | Yes | |
RFS_NumberConjured | integer | Yes | |
RFS_NumberOfRocks | integer | Yes | |
RFS_Reals | real | Yes | |
RFS_TempPoint | location | Yes | |
RFS_Timer | real | Yes | |
RFSine_Caster | unit | Yes | |
RFSine_Integers | integer | Yes | |
RFSine_MaxDamage | real | Yes | |
RFSine_Unit | unit | Yes | |
Salg | unit | No | |
SkipCinematics | boolean | No | |
TempU | unit | No | |
Uruzapoth | unit | No | |
WeatherEffect | weathereffect | No | |
Zekaon | unit | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
[COLOR="Lime"][SIZE="5"][B]The March v1.1[/B][/SIZE][/COLOR]
[COLOR="Wheat"][SIZE="4"][B][/B]by mckill2009[/SIZE][/COLOR]
[simpletable=Game Info]
[COLOR="YellowGreen"]
This is a teaser map for my upcoming campaign [url=http://www.hiveworkshop.com/forums/map-development-202/shattered-kingdoms-campaign-175561/]Shattered Kingdoms[/url]
Lyric, prince of Ephra has been charged by his father, king Herald to bring gifts of precious treasures for King Agbon. It’s up to you to control Prince Lyric and guard the caravan along the way.[/COLOR]
[/simpletable]
[simpletable=Features]
[COLOR="YellowGreen"]
- Semi-sandbox game, pick your quest based on dialog box choice
- 2 difficulty setting
- AI escorts, bosses and mini bosses
- Custom abilities with lots of eye candy
- Defense choice, kill the boss and gain lots of experience (levelup)
- Offense choice, kill a boss so that you may help the other boss (no level up)
- Decent cinematics
[/color]
[/simpletable]
[simpletable=Screenshots and Videos]
[hidden=Screenshots]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92068.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92069.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92071.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92070.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92072.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92073.jpg[/IMG]
[IMG]http://www.hiveworkshop.com/forums/members/167625-albums4826-picture92074.jpg[/IMG]
[/hidden]
[box=Boss Fight Videos]
[COLOR="YellowGreen"]Currently there are 4 bosses in the game in which you may optionally fight except for the last boss.[/color]
[youtube=]https://www.youtube.com/watch?v=2RbULmhwzaE&index=2&list=UUig-6-Xp6bR8IZcEcVNpfeQ[/youtube]
[youtube=]https://www.youtube.com/watch?v=u4miDwe3R3U&list=UUig-6-Xp6bR8IZcEcVNpfeQ[/youtube]
[/box]
[/simpletable]
[simpletable=Credits]
[COLOR="Olive"][SIZE="4"][B]TERRAIN:[/B][/SIZE][/COLOR]
mckill2009, edited by MasterTrainer
[COLOR="Olive"][SIZE="4"][B]SPELLS:[/B][/SIZE][/COLOR]
Mana Orb by Malhorne
Touch of Light by The_Witcher
Spectrum Shower by iAyanami
Dark Lightning Nova by msongyyy
Death Carrier by Moyack
Equilibrium Strike by -Berz-
Axes of Wonders by RMX
Multi Shock by Septimus
Cutting Edge by -Berz-
Haunt by Ciebron
Rockfall by Paladon
Landslide by Xiliger
[COLOR="Olive"][SIZE="4"][B]SYSTEMS:[/B][/SIZE][/COLOR]
Vexorian, Bribe, Magtheridon96, Spinnaker, Rising_Dusk, Jesus4lyf, Earth-Fury, Almia
[COLOR="Olive"][SIZE="4"][B]MODELS:[/B][/SIZE][/COLOR]
JetFangInferno for the DarkLightningNova and DarkLightning Models
[/simpletable]
[simpletable=Changelogs]
[hidden=]
v1.1
- Added Weather conditions, this makes the game more challenging
- Added mini boss which makes this more diffucult
- Caravan stop route fixed
[/hidden]
[/simpletable]
//TESH.scrollpos=106
//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=30
//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 WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
* readonly static integer centerX
* readonly static integer centerY
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=R2I(GetRectMaxX(world))
set maxY=R2I(GetRectMaxY(world))
set minX=R2I(GetRectMinX(world))
set minY=R2I(GetRectMinY(world))
set centerX=R2I((maxX+minX)/2)
set centerY=R2I((minY+maxY)/2)
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=90
//TESH.alwaysfold=0
library DamageEvent/* v 1.2.0.0
**********************************************************************************
*
* Physical Damage Detection Engine
* --------------------------------
* By looking_for_help aka eey
*
* This system is able to detect, modify and deal damage. It can differentiate
* between physical and spell damage, as well as block, reduce or increase the
* applied damage to a desired value. You can also allocate damage events from
* running damage events.
*
**********************************************************************************
*
* Implementation
* --------------
* 1. Copy this trigger to your map. With the AddDamageHandler function you can
* add as many handlers as you like (compare the OnDamage scope).
* 2. Copy the two custom abilities to your map and make sure they have the
* correct ID in the globals variable block.
* 3. Go to the locust swarm ability and invert its damage return portion
* from (default) 0.75 to -0.75.
* 4. Remove the spell damage reduction ability from the spell damage reduction
* items you use (runed bracers). You can configure the resistance of this
* item in the globals block, modifying BRACERS_SPELL_DAMAGE_REDUCTION.
*
**********************************************************************************
*
* Important Notes
* ---------------
* 1. Life Drain does not work with this system, so you should use a triggered
* version of this spell if you want to use it.
* 2. Same for Finger of Death, if you want to use this spell bug free with this
* system, you should use a triggered version of it.
* 3. If you use damage modifiers by setting the damage amount variable, you have
* to use GetUnitLife, GetUnitMaxLife and SetUnitLife instead of GetWidgetLife,
* GetUnitState for UNIT_STATE_MAX_LIFE and SetWidgetLife in your whole map to
* ensure there occure no bugs.
* 4. The boolean USE_SPELL_RESISTANCE_AUTO_DETECT is only neccessary set to true
* if you want to use a customized damage table with spell damage resistance
* above 100%. If this is not the case, it should be set to false, as the
* system is faster then and still works correct.
* 5. As already mentioned you can't use the spell reduction ability when using this
* system (runed bracers and elunes grace). If you want to use them, you can
* trigger them by using the damage modifiers. Runed bracers is already considered
* in this system, so you don't have to code it.
*
**********************************************************************************
*
* System API
* ----------
* unit PDDS.target
* - In this global unit variable, the damaged unit is saved. Don't write any-
* thing into this variable, use it as readonly.
*
* unit PDDS.source
* - In this global unit variable, the damage source is saved. Don't write any-
* thing into this variable, use it as readonly.
*
* real PDDS.amount
* - In this global real variable, the amount of damage is saved. This amount
* can be modified by simply setting it to the desired amount that should be
* applied to the target. Set the amount to 0.0 to block the damage completly.
* Negative values will result in heal.
*
* integer PDDS.damageType
* - In this global integer variable, the damage type of the current damage is
* saved. Use it to differentiate between physical, spell and code damage. The
* variable can takes the values PHYSICAL == 0, SPELL == 1 and CODE == 2. Don't
* write anything into this variable, use it as readonly.
*
* function UnitDamageTargetEx takes unit localSource, unit localTarget, real localAmount,
* boolean attack, boolean ranged, attacktype localAttackType,
* damagetype localDamageType, weapontype localWeaponType
* returns boolean
* - Use this function to allocate attacks from a running damage event. You can use
* it in exactly the same way as the standard native UnitDamageTarget. The function
* is designed recursive, so you can allocate as many attacks as you want. Do not
* use this function outside of a damage event.
*
* function GetUnitLife takes unit u returns real
* - Use this function instead of the GetWidgetLife native. It ensures that you
* get the correct health value, even when damage modifiers are applied. If
* you don't use damage modifiers at all, you don't need this function.
*
* function GetUnitMaxLife takes unit u returns real
* - Use this function instead of the GetUnitState(u, UNIT_STATE_MAX_LIFE) native.
* It will return the correct value, even when damage modifiers are applied. If
* you don't use damage modifiers at all, you don't need this function.
*
* function SetUnitLife takes unit u, real newLife returns nothing
* - Use this function instead of the SetWidgetLife(u, newLife) native if you use
* damage modifiers in your map. Same rules as for the GetUnitMaxLife and the
* GetUnitMaxLife functions.
*
* function AddDamageHandler takes code damageHandler returns nothing
* - Allows you to add a damage handler function to the system. Compare the
* OnDamage scope for an example usage.
*
* function RemoveDamageHandler takes code damageHandler returns nothing
* - Allows you to remove a damage handler function from the system dynamic-
* ally. If you added the same handler function multiple times to the sys-
* tem, this function will remove all of these equal functions.
*
*********************************************************************************/
globals
/*************************************************************************
* Customizable globals
*************************************************************************/
private constant integer DAMAGE_TYPE_DETECTOR = 0
private constant integer SET_MAX_LIFE = 0
private constant integer SPELL_DAMAGE_REDUCTION_ITEM = 'brac'
private constant boolean USE_SPELL_RESISTANCE_AUTO_DETECT = false
private constant real ETHEREAL_DAMAGE_FACTOR = 1.66
private constant real BRACERS_SPELL_DAMAGE_REDUCTION = 0.33
private constant real TRIGGER_CLEANUP_PERIOD = 60.0
/*************************************************************************
* End of Customizable globals
*************************************************************************/
constant integer PHYSICAL = 0
constant integer SPELL = 1
constant integer CODE = 2
constant real UNIT_MIN_LIFE = 0.406
private constant attacktype ATTACK_TYPE_UNIVERSAL = ConvertAttackType(7)
private hashtable h
private real pureAmount
private trigger damageEvent
private trigger damageHandler
private trigger runAllocatedAttacks
private integer allocatedAttacks
private integer totalAllocs
private integer allocCounter
private real damageEventTrigger
endglobals
struct PDDS extends array
static unit source
static unit target
static real amount
static integer damageType
endstruct
/******************************************************************************
* User functions
******************************************************************************/
function AddDamageHandler takes code func returns nothing
local integer id = GetHandleId(Condition(func))
local integer index = 0
// Loop to manage equal damage handlers
loop
exitwhen ( LoadTriggerConditionHandle(h, id, index) == null )
set index = index + 1
endloop
// Store the desired damage handler function
call SaveTriggerConditionHandle(h, id, index, TriggerAddCondition(damageHandler, Filter(func)))
endfunction
function RemoveDamageHandler takes code func returns nothing
local integer id = GetHandleId(Condition(func))
local integer index = 0
// Loop through all equal damage handlers
loop
exitwhen ( LoadTriggerConditionHandle(h, id, index) == null )
call TriggerRemoveCondition(damageHandler, LoadTriggerConditionHandle(h, id, index))
set index = index + 1
endloop
// Clean things up
call FlushChildHashtable(h, id)
endfunction
function GetUnitLife takes unit u returns real
local boolean duringModification
local integer uId = GetHandleId(u)
local real health
local real storedHealth = LoadReal(h, uId, 2)
local real storedDamage = LoadReal(h, uId, 1)
// Check if the unit is being rescued from damage
set duringModification = GetUnitAbilityLevel(u, SET_MAX_LIFE) > 0
if duringModification then
call UnitRemoveAbility(u, SET_MAX_LIFE)
endif
// Get the correct health value of the unit
if storedHealth != 0.0 then
set health = storedHealth - storedDamage
else
set health = GetWidgetLife(u) - storedDamage
endif
// Restore the rescue ability and return
if duringModification then
call UnitAddAbility(u, SET_MAX_LIFE)
endif
return health
endfunction
function GetUnitMaxLife takes unit u returns real
local real maxHealth
// Check if the unit is being rescued from damage
if GetUnitAbilityLevel(u, SET_MAX_LIFE) > 0 then
call UnitRemoveAbility(u, SET_MAX_LIFE)
set maxHealth = GetUnitState(u, UNIT_STATE_MAX_LIFE)
call UnitAddAbility(u, SET_MAX_LIFE)
return maxHealth
endif
// If the unit isn't being rescued, use the standard native
return GetUnitState(u, UNIT_STATE_MAX_LIFE)
endfunction
function SetUnitLife takes unit u, real newLife returns nothing
local integer targetId
local integer oldTimerId
local real oldHealth
// Check if the unit is being rescued from damage
if GetUnitAbilityLevel(u, SET_MAX_LIFE) > 0 then
call UnitRemoveAbility(u, SET_MAX_LIFE)
call SetWidgetLife(u, newLife)
call UnitAddAbility(u, SET_MAX_LIFE)
// Get the unit specific timer information
set targetId = GetHandleId(u)
set oldHealth = LoadReal(h, targetId, 0)
// Update the unit specific timer information
if oldHealth != 0.0 then
set oldTimerId = LoadInteger(h, targetId, 3)
call SaveReal(h, targetId, 2, newLife)
call SaveReal(h, targetId, 0, newLife)
call SaveReal(h, oldTimerId, 4, newLife)
endif
return
endif
// If the unit isn't being rescued, use the standard native
call SetWidgetLife(u, newLife)
endfunction
function UnitDamageTargetEx takes unit localSource, unit localTarget, real localAmount, boolean attack, /*
*/boolean ranged, attacktype localAttackType, damagetype localDamageType, /*
*/weapontype localWeaponType returns boolean
// Avoid infinite loop due to recursion
if PDDS.damageType == CODE then
return false
endif
// Avoid allocating attacks on units that are about to be killed
if ( localTarget == PDDS.target and GetUnitLife(localTarget) - PDDS.amount < UNIT_MIN_LIFE ) then
return false
endif
// Store all damage parameters determined by the user
set allocatedAttacks = allocatedAttacks + 1
call SaveUnitHandle(h, allocatedAttacks, 0, localSource)
call SaveUnitHandle(h, allocatedAttacks, 1, localTarget)
call SaveReal(h, allocatedAttacks, 2, localAmount)
call SaveBoolean(h, allocatedAttacks, 3, attack)
call SaveBoolean(h, allocatedAttacks, 4, ranged)
call SaveInteger(h, allocatedAttacks, 5, GetHandleId(localAttackType))
call SaveInteger(h, allocatedAttacks, 6, GetHandleId(localDamageType))
call SaveInteger(h, allocatedAttacks, 7, GetHandleId(localWeaponType))
// Return true if the damage was allocated
return true
endfunction
/******************************************************************************
* Sub functions
******************************************************************************/
private function DealFixDamage takes unit source, unit target, real pureAmount returns nothing
local real MAX_DAMAGE = 1000000.0
local real beforeHitpoints
local real newHitpoints
// Ensure the amount is positive
if pureAmount < 0 then
set pureAmount = -pureAmount
endif
// Save the targets hitpoints
set beforeHitpoints = GetWidgetLife(target)
set newHitpoints = beforeHitpoints - pureAmount
// Apply the desired, fixed amount
if newHitpoints >= UNIT_MIN_LIFE then
call SetUnitState(target, UNIT_STATE_LIFE, newHitpoints)
else
if ( IsUnitType(target, UNIT_TYPE_ETHEREAL) == false ) then
call SetWidgetLife(target, 1.0)
call UnitDamageTarget(source, target, MAX_DAMAGE, true, false, ATTACK_TYPE_UNIVERSAL, DAMAGE_TYPE_UNIVERSAL, null)
else
call UnitRemoveAbility(target, DAMAGE_TYPE_DETECTOR)
call SetWidgetLife(target, 1.0)
call UnitDamageTarget(source, target, MAX_DAMAGE, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
endif
endif
endfunction
private function GetUnitSpellResistance takes unit u returns real
local real originalHP
local real beforeHP
local real afterHP
local real resistance
local real DUMMY_DAMAGE = 100
local real DUMMY_FACTOR = 0.01
// Deal spell damage in order to get the units resistance
call UnitRemoveAbility(u, DAMAGE_TYPE_DETECTOR)
set originalHP = GetWidgetLife(u)
call UnitAddAbility(u, SET_MAX_LIFE)
call SetWidgetLife(u, 20000.0)
set beforeHP = GetWidgetLife(u)
call DisableTrigger(damageEvent)
call UnitDamageTarget(PDDS.source, u, DUMMY_DAMAGE, true, false, null, DAMAGE_TYPE_UNIVERSAL, null)
call EnableTrigger(damageEvent)
set afterHP = GetWidgetLife(u)
call UnitRemoveAbility(u, SET_MAX_LIFE)
call SetWidgetLife(u, originalHP)
call UnitAddAbility(u, DAMAGE_TYPE_DETECTOR)
call UnitMakeAbilityPermanent(u, true, DAMAGE_TYPE_DETECTOR)
// Calculate this resistance
set resistance = DUMMY_FACTOR*(beforeHP - afterHP)
// If the resistance was greater than 100%, return it
if resistance > 1.0 then
return resistance
else
return 1.0
endif
endfunction
private function UnitHasItemOfType takes unit u, integer itemId returns integer
local integer index = 0
local item indexItem
// Check if the target has a spell damage reducing item
loop
set indexItem = UnitItemInSlot(u, index)
if ( indexItem != null ) and ( GetItemTypeId(indexItem) == itemId ) then
return index + 1
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
return 0
endfunction
/******************************************************************************
* Damage Engine
******************************************************************************/
private function AfterDamage takes nothing returns nothing
local timer time = GetExpiredTimer()
local integer id = GetHandleId(time)
local unit localSource = LoadUnitHandle(h, id, 0)
local unit localTarget = LoadUnitHandle(h, id, 1)
local real amount = LoadReal(h, id, 3)
local real originalHealth = LoadReal(h, id, 4)
// If the damage was modified, restore units health
if originalHealth != 0.0 then
call UnitRemoveAbility(localTarget, SET_MAX_LIFE)
call SetWidgetLife(localTarget, originalHealth)
endif
// Apply the desired amount of damage
if amount > 0.0 then
call DisableTrigger(damageEvent)
call DealFixDamage(localSource, localTarget, amount)
call EnableTrigger(damageEvent)
else
call SetWidgetLife(localTarget, originalHealth - amount)
endif
// Clean things up
call FlushChildHashtable(h, id)
call FlushChildHashtable(h, GetHandleId(localTarget))
call DestroyTimer(time)
set time = null
set localSource = null
set localTarget = null
endfunction
private function DamageEngine takes nothing returns nothing
local timer time
local integer id
local real rawAmount
local real originalHealth
local integer targetId
local integer oldTimerId
local real oldHealth
local real oldOriginalHealth
local real oldAmount
// Set damage variables
set rawAmount = GetEventDamage()
if rawAmount == 0.0 then
return
endif
set PDDS.source = GetEventDamageSource()
set PDDS.target = GetTriggerUnit()
// Determine the damage type
if rawAmount > 0.0 then
if PDDS.damageType != CODE then
set PDDS.damageType = PHYSICAL
endif
set PDDS.amount = rawAmount
else
if PDDS.damageType != CODE then
set PDDS.damageType = SPELL
endif
set PDDS.amount = -rawAmount
endif
// Register spell reduction above 100%
static if USE_SPELL_RESISTANCE_AUTO_DETECT then
set PDDS.amount = GetUnitSpellResistance(PDDS.target)*PDDS.amount
else
if ( IsUnitType(PDDS.target, UNIT_TYPE_ETHEREAL) and IsUnitEnemy(PDDS.target, GetOwningPlayer(PDDS.source)) and rawAmount < 0.0 ) then
set PDDS.amount = ETHEREAL_DAMAGE_FACTOR*PDDS.amount
endif
endif
// Register spell damage reducing items like runed bracers
if ( IsUnitType(PDDS.target, UNIT_TYPE_HERO) and UnitHasItemOfType(PDDS.target, SPELL_DAMAGE_REDUCTION_ITEM) > 0 ) and rawAmount < 0.0 then
set PDDS.amount = (1 - BRACERS_SPELL_DAMAGE_REDUCTION)*PDDS.amount
endif
// Save health and damage variables
if PDDS.damageType != CODE then
call UnitRemoveAbility(PDDS.target, SET_MAX_LIFE)
endif
set pureAmount = PDDS.amount
set originalHealth = GetWidgetLife(PDDS.target)
set oldTimerId = 0
// Call damage handlers
set damageEventTrigger = 1.0
set damageEventTrigger = 0.0
// If the damage was modified, apply the rescue ability
if PDDS.amount != pureAmount then
call UnitAddAbility(PDDS.target, SET_MAX_LIFE)
call SetWidgetLife(PDDS.target, GetWidgetLife(PDDS.target) + pureAmount)
endif
// Check if a previous timer didn't yet expire
set targetId = GetHandleId(PDDS.target)
set oldHealth = LoadReal(h, targetId, 0)
// If this is the case, update the timer information
if oldHealth != 0.0 then
set oldTimerId = LoadInteger(h, targetId, 3)
set oldOriginalHealth = LoadReal(h, targetId, 2)
set oldAmount = LoadReal(h, targetId, 1)
set originalHealth = oldOriginalHealth - oldAmount
call SaveReal(h, oldTimerId, 4, oldOriginalHealth)
endif
// Call after damage event if damage was spell, modified, code or parallel
if ( rawAmount < 0.0 or pureAmount != PDDS.amount or oldTimerId != 0 or allocatedAttacks > 0 ) then
set time = CreateTimer()
set id = GetHandleId(time)
// Save handles for after damage event
call SaveUnitHandle(h, id, 0, PDDS.source)
call SaveUnitHandle(h, id, 1, PDDS.target)
call SaveReal(h, id, 2, pureAmount)
call SaveReal(h, id, 3, PDDS.amount)
call SaveReal(h, id, 4, originalHealth)
// Save this extra to manage parallel damage instances
call SaveReal(h, targetId, 0, GetWidgetLife(PDDS.target))
call SaveReal(h, targetId, 1, PDDS.amount)
call SaveReal(h, targetId, 2, originalHealth)
call SaveInteger(h, targetId, 3, id)
// Avoid healing of negative spell damage
if rawAmount < 0.0 then
call DisableTrigger(damageEvent)
call DealFixDamage(PDDS.source, PDDS.target, -rawAmount)
if ( originalHealth - PDDS.amount < UNIT_MIN_LIFE ) then
call UnitRemoveAbility(PDDS.target, SET_MAX_LIFE)
call DealFixDamage(PDDS.source, PDDS.target, PDDS.amount)
endif
call EnableTrigger(damageEvent)
endif
// Guarantee unit exploding
if originalHealth - PDDS.amount < UNIT_MIN_LIFE then
if rawAmount > 0.0 then
call UnitRemoveAbility(PDDS.target, SET_MAX_LIFE)
call SetWidgetLife(PDDS.target, UNIT_MIN_LIFE)
endif
endif
// Start the after damage event
call TimerStart(time, 0.0, false, function AfterDamage)
endif
// Handle allocated attacks from UnitDamageTargetEx
if totalAllocs == 0 then
set totalAllocs = allocatedAttacks
endif
if allocatedAttacks > 0 then
set allocatedAttacks = allocatedAttacks - 1
set allocCounter = allocCounter + 1
call TriggerEvaluate(runAllocatedAttacks)
endif
// Reset all required variables
set totalAllocs = 0
set allocCounter = -1
set PDDS.damageType = -1
endfunction
/******************************************************************************
* Initialization
******************************************************************************/
private function RestoreTriggers takes nothing returns nothing
local unit enumUnit = GetEnumUnit()
// Re-register units that are alive
if GetWidgetLife(enumUnit) >= UNIT_MIN_LIFE then
call TriggerRegisterUnitEvent(damageEvent, enumUnit, EVENT_UNIT_DAMAGED)
endif
set enumUnit = null
endfunction
private function ClearMemory_Actions takes nothing returns nothing
local group g = CreateGroup()
local code c = function DamageEngine
// Reset the damage event
call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
call ResetTrigger(damageEvent)
call DestroyTrigger(damageEvent)
set damageEvent = null
// Rebuild it then
set damageEvent = CreateTrigger()
call TriggerAddCondition(damageEvent, Filter(c))
call ForGroup(g, function RestoreTriggers)
// Clean things up
call DestroyGroup(g)
set g = null
set c = null
endfunction
private function MapInit takes nothing returns nothing
local unit enumUnit = GetEnumUnit()
// Register units on map initialization
call UnitAddAbility(enumUnit, DAMAGE_TYPE_DETECTOR)
call UnitMakeAbilityPermanent(enumUnit, true, DAMAGE_TYPE_DETECTOR)
call TriggerRegisterUnitEvent(damageEvent, enumUnit, EVENT_UNIT_DAMAGED)
set enumUnit = null
endfunction
private function UnitEntersMap takes nothing returns nothing
local unit triggerUnit = GetTriggerUnit()
// Register units that enter the map
if ( GetUnitAbilityLevel(triggerUnit, DAMAGE_TYPE_DETECTOR) < 1 ) then
call UnitAddAbility(triggerUnit, DAMAGE_TYPE_DETECTOR)
call UnitMakeAbilityPermanent(triggerUnit, true, DAMAGE_TYPE_DETECTOR)
call TriggerRegisterUnitEvent(damageEvent, triggerUnit, EVENT_UNIT_DAMAGED)
endif
set triggerUnit = null
endfunction
private function RunAllocatedAttacks takes nothing returns nothing
local integer localAllocAttacks = allocatedAttacks + 1
// Calculate the correct sequence of allocated attacks
set localAllocAttacks = localAllocAttacks - totalAllocs + 1 + 2*allocCounter
// Deal code damage if the unit isn't exploding
set PDDS.damageType = CODE
if GetUnitLife(LoadUnitHandle(h, localAllocAttacks, 1)) >= UNIT_MIN_LIFE then
call UnitDamageTarget(LoadUnitHandle(h, localAllocAttacks, 0), LoadUnitHandle(h, localAllocAttacks, 1), /*
*/LoadReal(h, localAllocAttacks, 2), LoadBoolean(h, localAllocAttacks, 3), /*
*/LoadBoolean(h, localAllocAttacks, 4), ConvertAttackType(LoadInteger(h, /*
*/localAllocAttacks, 5)), ConvertDamageType(LoadInteger(h, localAllocAttacks, 6)), /*
*/ConvertWeaponType(LoadInteger(h, localAllocAttacks, 7)))
else
call FlushChildHashtable(h, localAllocAttacks - 1)
endif
// Clean things up
call FlushChildHashtable(h, localAllocAttacks)
endfunction
private module Inits
private static method onInit takes nothing returns nothing
local group g = CreateGroup()
local region r = CreateRegion()
local trigger UnitEnters = CreateTrigger()
local trigger ClearMemory = CreateTrigger()
local code cDamageEngine = function DamageEngine
local code cUnitEnters = function UnitEntersMap
local code cClearMemory = function ClearMemory_Actions
local code cRunAllocatedAttacks = function RunAllocatedAttacks
// Initialize variables
set h = InitHashtable()
set damageEvent = CreateTrigger()
set damageHandler = CreateTrigger()
set PDDS.damageType = -1
set allocatedAttacks = 0
set runAllocatedAttacks = CreateTrigger()
set totalAllocs = 0
set allocCounter = -1
// Register units on map initialization
call TriggerRegisterVariableEvent(damageHandler, SCOPE_PRIVATE + "damageEventTrigger", EQUAL, 1.0)
call TriggerAddCondition(damageEvent, Filter(cDamageEngine))
call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
call ForGroup(g, function MapInit)
// Register units that enter the map
call RegionAddRect(r, GetWorldBounds())
call TriggerRegisterEnterRegion(UnitEnters, r, null)
call TriggerAddCondition(UnitEnters, Filter(cUnitEnters))
// Register trigger for allocated attacks
call TriggerAddCondition(runAllocatedAttacks, Filter(cRunAllocatedAttacks))
// Clear memory leaks
call TriggerRegisterTimerEvent(ClearMemory, TRIGGER_CLEANUP_PERIOD, true)
call TriggerAddCondition(ClearMemory, Filter(cClearMemory))
// Clean things up
call DestroyGroup(g)
set UnitEnters = null
set ClearMemory = null
set cDamageEngine = null
set cUnitEnters = null
set cClearMemory = null
set cRunAllocatedAttacks = null
set g = null
set r = null
endmethod
endmodule
private struct Init extends array
implement Inits
endstruct
endlibrary
//TESH.scrollpos=0
//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=27
//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=84
//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=259
//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=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//* This implementation is particularly useful because the boolexpr you pass to
//* the function will not be evaluated unless the unit is in collisional range
//* of the origin.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
//If you set this constant to false, the BOOLEXPR_TRUE and BOOLEXPR_FALSE
//boolean expressions will not be initialized in your map. Since they are
//no longer important, this is not a problem, but they are defined by
//default to maintain backwards compatibility.
private constant boolean USE_TRUEFALSE_BOOLEXPRS = true
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for storage purposes
private hashtable ht = InitHashtable()
//* Temporary references used internally
private boolean Flag = false
private group Temp = null
private group Area = CreateGroup()
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Temp)
set Flag = false
endif
call GroupAddUnit(Temp, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Temp = g
call ForGroup(Temp, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
local integer id = GetHandleId(g)
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(ht, 1, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(ht, 1, bid))
call RemoveSavedHandle(ht, 1, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
private function RangeFilter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function RangeFilter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(ht, 1, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(ht, 1, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function RangeFilter), filter)
call SaveBooleanExprHandle(ht, 1, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local unit u = null
call GroupClear(whichGroup)
call GroupEnumUnitsInRange(Area, x, y, GetRadius(radius), null)
loop
set u = FirstOfGroup(Area)
exitwhen u == null
call GroupRemoveUnit(Area, u)
if IsUnitInRangeXY(u, x, y, radius) then
call GroupAddUnit(whichGroup, u)
endif
endloop
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
static if USE_TRUEFALSE_BOOLEXPRS then
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endif
endfunction
endlibrary
//TESH.scrollpos=66
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=53
//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.
* (This function is only available if you have UnitIndexer)
*
* - function IsUnitChannelingById takes integer unitIndex returns boolean
* - Tells whether a unti is channeling or not given the unit index.
*
**************************************/
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=0
//TESH.alwaysfold=0
library TimedEffect /* v1.3
*************************************************************************************
*
* Allows one to create timed effects on 3d points or units.
*
*************************************************************************************
*
* API
*
* static method createOnPoint takes string mdl, real x, real y, real z, real duration returns thistype
* - starts a timed effect on a 3d point
*
* static method createOnUnit takes string mdl, unit u, string attach, real duration returns thistype
* - starts a timed effect on a unit
*
* method operator newDuration= takes real value returns nothing
* - sets an instance' new duration
*
* method destroy takes nothing returns nothing
* - destroys an instance
*
*************************************************************************************
*
* Credits
*
* PurgeAndFire for the OTip trick.
*
**************************************************************************************/
struct TimedEffect extends array
private static timer t = CreateTimer()
private static thistype instance = 0
private static integer count = 0
private static effect tempEffect
private static destructable platform
private thistype recycle
private thistype next
private thistype prev
private effect effects
private real time
method destroy takes nothing returns nothing
call DestroyEffect(effects)
set effects = null
set time = 0
set prev.next = next
set next.prev = prev
set recycle = thistype(0).recycle
set thistype(0).recycle = this
set count = count - 1
if 0 == count then
call PauseTimer(t)
endif
endmethod
method operator newDuration= takes real value returns nothing
set time = time + value
endmethod
private static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen 0 == this
set time = time - 0.031250000
if 0 >= time then
call destroy()
endif
set this = next
endloop
endmethod
private static method allocate takes nothing returns thistype
local thistype this = thistype(0).recycle
if 0 == this then
set this = instance + 1
set instance = this
else
set thistype(0).recycle = recycle
endif
set next = 0
set prev = 0
set thistype(0).prev.next = this
set thistype(0).prev = this
set count = count + 1
if 1 == count then
call TimerStart(t, 0.031250000, true, function thistype.periodic)
endif
return this
endmethod
static method createOnPoint takes string mdl, real x, real y, real z, real duration returns thistype
local thistype this
if 0 < z then
set platform = CreateDestructableZ('OTip', x, y, z, 0, 1, 0)
endif
set tempEffect = AddSpecialEffect(mdl, x, y)
if null != platform then
call RemoveDestructable(platform)
endif
if duration >= 0.031250000 then
set this = allocate()
set time = duration
set effects = tempEffect
return this
endif
call DestroyEffect(tempEffect)
set tempEffect = null
return 0
endmethod
static method createOnUnit takes string mdl, unit u, string attach, real duration returns thistype
local thistype this
set tempEffect = AddSpecialEffectTarget(mdl, u, attach)
if duration >= 0.031250000 then
set this = allocate()
set effects = tempEffect
set time = duration
return this
endif
call DestroyEffect(tempEffect)
set tempEffect = null
return 0
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@ SetUnitMaxState
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@ Written by:
//@ Earth-Fury
//@ Based on the work of:
//@ Blade.dk
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ SetUnitMaxState Readme
//@---------------------------------------------------------------------------------------
//@
//@ SetUnitMaxState() is a function origionally written by Blade.dk. It takes advantage of
//@ a bug which was introduced in one of the patches: Bonus life and mana abilitys will
//@ only ever add the bonus ammount for level 1. However, when removed, they will remove
//@ the ammount they should have added at their current level. This allows you to change a
//@ units maximum life and mana, without adding a perminent ability to the unit.
//@
//@---------------------------------------------------------------------------------------
//@ Adding SetUnitMaxState to your map:
//@
//@ Simply copy this library in to a trigger which has been converted to custom text.
//@ After that, you must copy over the abilitys. This is made easy by the ObjectMerger in
//@ JASS NewGen. Distributed with this system are //! external calls to the ObjectMerger.
//@ Simply copy both of them in to your map, save your map, close and reopen your map in
//@ the editor, and remove the external calls. (Or otherwise disable them. Removing the !
//@ after the // works.)
//@
//@---------------------------------------------------------------------------------------
//@ Using SetUnitMaxState:
//@
//@ nothing SetUnitMaxState(unit <target>, unitstate <state>, real <new value>)
//@
//@ This function changes <target>'s unitstate <state> to be eqal to <new value>. Note
//@ that the only valid unitstates this function will use are UNIT_STATE_MAX_MAN and
//@ UNIT_STATE_MAX_LIFE. Use SetUnitState() to change other unitstates.
//@
//@ nothing AddUnitMaxState(unit <target>, unitstate <state>, real <add value>)
//@
//@ This function adds <add value> to <target>'s <state> unitstate. <add value> can be
//@ less than 0, making this function reduce the specified unitstate. This function will
//@ only work with the unitstates UNIT_STATE_MAX_LIFE and UNIT_STATE_MAX_MANA.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library SetUnitMaxState initializer Initialize
globals
//========================================================================================
// Configuration
//========================================================================================
// The rawcode of the life ability:
private constant integer MAX_STATE_LIFE_ABILITY = 'Zlif'
// The rawcode of the mana ability:
private constant integer MAX_STATE_MANA_ABILITY = 'Zman'
// The maximum power of two the abilitys use:
private constant integer MAX_STATE_MAX_POWER = 8
endglobals
//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================
globals
private integer array PowersOf2
endglobals
function SetUnitMaxState takes unit u, unitstate state, real newValue returns nothing
local integer stateAbility
local integer newVal = R2I(newValue)
local integer i = MAX_STATE_MAX_POWER
local integer offset
if state == UNIT_STATE_MAX_LIFE then
set stateAbility = MAX_STATE_LIFE_ABILITY
elseif state == UNIT_STATE_MAX_MANA then
set stateAbility = MAX_STATE_MANA_ABILITY
else
debug call BJDebugMsg("SetUnitMaxState Error: Invalid unitstate")
return
endif
set newVal = newVal - R2I(GetUnitState(u, state))
if newVal > 0 then
set offset = MAX_STATE_MAX_POWER + 3
elseif newVal < 0 then
set offset = 2
set newVal = -newVal
else
return
endif
loop
exitwhen newVal == 0 or i < 0
if newVal >= PowersOf2[i] then
call UnitAddAbility(u, stateAbility)
call SetUnitAbilityLevel(u, stateAbility, offset + i)
call UnitRemoveAbility(u, stateAbility)
set newVal = newVal - PowersOf2[i]
else
set i = i - 1
endif
endloop
endfunction
function AddUnitMaxState takes unit u, unitstate state, real addValue returns nothing
call SetUnitMaxState(u, state, GetUnitState(u, state) + addValue)
endfunction
private function Initialize takes nothing returns nothing
local integer i = 1
set PowersOf2[0] = 1
loop
set PowersOf2[i] = PowersOf2[i - 1] * 2
set i = i + 1
exitwhen i == MAX_STATE_MAX_POWER + 3
endloop
endfunction
endlibrary
//TESH.scrollpos=4
//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)
if b then
call FlashQuestDialogButton()
endif
endmethod
method operator discover= takes boolean b returns nothing
call QuestSetDiscovered(.q, b)
if b then
call FlashQuestDialogButton()
endif
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=2
//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=1
//TESH.alwaysfold=0
library RandomUnit
globals
private unit u = null
private group G = CreateGroup()
private integer count = 0
endglobals
private function EnumUnits takes nothing returns nothing
set count = count+1
endfunction
function GetRandomUnitInArea takes real x, real y, real aoe, boolexpr b returns unit
local integer ran
call GroupEnumUnitsInRange(G, x, y, aoe, b)
set count = 0
call ForGroup(G, function EnumUnits)
set ran = GetRandomInt(1, count)
set count = 0
loop
set u = FirstOfGroup(G)
exitwhen u==null
set count = count + 1
if count==ran then
exitwhen true
endif
call GroupRemoveUnit(G, u)
endloop
call GroupClear(G)
return u
endfunction
endlibrary
//TESH.scrollpos=84
//TESH.alwaysfold=0
/**************************************************************
Escort Lite v1.0
by: mckill2009
****************************************************************/
library EscortLite uses IsUnitChanneling
globals
private constant integer ATTACK = 851983
private constant integer MOVE = 851986
private constant integer SMART = 851971
private constant real INTERVAL = 3.0
private constant real NO_ENEMY_IN_AOE = 800
private constant real LEADER_TOO_FAR = 1000000 //1000*1000
private group g = CreateGroup()
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null
endfunction
private function GetDistance takes real x1, real y1, real x2, real y2 returns real
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
endfunction
private function NoEnemyUnits takes unit u, real radius returns boolean
local unit first
local player pl = GetOwningPlayer(u)
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), radius, null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, pl) and not UnitIsSleeping(first) then
//returns has enemy units
set first = null
set pl = null
return false
endif
call GroupRemoveUnit(g, first)
endloop
set pl = null
return true
endfunction
private function UnitMoveOrder takes unit u returns boolean
return GetUnitCurrentOrder(u)==MOVE or GetUnitCurrentOrder(u)==SMART or GetUnitCurrentOrder(u)==ATTACK
endfunction
struct EscortLite
unit leader
unit guard
real angle
real offset
real delay
boolean ra
boolean isEscorting
private static real interval = 0.1
private static real xGuard
private static real yGuard
private static real xLeader
private static real yLeader
private static timer t = CreateTimer()
private static integer ins = 0
private static integer array indexAr
private method destroy takes nothing returns nothing
set .leader = null
set .guard = null
call .deallocate()
endmethod
private method moveUnit takes nothing returns nothing
local unit first
local real facing
local real x //lea
local real y //lea
local real x1
local real y1
local real random
if UnitAlive(.leader) then
if NoEnemyUnits(.guard, NO_ENEMY_IN_AOE) then
if .ra then
set random = GetRandomReal(0,6)
set x1 = xLeader + .offset*Cos(random)
set y1 = yLeader + .offset*Sin(random)
else
set facing = GetUnitFacing(.leader)
set x1 = xLeader + .offset * Cos(facing + .angle)
set y1 = yLeader + .offset * Sin(facing + .angle)
endif
if GetUnitCurrentOrder(.guard)==0 or UnitMoveOrder(.leader) and not IsUnitChanneling(.guard) then
call IssueTargetOrderById(.guard, SMART, .leader)
call IssuePointOrderById(.guard, ATTACK, x1, y1)
endif
else
//Engage enemy units here
call GroupEnumUnitsInRange(g, x, y, NO_ENEMY_IN_AOE+50, null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.guard)) then
call IssuePointOrderById(.guard, ATTACK, GetUnitX(first), GetUnitY(first))
exitwhen true
endif
call GroupRemoveUnit(g, first)
endloop
endif
endif
endmethod
private static method looper takes nothing returns nothing
local thistype this
local integer i = 0
loop
set i = i + 1
set this = indexAr[i]
if .isEscorting and UnitAlive(.guard) then
set xGuard = GetUnitX(.guard)
set yGuard = GetUnitY(.guard)
set xLeader = GetUnitX(.leader)
set yLeader = GetUnitY(.leader)
if GetDistance(xGuard, yGuard, xLeader, yLeader) > LEADER_TOO_FAR then
call IssuePointOrderById(.guard, MOVE, xLeader, yLeader)
endif
set .delay = .delay + interval
if .delay > INTERVAL then
set .delay = 0
call .moveUnit()
endif
else
call .destroy()
set indexAr[i] = indexAr[ins]
set indexAr[ins] = this
set ins = ins - 1
set i = i - 1
if ins==0 then
call PauseTimer(t)
endif
endif
exitwhen i==ins
endloop
endmethod
static method addEscort takes unit leader, unit guard, real offset, real angle, boolean randomAngle returns thistype
local thistype this = allocate()
set .leader = leader
set .guard = guard
set .offset = offset
set .angle = angle * bj_DEGTORAD
set .ra = randomAngle
set .isEscorting = true
set .delay = 0
call RemoveGuardPosition(guard)
if ins==0 then
call TimerStart(t, interval, true, function thistype.looper)
endif
set ins = ins + 1
set indexAr[ins] = this
return this
endmethod
method removeEscort takes nothing returns nothing
set .isEscorting = false
endmethod
endstruct
endlibrary
//TESH.scrollpos=183
//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 = true
/**************************************************************************
* 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 = true
/**************************************************************************
* 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 = 200
/**************************************************************************
* 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 = 400
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=44
//TESH.alwaysfold=0
/*************************************************************************
ItemTable v1.0
by mckill2009
Allows to make Item Sets and drops item by chance on unit death event
**************************************************************************/
library ItemTable uses Table
globals
private Table data
private TableArray ItemGroup
endglobals
private module DI
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition( t, function thistype.death)
set data = Table.create()
set ItemGroup = TableArray[0x2000]
set t = null
endmethod
endmodule
struct ItemTable
private integer itemTypeCount
private integer chance
private static method dropItem takes unit u returns nothing
local integer id = GetHandleId(u)
local thistype this = data[id]
local integer randomItem = GetRandomInt(1, 100)
if randomItem <= this.chance then
call CreateItem(ItemGroup[this][GetRandomInt(1, this.itemTypeCount)], GetUnitX(u), GetUnitY(u))
endif
call data.remove(id)
endmethod
static method death takes nothing returns boolean
if data.has(GetHandleId(GetTriggerUnit())) then
call dropItem(GetTriggerUnit())
endif
return false
endmethod
implement DI
/*********************************************************
* SYSTEM API
***********************************************************/
static method create takes integer chance returns thistype
local thistype this = allocate()
set this.chance = chance
return this
endmethod
method addUnit takes unit u returns nothing
set data[GetHandleId(u)] = this
endmethod
method addItemType takes integer itemType returns nothing
set this.itemTypeCount = this.itemTypeCount + 1
set ItemGroup[this][this.itemTypeCount] = itemType
endmethod
method setDropChance takes integer chance returns nothing
set this.chance = chance
endmethod
method destroy takes nothing returns nothing
call this.deallocate()
endmethod
endstruct
endlibrary
//TESH.scrollpos=105
//TESH.alwaysfold=0
/**********************************************
* EngageLite v1.0
* by mckill2009
***********************************************/
library EngageLite uses IsUnitChanneling
globals
private constant real INTERVAL = 0.1 //recommended
private timer t = CreateTimer()
private group g = CreateGroup()
private group attackingGroup = CreateGroup()
private integer instance = 0
private integer array instanceAR
endglobals
/**********************************************
* CONFIGURABLES
***********************************************/
private function FilterEngagingUnits takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
private function FilterTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
/**********************************************
* NON-CONFIGURABLES
***********************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private struct EngageLite
private unit attacker //attacking unit
private unit target
private real interval
//private real lockTime
private static method engaging takes nothing returns nothing
local thistype this
local unit first
local integer i = 0
local real xTar
local real yTar
loop
set i = i + 1
set this = instanceAR[i]
if UnitAlive(.attacker) then
if UnitAlive(.target) then
set .interval = .interval + INTERVAL
set xTar = GetUnitX(.target)
set yTar = GetUnitY(.target)
if .interval > 3. then
set .interval = 0
if not IsUnitChanneling(.attacker) then
call IssuePointOrderById(.attacker, ATTACK, xTar, yTar)
endif
endif
else
//search for new target enemy
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(.attacker, GetOwningPlayer(first)) and FilterTargets(first) then
set .target = first
exitwhen true
endif
call GroupRemoveUnit(g, first)
endloop
endif
else
call GroupRemoveUnit(attackingGroup, .attacker)
set .attacker = null
set .target = null
call .deallocate()
set instanceAR[i] = instanceAR[instance]
set instanceAR[instance] = this
set instance = instance - 1
set i = i-1
if instance==0 then
call PauseTimer(t)
endif
endif
exitwhen i==instance
endloop
endmethod
static method register takes unit attacker, unit target returns nothing
local thistype this = allocate()
set .attacker = attacker
set .target = target
set .interval = 0
if instance==0 then
call TimerStart(t, INTERVAL, true, function thistype.engaging)
endif
set instance = instance + 1
set instanceAR[instance] = this
endmethod
endstruct
/**********************************
/ API
***********************************/
function EngageSingle takes unit attacker, unit target returns nothing
if not IsUnitInGroup(attacker, attackingGroup) then
call GroupAddUnit(attackingGroup, attacker)
call RemoveGuardPosition(attacker)
call IssuePointOrderById(attacker, ATTACK, GetUnitX(target), GetUnitY(target))
call EngageLite.register(attacker, target)
endif
endfunction
function EngageGroupForm takes unit attacker, unit target, real range returns nothing
local unit first
local player pl = GetOwningPlayer(attacker)
call GroupEnumUnitsInRange(g, GetUnitX(attacker), GetUnitY(attacker), range, null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and FilterEngagingUnits(first) and GetOwningPlayer(first)==pl then
call EngageSingle(first, target)
endif
call GroupRemoveUnit(g, first)
endloop
set pl = null
endfunction
function EngageGroupForPlayer takes player owner, unit target, real x, real y, real range returns nothing
local unit first
call GroupEnumUnitsInRange(g, x, y, range, null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and FilterEngagingUnits(first) and GetOwningPlayer(first)==owner then
call EngageSingle(first, target)
endif
call GroupRemoveUnit(g, first)
endloop
endfunction
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
/*********************************************************************
AutoCastSystem v1.2
by mckill2009
**********************************************************************
INSTALLATION:
Copy ALL the required libraries and the AutoCastSystem trigger to your trigger editor
OR
Copy ALL the triggers from the AutoCastSystem folder
**********************************************************************
Struct API: See the tutorial/demo on how this works
static method register takes unit caster returns thistype
method spellTypeUnitTarget takes code func, integer spellOrderID returns nothing
method spellTypePointTarget takes code func, integer spellOrderID returns nothing
method spellTypeNoTarget takes code func, integer spellOrderID returns nothing
method removeSpellOrderUnit takes integer spellOrderID returns nothing
method removeSpellOrderPoint takes integer spellOrderID returns nothing
method removeSpellOrderNone takes integer spellOrderID returns nothing
method launch takes real interval returns nothing
method removeAutocast takes nothing returns nothing
Struct globals
CS.caster
CS.target
CS.SpellTargetX
CS.SpellTargetY
**********************************************************************
CREDITS:
TimerUtils by Vexorian http://www.wc3c.net/showthread.php?t=101322
Table by Bribe http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
IsUnitChanneling by Magtheridon96 http://www.hiveworkshop.com/forums/jass-resources-412/snippet-isunitchanneling-211254/
**********************************************************************/
library AutoCastSystem uses TimerUtils, Table, IsUnitChanneling
globals
/***********************************************
* NON-CONFIGURABLES
************************************************/
private TableArray trig
private TableArray oID
private Table chk
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
struct CS extends array
static unit caster
static unit target
static real SpellTargetX
static real SpellTargetY
private static method onInit takes nothing returns nothing
set trig = TableArray[0x2000]
set oID = TableArray[0x2000]
set chk = Table.create()
endmethod
endstruct
struct ACS
private unit caster
private integer indexUnitMax
private integer indexPointMax
private integer indexNoneMax
private integer spellType
private boolean remove
private static integer pointIndex = 10000
private static integer noneIndex = 20000
private method removeEx takes integer index, integer maxIndex returns nothing
local integer i = index
loop
set i = i+1
set oID[this][i] = 0
call DestroyTrigger(trig[this].trigger[i])
set trig[this].trigger[i] = null
exitwhen i==maxIndex
endloop
endmethod
private method destroy takes nothing returns nothing
call .removeEx(0, .indexUnitMax)
call .removeEx(pointIndex, .indexPointMax)
call .removeEx(noneIndex, .indexNoneMax)
call chk.remove(GetHandleId(.caster))
set .caster = null
call .deallocate()
endmethod
private static method period takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local integer randomizer
local integer i
if .remove then
call ReleaseTimer(GetExpiredTimer())
call .destroy()
elseif UnitAlive(.caster) then
set CS.caster = .caster
if not IsUnitChanneling(.caster) then
set randomizer = GetRandomInt(1, 3)
if randomizer==1 then //Unit target
set i = GetRandomInt(1, .indexUnitMax)
if oID[this][i] > 0 then
if TriggerEvaluate(trig[this].trigger[i]) then
call IssueTargetOrderById(.caster, oID[this][i], CS.target)
endif
endif
elseif randomizer==2 then //Point target
set i = GetRandomInt(pointIndex, .indexPointMax)
if oID[this][i] > 0 then
if TriggerEvaluate(trig[this].trigger[i]) then
call IssuePointOrderById(.caster, oID[this][i], CS.SpellTargetX, CS.SpellTargetY)
endif
endif
elseif randomizer==3 then //No target
set i = GetRandomInt(noneIndex, .indexNoneMax)
if oID[this][i] > 0 then
if TriggerEvaluate(trig[this].trigger[i]) then
call IssueImmediateOrderById(.caster, oID[this][i])
endif
endif
endif
endif
endif
endmethod
/***********************************************
* SYSTEM API's
************************************************/
static method register takes unit caster returns thistype
local thistype this
if chk.has(GetHandleId(caster)) then
if IsUnitType(caster, UNIT_TYPE_HERO) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "thistype.register ERROR: "+GetHeroProperName(caster)+" is already registered!")
else
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "thistype.register ERROR: "+GetUnitName(caster)+" is already registered!")
endif
return 0
else
set this = allocate()
set .caster = caster
set .remove = false
set .indexUnitMax = 0
set .indexPointMax = pointIndex
set .indexNoneMax = noneIndex
set chk[GetHandleId(caster)] = this
endif
return this
endmethod
method spellTypeUnitTarget takes code func, integer spellOrderID returns nothing
set .indexUnitMax = .indexUnitMax + 1
set oID[this][.indexUnitMax] = spellOrderID
set trig[this].trigger[.indexUnitMax] = CreateTrigger()
call TriggerAddCondition(trig[this].trigger[.indexUnitMax], Condition(func))
endmethod
method spellTypePointTarget takes code func, integer spellOrderID returns nothing
set .indexPointMax = .indexPointMax + 1
set oID[this][.indexPointMax] = spellOrderID
set trig[this].trigger[.indexPointMax] = CreateTrigger()
call TriggerAddCondition(trig[this].trigger[.indexPointMax], Condition(func))
endmethod
method spellTypeNoTarget takes code func, integer spellOrderID returns nothing
set .indexNoneMax = .indexNoneMax + 1
set oID[this][.indexNoneMax] = spellOrderID
set trig[this].trigger[.indexNoneMax] = CreateTrigger()
call TriggerAddCondition(trig[this].trigger[.indexNoneMax], Condition(func))
endmethod
method removeSpellOrderUnit takes integer spellOrderID returns nothing
local integer i = 0
loop
set i = i+1
if oID[this][i]==spellOrderID then
set oID[this][i] = oID[this][.indexUnitMax]
set oID[this][.indexUnitMax] = 0
call DestroyTrigger(trig[this].trigger[.indexUnitMax])
set trig[this].trigger[.indexUnitMax] = null
set .indexUnitMax = .indexUnitMax - 1
exitwhen true
endif
exitwhen i==.indexUnitMax
endloop
endmethod
method removeSpellOrderPoint takes integer spellOrderID returns nothing
local integer i = pointIndex
loop
set i = i+1
if oID[this][i]==spellOrderID then
set oID[this][i] = oID[this][.indexPointMax]
set oID[this][.indexPointMax] = 0
call DestroyTrigger(trig[this].trigger[.indexPointMax])
set trig[this].trigger[.indexPointMax] = null
set .indexPointMax = .indexPointMax - 1
exitwhen true
endif
exitwhen i==.indexPointMax
endloop
endmethod
method removeSpellOrderNone takes integer spellOrderID returns nothing
local integer i = noneIndex
loop
set i = i+1
if oID[this][i]==spellOrderID then
set oID[this][i] = oID[this][.indexNoneMax]
set oID[this][.indexNoneMax] = 0
call DestroyTrigger(trig[this].trigger[.indexNoneMax])
set trig[this].trigger[.indexNoneMax] = null
set .indexNoneMax = .indexNoneMax - 1
exitwhen true
endif
exitwhen i==.indexNoneMax
endloop
endmethod
method launch takes real interval returns nothing
if chk.has(GetHandleId(.caster)) then
call TimerStart(NewTimerEx(this), interval, true, function thistype.period)
else
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "thistype.launch ERROR: attempt to start a null caster.")
endif
endmethod
method removeAutocast takes nothing returns nothing
set .remove = true
endmethod
endstruct
endlibrary
//TESH.scrollpos=45
//TESH.alwaysfold=0
/**************************************************************
Mobilize v1.0
by mckill2009
Summons units from XY using parabola
***************************************************************/
library Mobilize uses T32, SpellEffectEvent, Table, IsUnitChanneling optional SummonedEscort
globals
private constant integer SPELL_ID = 'A00U'
private constant integer DUMMY_ID = 'h003'
private constant real INTERVAL = 2.0
private constant real OFFSET_FROM_CASTER = 200
private constant real HEIGHT = 500
private constant real SPEED = 70
private string SFX = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
private boolean IS_SPELL_CHANNELING = false
/**************************************************************
* NON-CONFIGURABLES
***************************************************************/
private Table mobData
private TableArray unitType
private TableArray xLoc
private TableArray yLoc
endglobals
private function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)//Standard parabola
endfunction
private function GetDistanceEx takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null
endfunction
private struct CreatingUnits
private unit summoner
private real angle
private real distance
private real distX
private real xPoint
private real yPoint
private real height
private Mobilize dat
private method periodic takes nothing returns nothing
local integer random
local unit sum
if .distance > .distX then
set .distX = .distX + SPEED
call SetUnitX(.summoner, GetUnitX(.summoner) + SPEED * Cos(.angle))
call SetUnitY(.summoner, GetUnitY(.summoner) + SPEED * Sin(.angle))
call SetUnitFlyHeight(.summoner, GetParabolaZ(HEIGHT, .distance, .distX) ,0)
else
set random = GetRandomInt(1, .dat.count)
set sum = CreateUnit(GetOwningPlayer(.summoner), unitType[dat][random], .xPoint, .yPoint, 0)
call DestroyEffect(AddSpecialEffectTarget(SFX, sum, "origin"))
call UnitApplyTimedLife(.summoner, 'BTLF', 0.1)
static if LIBRARY_SummonedEscort then
call SE.summoned(null, sum)
endif
set sum = null
set .summoner = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method start takes unit u, real x, real y, integer d returns nothing
local thistype this = allocate()
local real xU = GetUnitX(u)
local real yU = GetUnitY(u)
set .dat = d
set .angle = Atan2(y - yU, x - xU)
set .summoner = u
set .distance = GetDistanceEx(x, y, xU, yU)
set .xPoint = x
set .yPoint = y
set .distX = 0
call .startPeriodic()
endmethod
endstruct
struct MobilizeCast
private unit caster
private real delay
private real duration
private player pl
private boolean isOn
private method action takes nothing returns nothing
local unit summoner
local real xCaster
local real yCaster
local real angle
local integer random
local Mobilize dat
if .duration > 0 then
set .duration = .duration - T32_PERIOD
set .delay = .delay + T32_PERIOD
if .delay > INTERVAL then
set .delay = 0
set angle = GetRandomReal(-3, 3)
set xCaster = GetUnitX(.caster) + OFFSET_FROM_CASTER * Sin(angle)
set yCaster = GetUnitY(.caster) + OFFSET_FROM_CASTER * Cos(angle)
//recovering the data from Mobilize struct using Table
set dat = mobData[GetHandleId(.caster)]
set random = GetRandomInt(1, dat.countLoc)
set summoner = CreateUnit(.pl, DUMMY_ID, xLoc[dat].real[random], yLoc[dat].real[random], 0)
call DestroyEffect(AddSpecialEffectTarget(SFX, summoner, "origin"))
call CreatingUnits.start(summoner, xCaster, yCaster, dat)
set summoner = null
endif
else
set .isOn = false
endif
endmethod
private method periodic takes nothing returns nothing
if UnitAlive(.caster) and .isOn then
if IS_SPELL_CHANNELING then
if IsUnitChanneling(.caster) then
call .action()
else
set .isOn = false
endif
else
call .action()
endif
else
set .caster = null
set .pl = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
local Mobilize dat
set dat = mobData[GetHandleId(GetTriggerUnit())]
set .pl = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .delay = 0
set .isOn = true
set .duration = dat.duration
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
set mobData = Table.create()
set unitType = TableArray[0x2000]
set xLoc = TableArray[0x2000]
set yLoc = TableArray[0x2000]
endmethod
endstruct
struct Mobilize
integer count
integer countLoc
real duration
/*******************************************************
* API
********************************************************/
static method create takes unit caster returns thistype
local thistype this = allocate()
set mobData[GetHandleId(caster)] = this
set .count = 0
set .countLoc = 0
set .duration = 0
return this
endmethod
method setDuration takes real duration returns nothing
set .duration = duration
endmethod
method add takes integer unitID returns nothing
set .count = .count + 1
set unitType[this][.count] = unitID
endmethod
method setPoint takes real x, real y returns nothing
set .countLoc = .countLoc + 1
set xLoc[this].real[.countLoc] = x
set yLoc[this].real[.countLoc] = y
endmethod
method remove takes integer unitID returns nothing
local integer i = 0
loop
set i = i+1
if unitType[this][i]==unitID then
set unitType[this][i] = unitType[this][.count]
set .count = .count - 1
exitwhen true
endif
exitwhen i==.count
endloop
endmethod
method removePoint takes real x, real y returns nothing
local integer i = 0
loop
set i = i+1
if xLoc[this].real[i]==x and yLoc[this].real[i]==y then
set xLoc[this][i] = xLoc[this][.countLoc]
set yLoc[this][i] = yLoc[this][.countLoc]
set .countLoc = .countLoc - 1
exitwhen true
endif
exitwhen i==.countLoc
endloop
endmethod
endstruct
endlibrary
//TESH.scrollpos=106
//TESH.alwaysfold=0
/*******************************************************
Simple Functions
by mckill2009
For easy implementation
********************************************************/
library SimpleFunctions initializer init
globals
private location LOC = Location(0,0)
private group TempG = CreateGroup()
private unit dummy = null
private player pl = 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 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 NoEnemyUnits takes unit u, real radius returns boolean
local unit first
set pl = GetOwningPlayer(u)
call GroupEnumUnitsInRange(TempG, GetUnitX(u), GetUnitY(u), radius, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, pl) and GetUnitAbilityLevel(first, 'Aloc')==0 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=178
//TESH.alwaysfold=0
library AIBoss initializer init uses AutoCastSystem, RandomUnit, RegisterPlayerUnitEvent
globals
private constant real RANGE = 600
private integer count = 0
//Bosses
private ACS emek
private ACS clawgrek
private ACS batushk
private ACS uruzapoth
private ACS kalifas
//Mini Bosses
private ACS salg
private ACS zekaon
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null and GetUnitAbilityLevel(u, 'Aloc')==0
endfunction
private function NoBuff takes unit u, integer buffID returns boolean
return GetUnitAbilityLevel(u, buffID)==0
endfunction
private function UnitEnemy takes unit u, unit u2 returns boolean
return UnitAlive(u) and IsUnitEnemy(u, GetOwningPlayer(u2)) //u is the filter unit
endfunction
private function IsAlly takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(CS.caster)) and UnitAlive(GetFilterUnit())
endfunction
private function IsEnemy takes nothing returns boolean
return UnitEnemy(GetFilterUnit(), CS.caster)
endfunction
private function NoTargetCast300 takes nothing returns boolean
local unit first
call GroupEnumUnitsInRange(TempG, GetUnitX(CS.caster), GetUnitY(CS.caster), 300, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitEnemy(first, CS.caster) then
set first = null
return true
endif
call GroupRemoveUnit(TempG, first)
endloop
return false
endfunction
private function NoTargetCast600 takes nothing returns boolean
local unit first
call GroupEnumUnitsInRange(TempG, GetUnitX(CS.caster), GetUnitY(CS.caster), 600, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitEnemy(first, CS.caster) then
set first = null
return true
endif
call GroupRemoveUnit(TempG, first)
endloop
return false
endfunction
private function CastToPoint takes nothing returns boolean
set CS.target = GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 500, Filter(function IsEnemy))
if CS.target!=null then
set CS.SpellTargetX = GetUnitX(CS.target)
set CS.SpellTargetY = GetUnitY(CS.target)
endif
return CS.target!=null
endfunction
private function CastUnitEnemyNear takes nothing returns boolean
return GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 200, Filter(function IsEnemy))!=null
endfunction
private function CastUnitEnemyAoe400 takes nothing returns boolean
return GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 400, Filter(function IsEnemy))!=null
endfunction
private function CastUnitEnemyFar takes nothing returns boolean
return GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 700, Filter(function IsEnemy))!=null
endfunction
private function CastCripple takes nothing returns boolean
set CS.target = GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 400, Filter(function IsEnemy))
return CS.target!=null and NoBuff(CS.target, 'Bcri')
endfunction
/**********************************************************************
* EMEK
***********************************************************************/
private function CheckEnemyCyclone takes nothing returns boolean
return UnitEnemy(GetFilterUnit(), CS.caster) and NoBuff(GetFilterUnit(), 'Bcyc') and NoBuff(GetFilterUnit(), 'Bcy2')
endfunction
private function CheckAllyWithMana takes nothing returns boolean
return not IsUnitEnemy(CS.caster, GetOwningPlayer(GetFilterUnit())) and GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > 0
endfunction
private function EmekCastManaOrb takes nothing returns boolean
set CS.target = GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 600, Filter(function CheckAllyWithMana))
return CS.target!=null and GetUnitState(CS.target, UNIT_STATE_MANA) < GetUnitState(CS.target, UNIT_STATE_MAX_MANA) /*
*/ and GetUnitAbilityLevel(CS.target, 'B002')==0
endfunction
private function EmekCastCyclone takes nothing returns boolean
set CS.target = GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 600, Filter(function CheckEnemyCyclone))
return CS.target!=null
endfunction
/**********************************************************************
* CLAWGREK
***********************************************************************/
private function ClawgrekCastRejuv takes nothing returns boolean
set CS.target = GetRandomUnitInArea(GetUnitX(CS.caster), GetUnitY(CS.caster), 400, Filter(function IsAlly))
return CS.target!=null and CS.target!=udg_Clawgrek and NoBuff(CS.target, 'Brej') and GetWidgetLife(CS.target) < GetUnitState(CS.target, UNIT_STATE_MAX_LIFE)
endfunction
/**********************************************************************
* FUNCTIONS
***********************************************************************/
private function Death takes nothing returns nothing
if GetTriggerUnit()==udg_Clawgrek then
call clawgrek.removeAutocast()
elseif GetTriggerUnit()==udg_Batushk then
call batushk.removeAutocast()
elseif GetTriggerUnit()==udg_Uruzapoth then
call uruzapoth.removeAutocast()
elseif GetTriggerUnit()==udg_Kalifas then
call kalifas.removeAutocast()
endif
endfunction
private function init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function Death)
endfunction
//From CinematicIntro
function EmekAI takes unit u returns nothing
set emek = emek.register(u)
call emek.spellTypeUnitTarget(function EmekCastManaOrb, 852529)
call emek.spellTypeUnitTarget(function EmekCastCyclone, 852144)
call emek.spellTypePointTarget(function CastToPoint, 852662) //fire storm, OID acid bomb
call emek.spellTypeNoTarget(function CastUnitEnemyFar, 852097) //water elemental, OID water elemental
call emek.launch(1.0)
endfunction
/**********************************************************************
* BOSSES
***********************************************************************/
function ClawgrekBossAI takes unit u returns nothing
set clawgrek = clawgrek.register(u)
call clawgrek.spellTypeNoTarget(function NoTargetCast300, 852127) //warstomp
call clawgrek.spellTypeUnitTarget(function ClawgrekCastRejuv, 852160) //rejuvenation
call clawgrek.spellTypeUnitTarget(function CastUnitEnemyAoe400, 852231) //ground tremor, OID firebolt
call clawgrek.spellTypePointTarget(function CastToPoint, 852218) //shockwave, OID carrion swarm
call clawgrek.launch(1.0)
endfunction
function BatushkAI takes unit u returns nothing
set batushk = batushk.register(u)
call batushk.spellTypeUnitTarget(function CastCripple, 852189) //cripple
call batushk.spellTypePointTarget(function CastToPoint, 852218) //crushing wave, OID carrion swarm
call batushk.spellTypePointTarget(function CastToPoint, 852089) //death carrier, OID blizzard
call batushk.spellTypeNoTarget(function NoTargetCast300, 852183) //mobilize, OID starfall
call batushk.launch(1.0)
endfunction
function UruzapothAI takes unit u returns nothing
set uruzapoth = uruzapoth.register(u)
call uruzapoth.spellTypePointTarget(function CastToPoint, 852662) //dark lightning nova, OID acid bomb
call uruzapoth.spellTypePointTarget(function CastToPoint, 852218) //charge strike, OID carrion swarm
call uruzapoth.spellTypeUnitTarget(function CastUnitEnemyNear, 852119) //equilibrium strike, OID chain lightning
call uruzapoth.spellTypeNoTarget(function NoTargetCast300, 852526) //axes of wonders, OID fan of knives
call uruzapoth.launch(1.0)
endfunction
function KalifasAI takes unit u returns nothing
set kalifas = kalifas.register(u)
call kalifas.spellTypePointTarget(function CastToPoint, 852218) //cutting edge, OID carrion swarm
call kalifas.spellTypePointTarget(function CastToPoint, 852089) //rock fall, OID blizzard
call kalifas.spellTypeUnitTarget(function CastUnitEnemyFar, 852149) //haunt strike, OID faerie fire
call kalifas.spellTypeNoTarget(function NoTargetCast300, 852526) //fallen souls, OID fan of knives
call kalifas.launch(0.5)
endfunction
/**********************************************************************
* MINI-BOSSES
***********************************************************************/
function SalgAI takes unit u returns nothing
set salg = salg.register(u)
call salg.spellTypeUnitTarget(function CastUnitEnemyFar, 852119) //chain lightning, OID chainlightning
call salg.spellTypeNoTarget(function NoTargetCast300, 852096) //slam, OID thunderclap
call salg.spellTypeNoTarget(function NoTargetCast300, 852526) //slam, OID fan of knives
call salg.spellTypePointTarget(function CastToPoint, 852218) //ground bash, OID carrion swarm
call salg.launch(0.5)
endfunction
function ZekaonAI takes unit u returns nothing
set zekaon = zekaon.register(u)
call zekaon.spellTypeUnitTarget(function CastUnitEnemyFar, 852231) //blazing rocks, OID firebolt
call zekaon.spellTypeNoTarget(function NoTargetCast600, 852526) //furios rocks, OID fan of knives
call zekaon.spellTypePointTarget(function CastToPoint, 852580) //breath of fire
call zekaon.launch(0.5)
endfunction
endlibrary
//TESH.scrollpos=118
//TESH.alwaysfold=0
library Dialogs uses DialogBox, CaravanMovement, Quests, ItemSetCreation, SetUnitStates
globals
private DialogBox cin
private button yes
private button no
private DialogBox d
private button normal
private button hard
//furbolg
private DialogBox furbolg
private button kill
private button investigate
//centaurs
private DialogBox centaurs
private button bosses
private button norm
endglobals
/******************************************************
/ INTRO DIALOG: Starts at the beginning of the game
*******************************************************/
private function LevelPick takes nothing returns nothing
local unit har
local integer i = 0
local integer random
set udg_GameLevelDisplay = "Normal Level"
if d.clickedButton(normal) then
set udg_Difficulty = 0
call SetupUnitStates(0)
call CreateItemDrops()
else //if d.clickedButton(hard) then
set udg_Difficulty = 1
call SetupUnitStates(1)
loop
set random = GetRandomInt(1, 2)
if random==2 then
set har = CreateUnitAtRect('nhrr', gg_rct_HarpyPosts, ENEMY, GetRandomReal(0, 6)*bj_RADTODEG, false) //level 3
else
set har = CreateUnitAtRect('nhrw', gg_rct_HarpyPosts, ENEMY, GetRandomReal(0, 6)*bj_RADTODEG, false) //level 3
endif
call GroupAddUnit(udg_HarpyGroup, har)
set i = i+1
exitwhen i==7
endloop
//Clawgrek Boss
call SetHeroLevel(udg_Clawgrek, 10, false)
//Batushk Boss
call SetHeroLevel(udg_Batushk, 10, false)
//Uruzapoth Boss
call SetHeroLevel(udg_Uruzapoth, 10, false)
//Kalifas Boss
call SetHeroLevel(udg_Kalifas, 10, false)
call SelectHeroSkill(udg_Kalifas, 'A00S')
call SelectHeroSkill(udg_Kalifas, 'A00S')
call SelectHeroSkill(udg_Kalifas, 'A00R')
call SelectHeroSkill(udg_Kalifas, 'A00V')
call SelectHeroSkill(udg_Kalifas, 'A00W')
set udg_GameLevelDisplay = "Hard Level"
call CreateItemDrops() //ItemSetCreation
endif
call TriggerExecute(gg_trg_CinematicIntro)
endfunction
//This should run before intro cinematic
private function DialogSetup takes nothing returns nothing
set d = d.create("Choose Level", function LevelPick)
set normal = d.addButton("Normal", 1)
set hard = d.addButton("Hard", 2)
call d.displayForAll()
call DestroyTimer(GetExpiredTimer())
endfunction
/******************************************************
/ SKIP CINEMATICS SETUP:
*******************************************************/
private function SkipCinSetupDia takes nothing returns nothing
if cin.clickedButton(yes) then
set udg_SkipCinematics = true
endif
call TimerStart(CreateTimer(), 0, false, function DialogSetup)
endfunction
private function SkipCinSetup takes nothing returns nothing
set cin = cin.create("Skip Cinematics?", function SkipCinSetupDia)
set yes = cin.addButton("Yes", 1)
set no = cin.addButton("No", 2)
call cin.displayForAll()
call DestroyTimer(GetExpiredTimer())
endfunction
/******************************************************
/ FURBOLG DIALOG: Starts after enters furbolg region
*******************************************************/
private function FurbolgQuestPick takes nothing returns nothing
if furbolg.clickedButton(kill) then
set udg_QuestStatus = 1
elseif furbolg.clickedButton(investigate) then
set udg_QuestStatus = 2
endif
endfunction
/******************************************************
/ CENTAUR ATTAKCS: When Lyric enters centaur region
*******************************************************/
private function CentaursAttackPick takes nothing returns nothing
if centaurs.clickedButton(bosses) then
set udg_CentaurPickAttack = true
endif
call TriggerExecute(gg_trg_CentaurBossesAttack)
endfunction
/******************************************************
/ API: calls from triggers
*******************************************************/
function CentaursQuest takes nothing returns nothing
set centaurs = centaurs.create("Warning: Centaur Territory", function CentaursAttackPick)
set bosses = centaurs.addButton("Boss Attacks", 1)
set norm = centaurs.addButton("First Wave Attacks", 2)
call centaurs.displayForAll()
endfunction
function FurbolgInvestigate takes nothing returns nothing
set furbolg = furbolg.create("What do you want to do?", function FurbolgQuestPick)
set kill = furbolg.addButton("Kill the Creatures", 1)
set investigate = furbolg.addButton("Investigate", 2)
call furbolg.displayForAll()
endfunction
function SkipCinematics takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function SkipCinSetup)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SetUnitStates initializer init uses SetUnitMaxState
globals
constant real ADD_LIFE = 350 //for lyric and emek
constant real ENEMY_ADD_LIFE = 250
constant real CLAWGREK_ADD_LIFE = 3500
constant real BATUSHK_ADD_LIFE = 4000
constant real UZURAPOTH_ADD_LIFE = 4000
constant real KALIFAS_ADD_LIFE = 7000
constant real SALG_ADD_LIFE = 2500
constant real ZEKAON_ADD_LIFE = 2500
private integer DIFFICULTY
endglobals
private function LifeManaOfNonHeroes takes real addLife returns nothing
local unit first
call GroupEnumUnitsInRect(TempG, bj_mapInitialPlayableArea, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if not IsUnitType(first, UNIT_TYPE_HERO) then
call AddUnitMaxState(first, UNIT_STATE_MAX_LIFE, addLife)
if GetUnitState(first, UNIT_STATE_MANA) > 0 then
call AddUnitMaxState(first, UNIT_STATE_MAX_MANA, 400)
endif
endif
call GroupRemoveUnit(TempG, first)
endloop
endfunction
private function SetupUnitState takes nothing returns nothing
if DIFFICULTY==0 then
//Normal Units
call LifeManaOfNonHeroes(ENEMY_ADD_LIFE)
//Mini Bosses
call AddUnitMaxState(udg_Salg, UNIT_STATE_MAX_LIFE, SALG_ADD_LIFE)
call AddUnitMaxState(udg_Zekaon, UNIT_STATE_MAX_LIFE, ZEKAON_ADD_LIFE)
//Bosses
call AddUnitMaxState(udg_Clawgrek, UNIT_STATE_MAX_LIFE, CLAWGREK_ADD_LIFE)
call AddUnitMaxState(udg_Batushk, UNIT_STATE_MAX_LIFE, BATUSHK_ADD_LIFE)
call AddUnitMaxState(udg_Uruzapoth, UNIT_STATE_MAX_LIFE, UZURAPOTH_ADD_LIFE)
call AddUnitMaxState(udg_Kalifas, UNIT_STATE_MAX_LIFE, KALIFAS_ADD_LIFE)
else
call LifeManaOfNonHeroes(ENEMY_ADD_LIFE * 2)
call AddUnitMaxState(udg_Salg, UNIT_STATE_MAX_LIFE, SALG_ADD_LIFE + 1000)
call AddUnitMaxState(udg_Zekaon, UNIT_STATE_MAX_LIFE, ZEKAON_ADD_LIFE + 1000)
call AddUnitMaxState(udg_Clawgrek, UNIT_STATE_MAX_LIFE, CLAWGREK_ADD_LIFE + 1000)
call AddUnitMaxState(udg_Batushk, UNIT_STATE_MAX_LIFE, BATUSHK_ADD_LIFE + 1000)
call AddUnitMaxState(udg_Uruzapoth, UNIT_STATE_MAX_LIFE, UZURAPOTH_ADD_LIFE + 1000)
call AddUnitMaxState(udg_Kalifas, UNIT_STATE_MAX_LIFE, KALIFAS_ADD_LIFE + 1500)
endif
endfunction
private function Enters takes nothing returns nothing
if DIFFICULTY==0 then
call AddUnitMaxState(GetTriggerUnit(), UNIT_STATE_MAX_LIFE, ENEMY_ADD_LIFE)
else
call AddUnitMaxState(GetTriggerUnit(), UNIT_STATE_MAX_LIFE, ENEMY_ADD_LIFE * 2)
endif
//call BJDebugMsg("From SetUnitStates "+GetUnitName(GetTriggerUnit()))
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterEnterRectSimple(t, bj_mapInitialPlayableArea)
call TriggerAddAction(t, function Enters)
set t = null
endfunction
function SetupUnitStates takes integer difficulty returns nothing
set DIFFICULTY = difficulty //0=normal or 1=hard
call SetupUnitState()
call AddUnitMaxState(udg_Lyric, UNIT_STATE_MAX_LIFE, ADD_LIFE)
call AddUnitMaxState(udg_Lyric, UNIT_STATE_MAX_MANA, 400)
call AddUnitMaxState(udg_Emek, UNIT_STATE_MAX_LIFE, ADD_LIFE)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ItemSetCreation uses ItemTable
globals
private ItemTable healing
private ItemTable good
private ItemTable powerups
endglobals
function AddHealingItems takes unit u returns nothing
call healing.addUnit(u)
endfunction
function AddGoodItems takes unit u returns nothing
call good.addUnit(u)
endfunction
function AddPowerupItems takes unit u returns nothing
call powerups.addUnit(u)
endfunction
//20% for normal, 10% for hard
function CreateItemDrops takes nothing returns nothing
if udg_Difficulty==1 then
set ITEM_DROP_CHANCE = ITEM_DROP_CHANCE/2
endif
set healing = healing.create(ITEM_DROP_CHANCE)
set powerups = powerups.create(ITEM_DROP_CHANCE - 2)
set good = good.create(ITEM_DROP_CHANCE - 3)
call healing.addItemType('rhe1') //lesser healing
call healing.addItemType('rman') //rune of mana
call powerups.addItemType('tdex') //agility
call powerups.addItemType('tint') //intelligence
call powerups.addItemType('tstr') //strength
call good.addItemType('sreg')
call good.addItemType('pman')
call good.addItemType('rag1') //agility + 3
call good.addItemType('rin1') //intelligence + 3
call good.addItemType('rst1') //strength + 3
endfunction
endlibrary
//TESH.scrollpos=78
//TESH.alwaysfold=0
library CaravanMovement uses SimpleFunctions, EscortLite
globals
private timer t = CreateTimer()
private real lap = 0.3
private real maxdist = 490000 //700*700, caravan will stop if lyric is too far
private real distX = 0
private real offsetfromcaravan = 250
endglobals
private function StopMoving takes nothing returns nothing
if GetUnitCurrentOrder(udg_Caravan)==MOVE then
call IssueImmediateOrderById(udg_Caravan, STOP)
//call BJDebugMsg("CARAVAN STOPPING")
endif
endfunction
private function DistanceFromCheckpoint takes real x, real y returns real
return SquareRoot(GetDistance(GetUnitX(udg_Caravan), GetUnitY(udg_Caravan), x, y))
endfunction
private function CaravanRoute takes real x, real y returns nothing
call IssuePointOrderById(udg_Caravan, MOVE, x, y)
//call BJDebugMsg("Going to checkpoint "+I2S(CAR_CHECKPOINT))
if DistanceFromCheckpoint(x, y) < 100 then
set CAR_CHECKPOINT = CAR_CHECKPOINT + 1
endif
endfunction
private function CaravanCheckpoints takes nothing returns nothing
/*
/ caravan moves from one checkpoint to the other
*/
if CAR_CHECKPOINT==1 then
call CaravanRoute(6900, -3433)
elseif CAR_CHECKPOINT==2 then
call CaravanRoute(7020, -1670)
elseif CAR_CHECKPOINT==3 then
call CaravanRoute(6450, -550)
elseif CAR_CHECKPOINT==4 then
call CaravanRoute(6836, 1370)
elseif CAR_CHECKPOINT==5 then
/*
/ kill furbolgs and centaur attacks at this point if Centaur Khan is still alive
/ horn will blow if Centaur Khan is alive
*/
call CaravanRoute(6300, 2359)
elseif CAR_CHECKPOINT==6 then
call CaravanRoute(4200, 3220)
elseif CAR_CHECKPOINT==7 then
call CaravanRoute(2700, 3580)
elseif CAR_CHECKPOINT==8 then
call CaravanRoute(600, 3000)
elseif CAR_CHECKPOINT==9 then
/*
/ Bandits will attack at this point
*/
call CaravanRoute(-800, 90)
elseif CAR_CHECKPOINT==10 then
call CaravanRoute(-2815, 280)
elseif CAR_CHECKPOINT==11 then
call CaravanRoute(-3650, -700)
elseif CAR_CHECKPOINT==12 then
call CaravanRoute(-4210, -2600)
elseif CAR_CHECKPOINT==13 then
call CaravanRoute(-5200, -3200)
elseif CAR_CHECKPOINT==14 then
call CaravanRoute(-6300, -3130)
elseif CAR_CHECKPOINT==15 then
call CaravanRoute(-7160, -2300)
elseif CAR_CHECKPOINT==16 then
call CaravanRoute(-7450, -1660)
elseif CAR_CHECKPOINT==17 then
call CaravanRoute(-6860, 120)
elseif CAR_CHECKPOINT==18 then
call CaravanRoute(-7030, 2750)
elseif CAR_CHECKPOINT==19 then
call PauseTimer(t)
call DestroyTimer(t)
//Bandit battle
endif
endfunction
private function CaravanMoving takes nothing returns nothing
if CARAVAN_ROUTE_TEST then
call CaravanCheckpoints()
else
if udg_CaravanMoving and NoEnemyUnits(udg_Lyric, NO_ENEMY_AOE) and NoEnemyUnits(udg_Caravan, NO_ENEMY_AOE) then
if UnitAlive(udg_Lyric) and (GetDistanceFromUnit(udg_Lyric, udg_Caravan) < maxdist) then
call CaravanCheckpoints()
//call BJDebugMsg("caravan moving")
else
call StopMoving()
//call BJDebugMsg("caravan STOP")
endif
else
call StopMoving()
//call BJDebugMsg("caravan STOP, CARAVAN_MOVE is false")
endif
endif
endfunction
//This should run after intro cinematic
function CarMovSetup takes unit car returns nothing
local unit first
local integer i = 0
call GroupEnumUnitsInRange(TempG, GetUnitX(udg_Caravan), GetUnitY(udg_Caravan), 1000, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitAlive(first) and GetOwningPlayer(first)==Player(1) then
call RemoveGuardPosition(first)
endif
call GroupRemoveUnit(TempG, first)
endloop
call EscortLite.addEscort(udg_Lyric, udg_Emek, 250, 0, true) //emek escorts lyric
if ENABLE_CARAVAN_ESCORTS then
call EscortLite.addEscort(car, udg_Knight[1], offsetfromcaravan, 0, false)
call EscortLite.addEscort(car, udg_Knight[2], offsetfromcaravan, 90, false)
call EscortLite.addEscort(car, udg_Knight[3], offsetfromcaravan, 180, false)
call EscortLite.addEscort(car, udg_Knight[4], offsetfromcaravan, 270, false)
else
call SetUnitInvulnerable(car, true)
endif
if TEST_ENEMY then
loop
call CreateUnit(ENEMY, ENEMY_TYPE, 6844, -2479, 0)
set i = i+1
exitwhen i==8
endloop
endif
set i = 0
if CREATE_ALLIES then
loop
call CreateUnit(Player(0), ALLY_TYPE, 6251, -3200, 0)
set i = i+1
exitwhen i==10
endloop
endif
call TimerStart(t, lap, true, function CaravanMoving)
endfunction
function PauseTimerCaravan takes boolean p returns nothing
if udg_CaravanMoving then
call StopMoving()
endif
if p then
call PauseTimer(t)
else
call ResumeTimer(t)
endif
endfunction
endlibrary
//TESH.scrollpos=79
//TESH.alwaysfold=0
library EnemyEngages uses EngageLite, ItemSetCreation
globals
private unit u
private player Enemy = Player(11)
private real WolfCreationX = 9250
private real WolfCreationY = 80
private real TrollCreationX = 4657
private real TrollCreationY = 852
private real CentaurCreationX1 = 9050 //lower right
private real CentaurCreationY1 = -5000 //lower right
private real CentaurCreationX2 = -970 //in hut
private real CentaurCreationY2 = -4600 //in hut
/********************************
/ CENTAURS
*********************************/
private integer CEN8_KHAN = 'ncnk'
private integer CEN5_SOR = 'ncks'
private integer CEN4_OUT = 'ncen'
private integer CEN4_IMP = 'ncim'
private integer CEN2_ARC = 'ncea'
private integer CEN2_DRU = 'ncer'
/********************************
/ TROLLS
*********************************/
private integer TRL6_WAR = 'nftk'
private integer TRL4_HPR = 'nfsh'
private integer TRL4_BER = 'nftb'
private integer TRL3_TRA = 'nftt'
private integer TRL2_SPR = 'nfsp'
private integer TRL2_FTR = 'nftr'
/********************************
/ WOLVES
*********************************/
private integer WOLF2_TIMBER = 'nwlt'
private integer WOLF4_GIANT = 'nwlg'
private integer WOLF6_DIRE = 'nwld'
endglobals
private function CreateEnemy takes integer UnitID, real x, real y, integer qty returns nothing
local integer i = 0
loop
set u = CreateUnit(Enemy, UnitID, x, y, 0)
if GetRandomInt(1, 2)==1 then
call AddHealingItems(u)
else
call AddPowerupItems(u)
endif
call EngageSingle(u, udg_Caravan)
set i = i+1
exitwhen i==qty
endloop
endfunction
private function CreateEnemyOne takes integer UnitID, real x, real y returns nothing
set u = CreateUnit(Enemy, UnitID, x, y, 0)
if GetRandomInt(1, 2)==1 then
call AddHealingItems(u)
else
call AddGoodItems(u)
endif
call EngageSingle(u, udg_Caravan)
endfunction
/**************************************
/ WOLVES - Caravan Enters
***************************************/
function Wolves takes nothing returns nothing
call EngageGroupForPlayer(Enemy, udg_Caravan, 9130, 530, 600)
call CreateEnemy(WOLF4_GIANT, WolfCreationX, WolfCreationY, 4)
if udg_Difficulty==1 then
call CreateEnemy(WOLF4_GIANT, WolfCreationX, WolfCreationY, 2)
call CreateEnemyOne(WOLF6_DIRE, WolfCreationX, WolfCreationY)
endif
endfunction
/**************************************
/ TROLLS - Lyric Enters
***************************************/
function Trolls takes nothing returns nothing
call CreateEnemy(TRL2_SPR, TrollCreationX, TrollCreationY, 2)
call CreateEnemy(TRL2_FTR, TrollCreationX, TrollCreationY, 2)
call CreateEnemy(TRL3_TRA, TrollCreationX, TrollCreationY, 2)
call CreateEnemy(TRL4_BER, TrollCreationX, TrollCreationY, 1)
if udg_Difficulty==1 then
call CreateEnemy(TRL4_HPR, TrollCreationX, TrollCreationY, 2)
call CreateEnemyOne(TRL6_WAR, TrollCreationX, TrollCreationY)
endif
endfunction
/**************************************
/ CENTAURS - Lyric Enters
***************************************/
function CentaurFirstWave takes nothing returns nothing
call QuestKillCentaurBosses()
// X1/Y1 in lower right or player 1 start location
// X2/Y2 in centaur bosses hut
call CreateEnemy(CEN2_ARC, CentaurCreationX2, CentaurCreationY2, 2)
call CreateEnemy(CEN2_DRU, CentaurCreationX2, CentaurCreationY2, 2)
call CreateEnemy(CEN2_ARC, CentaurCreationX2, CentaurCreationY2, 2)
if udg_Difficulty==1 then
call CreateEnemy(CEN2_ARC, CentaurCreationX1, CentaurCreationY1, 3)
call CreateEnemyOne(CEN4_IMP, CentaurCreationX1, CentaurCreationY1)
call CreateEnemyOne(CEN4_OUT, CentaurCreationX1, CentaurCreationY1)
call CreateEnemyOne(CEN4_OUT, CentaurCreationX2, CentaurCreationY2)
call CreateEnemyOne(CEN4_OUT, CentaurCreationX2, CentaurCreationY2)
endif
endfunction
/**************************************
/ RIVER MONSTERS - Lyric Enters
***************************************/
function RiverMonsters takes nothing returns nothing
call EngageGroupForPlayer(Enemy, udg_Caravan, 630, 4667, 1000)
endfunction
/**************************************
/ BANDITS - Caravan Enters
***************************************/
function Bandits takes nothing returns nothing
//bandit huts
call CreateEnemy('nban', 2368, 80, 4) //level 1
call CreateEnemy('nbrg', 2368, 80, 2) //level 2
call CreateEnemy('nrog', 2368, 80, 3) //level 3
call CreateEnemy('nass', 2368, 80, 2) //level 4
if udg_Difficulty==1 then
call CreateEnemy('nass', 2368, 80, 2) //level 4
call CreateEnemy('nenf', 2368, 80, 2) //level 5
endif
endfunction
/**************************************
/ TESTS - THIS IS NOT NEEDED
***************************************/
function CentaurTestFirstAttack takes nothing returns nothing
call CreateEnemy(CEN2_ARC, CentaurCreationX2, CentaurCreationY2, 2)
call CreateEnemy(CEN2_DRU, CentaurCreationX2, CentaurCreationY2, 2)
call CreateEnemy(CEN2_ARC, CentaurCreationX2, CentaurCreationY2, 2)
call CreateEnemyOne(CEN4_IMP, CentaurCreationX1, CentaurCreationY1)
if udg_Difficulty==1 then
call CreateEnemyOne(CEN4_OUT, CentaurCreationX1, CentaurCreationY1)
call CreateEnemyOne(CEN5_SOR, CentaurCreationX1, CentaurCreationY1)
call CreateEnemyOne(CEN5_SOR, CentaurCreationX2, CentaurCreationY2)
endif
endfunction
endlibrary
//TESH.scrollpos=56
//TESH.alwaysfold=0
library Quests uses QuestUtils
globals
QuestUtils gamelevel
QuestUtils dock
QuestUtils centaurs
QuestItem lastCentaurs
QuestUtils killBatushk
QuestUtils bandits
QuestUtils harpies
QuestItem harCreature
QuestItem harKill
QuestUtils tip01
//QuestUtils tip02
endglobals
/*********************************************************
* Functions for quest update
**********************************************************/
function QuestFinish takes QuestUtils var returns nothing
set var.completed = true
endfunction
function QuestFailed takes QuestUtils var returns nothing
set var.failed = true
endfunction
function QuestItemCompleted takes QuestItem var returns nothing
set var.completed = true
endfunction
/*********************************************************
* Just displays the game mode
**********************************************************/
function GameLevelInfo takes nothing returns nothing
set gamelevel = gamelevel.create(false)
set gamelevel["Quest Level"] = "|cff00FFFF" + GAME_VERSION + "|r" + " - " + udg_GameLevelDisplay
set gamelevel.questIcon = "ReplaceableTextures\\CommandButtons\\BTNEngineeringUpgrade.blp"
endfunction
/*********************************************************
* Functions for quest update
**********************************************************/
function QuestMain takes nothing returns nothing
set dock = dock.create(true)
set dock["Sail"] = "Escort the caravan to the ship dock where you deliver the goods to a greedy king, Agbon.
- The Caravan must survive.
- Prince Lyric must survive.
- Emek must survive."
set dock.questIcon = "ReplaceableTextures\\CommandButtons\\BTNHumanTransport.blp"
endfunction
function QuestKillCentaurBosses takes nothing returns nothing
set tip01 = tip01.create(false)
set tip01["Kill the Centaur Bosses"] = "TIP: Kill the Centaur Bosses for easier journey."
set tip01.questIcon = "ReplaceableTextures\\CommandButtons\\BTNReincarnation.blp"
endfunction
function QuestKillBatuschk takes nothing returns nothing
set killBatushk = killBatushk.create(false)
set killBatushk["Kill the Sea Giant Behemoth"] = "Kill Batuschk, a behemoth sea giant to free Clawgrek's people."
set killBatushk.questIcon = "ReplaceableTextures\\CommandButtons\\BTNSeaGiant.blp"
endfunction
function QuestSurviveCentaurs takes nothing returns nothing
set centaurs = centaurs.create(false)
set centaurs["Wrath of the Centaurs"] = "Survive the onslaught of the centaurs for " + I2S(R2I(udg_CentaurSurviveTimer/60)) + " minutes."
set centaurs.questIcon = "ReplaceableTextures\\CommandButtons\\BTNCentaurKhan.blp"
endfunction
function QuestBandits takes nothing returns nothing
set bandits = bandits.create(true)
set bandits["Passage"] = "Kill the Bandits for you to enter the dock."
set bandits.questIcon = "ReplaceableTextures\\CommandButtons\\BTNBanditLord.blp"
endfunction
function QuestHarpiesWithCreature takes nothing returns nothing
set harpies = harpies.create(false)
set harpies["Air Trouble"] = "Search for the an ancient creature that holds the power to lure flying units down."
set harpies.questIcon = "ReplaceableTextures\\CommandButtons\\BTNHarpy.blp"
set harCreature = harCreature.create(harpies, "Search for an ancient creature and slay it.")
set harKill = harKill.create(harpies, "Kill the harpies.")
endfunction
function QuestHarpies takes nothing returns nothing
set harpies = harpies.create(false)
set harpies["Air Trouble"] = "Bring the harpies down and slay the all."
set harpies.questIcon = "ReplaceableTextures\\CommandButtons\\BTNHarpy.blp"
set harKill = harKill.create(harpies, "Kill the harpies.")
endfunction
endlibrary
//TESH.scrollpos=96
//TESH.alwaysfold=0
library Elevate initializer init uses T32, IsUnitChanneling
globals
private constant integer SPELL_ID = 'A00A'
private constant integer DUMMY_ID = 'h001'
/***********************************************
* DUMMY_SPELL_ID should synchronize with ORDER_ID, else this will not cast
************************************************/
private constant integer DUMMY_SPELL_ID = 'A00B' //based on firebolt
private constant integer ORDER_ID = 852231 //based on firebolt order
/***********************************************
* CONFIGURABLE VARIABLES:
************************************************/
private constant real MAX_HEIGHT = 400
private constant real ELEVATE_SPEED = 1
private constant real CAST_INTERVAL = 1
private constant real CAST_HEIGHT_DELAY = 50
private constant string SFX_LIGHTNING = "MFPB"
/***********************************************
* NON-CONFIGURABLE VARIABLES:
************************************************/
private location LOC = Location(0,0)
private group TempG = CreateGroup()
endglobals
/******************************************************
* CONFIGURABLES:
*******************************************************/
private function Targetable takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private function GetUnitZ takes unit u returns real
call MoveLocation(LOC, GetUnitX(u), GetUnitY(u))
return GetLocationZ(LOC)
endfunction
private struct Elevate
unit u
unit tar
unit dummyCaster
real heightU
real heightTar
real heightTarConst
real xU
real yU
real xTar
real yTar
real castInterval
boolean isGoingUp
boolean isSpellActive
lightning lg
player pl
method moveZ takes nothing returns nothing
call SetUnitFlyHeight(.tar, .heightTar, 0)
call SetUnitFlyHeight(.dummyCaster, .heightTar, 0)
call MoveLightningEx(.lg, true, .xU, .yU, GetUnitZ(.u) + .heightU, .xTar, .yTar, GetUnitZ(.tar) + .heightTar)
endmethod
private method periodic takes nothing returns nothing
local unit first
local real xCaster
local real yCaster
if UnitAlive(.tar) and .isSpellActive and IsUnitChanneling(.u) then
/*********************************************
* Code for dummy caster
**********************************************/
set .castInterval = .castInterval + 0.03125
if .castInterval > CAST_INTERVAL then
set .castInterval = 0
if .heightTar > CAST_HEIGHT_DELAY then
call GroupEnumUnitsInRange(TempG, .xTar, .yTar, 500, null)
loop
set first = FirstOfGroup(TempG)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, .pl) and first!=.tar and Targetable(first) then
call IssueTargetOrderById(.dummyCaster, ORDER_ID, first)
endif
call GroupRemoveUnit(TempG, first)
endloop
endif
endif
/*********************************************
* Code for elevating
**********************************************/
if .isGoingUp then
if MAX_HEIGHT > .heightTar then
set .heightTar = .heightTar + ELEVATE_SPEED
call this.moveZ()
else
set .isGoingUp = false
endif
else
set .heightTar = .heightTar - ELEVATE_SPEED
if .heightTar > .heightTarConst then
call this.moveZ()
else
set .isSpellActive = false
call IssuePointOrderById(.u, 851983, .xU, .yU)
endif
endif
else
call KillUnit(.dummyCaster)
call SetUnitFlyHeight(.tar, GetUnitDefaultFlyHeight(.tar), 0)
call PauseUnit(.tar, false)
call SetUnitInvulnerable(.tar, false)
call DestroyLightning(.lg)
set .u = null
set .tar = null
set .dummyCaster = null
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method cast takes nothing returns nothing
local thistype this = create()
set .u = GetTriggerUnit()
set .tar = GetSpellTargetUnit()
set .pl = GetTriggerPlayer()
set .heightU = GetUnitFlyHeight(.u)
if not IsUnitType(.u, UNIT_TYPE_FLYING) then
set .heightU = 70
endif
set .heightTar = GetUnitFlyHeight(.tar) //adjustable height
set .heightTarConst = GetUnitFlyHeight(.tar) //constant height
set .xU = GetUnitX(.u)
set .yU = GetUnitY(.u)
set .xTar = GetUnitX(.tar)
set .yTar = GetUnitY(.tar)
set .lg = AddLightningEx(SFX_LIGHTNING, true, .xU, .yU, GetLocationZ(LOC) + .heightU, .xTar, .yTar, .heightTar)
set .isGoingUp = true
set .isSpellActive = true
set .castInterval = 0
set .dummyCaster = CreateUnit(GetTriggerPlayer(), DUMMY_ID, .xTar, .yTar, .heightTar)
call UnitAddAbility(.dummyCaster, DUMMY_SPELL_ID)
call SetUnitAbilityLevel(.dummyCaster, DUMMY_SPELL_ID, GetUnitAbilityLevel(.u, SPELL_ID))
call SetUnitInvulnerable(.tar, true)
call PauseUnit(.tar, true)
if UnitAddAbility(.tar, 'Arav') and UnitRemoveAbility(.tar, 'Arav') then
endif
call .startPeriodic()
endmethod
endstruct
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function Elevate.cast)
endfunction
endlibrary
//TESH.scrollpos=73
//TESH.alwaysfold=0
//Spell Name: Lightning Cloud v2.2
//Made by: mckill2009
//===INSTALLATION:
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- The trigger name MUST be >>> InitTrig_LightningCloud (see the name below)
//- Copy this trigger "LightningCloud" to your trigger editor
//- Copy the custom unit and abilities... to your object editor
//- Make sure you inputed the correct raw codes of the spells and dummy
//- You can view the raw codes by pressing CTRL+D in the object editor
//- Examples of raw codes are 'A000', 'h001' etc... as written below
//- Add the ability to your hero
//===REQUIRED VARIABLES:
//- HASH = Hashtable
//- LC_TargetGrp = Group
//- LC_Group = Group
//- LC_Index = Integer
//- LC_Timer = Timer
//===CONFIGURABLES:
constant function LC_SpellId takes nothing returns integer
return 'A00D' //Raw code for the Hero ability
endfunction
constant function LC_LightningSpellId takes nothing returns integer
return 'A00C' //Raw code for the Lightning Strike ability
endfunction
constant function LC_CloudUnit takes nothing returns integer
return 'h004' //Raw code for the Cloud Unit
endfunction
constant function LC_Range takes nothing returns real
return 500. //Maximum range is 3000 or you can adjust it via object editor
endfunction
constant function LC_Duration takes integer i returns real
return 10 + i * 10. //This is the duration of the cloud and spell
endfunction
constant function LC_ATT takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
constant function LC_DAM takes nothing returns damagetype
return DAMAGE_TYPE_LIGHTNING
endfunction
constant function LC_FilterTargets takes unit u returns boolean
return not (IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitType(u, UNIT_TYPE_MECHANICAL))
endfunction
//===END OF CONFIGURABLES===
function LC_UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
function LC_FilterEnemies takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_TempU)) and LC_UnitAlive(GetFilterUnit()) and LC_FilterTargets(GetFilterUnit())
endfunction
function LC_CloudLooper takes nothing returns nothing
local unit first
local unit cloud = GetEnumUnit()
local integer ID = GetHandleId(cloud)
local unit caster = LoadUnitHandle(udg_HASH, ID, 1)
local real duration = LoadReal(udg_HASH, ID, 2)
if duration > 0 and LC_UnitAlive(caster) then
call SaveReal(udg_HASH, ID, 2 , duration - 0.03125)
call SetUnitX(cloud, GetUnitX(caster))
call SetUnitY(cloud, GetUnitY(caster))
set udg_TempU = caster
set first = GetRandomUnitInArea(GetUnitX(cloud), GetUnitY(cloud), LC_Range(), Filter(function LC_FilterEnemies))
call IssueTargetOrderById(cloud, 852119, first) //chainlightning
else
call UnitApplyTimedLife(cloud, 'BTLF', 0.01)
call FlushChildHashtable(udg_HASH, ID)
call GroupRemoveUnit(udg_LC_Group, cloud)
set udg_LC_Index = udg_LC_Index - 1
if udg_LC_Index==0 then
call PauseTimer(udg_LC_Timer)
endif
endif
set cloud = null
set caster = null
endfunction
function LC_GroupLooper takes nothing returns nothing
call ForGroup(udg_LC_Group, function LC_CloudLooper)
endfunction
function LC_OnCast takes nothing returns boolean
local unit cloud
local integer cloudID
local integer level
if GetSpellAbilityId()==LC_SpellId() then
set cloud = CreateUnit(GetOwningPlayer(GetTriggerUnit()), LC_CloudUnit() , 0, 0, 0)
set cloudID = GetHandleId(cloud)
set level = GetUnitAbilityLevel(GetTriggerUnit(), LC_SpellId())
call SaveUnitHandle(udg_HASH, cloudID, 1, GetTriggerUnit()) //saves the caster
call SaveReal(udg_HASH, cloudID, 2 , LC_Duration(level)) //saves the duration
call UnitAddAbility(cloud, LC_LightningSpellId())
call SetUnitAbilityLevel(cloud, LC_LightningSpellId(), level)
if udg_LC_Index==0 then
call TimerStart(udg_LC_Timer, 0.03125, true, function LC_GroupLooper)
endif
set udg_LC_Index = udg_LC_Index + 1
call GroupAddUnit(udg_LC_Group, cloud)
set cloud = null
endif
return false
endfunction
function InitTrig_LightningCloud takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function LC_OnCast))
set udg_HASH = InitHashtable()
set t = null
endfunction
//TESH.scrollpos=118
//TESH.alwaysfold=0
/*********************************************************
Touch of Light by The_Witcher
Edited by mckill2009
**********************************************************/
library TouchOfLight initializer Init uses T32
globals
private constant integer SPELL_ID = 'A00F'
private constant integer ORB_ID = 'h005'
private constant integer ORB_DRAIN_RANGE = 150
private constant real ORB_HEIGHT = 80
private constant real ORB_MOVE_SPEED = 10
private constant real ORB_SEARCH_DELAY = 0.2 //recommended
private constant real ORB_CREATION_DELAY = 0.5 //recommended
private constant real ORB_ALLY_FIND = 3000
private constant string HEAL_SFX = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
private constant string HEAL_SFX_TARGET = "origin"
private constant string DRAIN_SFX = "Abilities\\Spells\\Human\\Slow\\SlowCaster.mdl"
private constant string EXPLODE_SFX = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
private constant string LIGHTNING = "HWPB"
private attacktype ATK = ATTACK_TYPE_MAGIC
private damagetype DMG = DAMAGE_TYPE_MAGIC
private unit DATA
private group g = CreateGroup()
private location loc = Location(0,0)
endglobals
private function GetOrbAmount takes integer lvl returns integer
return 2 + lvl * 2 //4, 6, 8, 10, 12
endfunction
private function GetOrbAreaSize takes integer lvl returns real
return 400. + 100 * lvl //500, 600, 700, 800, 900
endfunction
private function GetDrainDamage takes integer lvl returns real
return 3. + lvl * 3 //6, 9, 12, 15, 18
endfunction
private function GetDuration takes integer lvl returns real
return 10. //3. + lvl * 5 //8, 13, 16,
endfunction
private function FilterEnemies takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
private function FilterAllies takes unit u returns boolean
return not (IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endfunction
/***********************************************************
* NON-CONFIGURABLES
************************************************************/
private function AngleBetweenCoords takes real x, real y, real xx, real yy returns real
return Atan2(yy - y, xx - x)
endfunction
private function DistanceBetweenCoords takes real x , real y , real xx , real yy returns real
return SquareRoot((x-xx)*(x-xx)+(y-yy)*(y-yy))
endfunction
private function DistanceBetweenUnits takes unit a, unit b returns real
local real dx = GetUnitX(b) - GetUnitX(a)
local real dy = GetUnitY(b) - GetUnitY(a)
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit a, unit b returns real
return Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private function EnemiesOnly takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(DATA)) and UnitAlive(GetFilterUnit()) and FilterEnemies(GetFilterUnit())
endfunction
private function AlliesOnly takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(DATA)) and UnitAlive(GetFilterUnit()) /*
*/ and (GetWidgetLife(GetFilterUnit())) < (GetUnitState(GetFilterUnit(), UNIT_STATE_MAX_LIFE)) and FilterAllies(GetFilterUnit())
endfunction
private function GetTarget takes real x, real y, real range, boolexpr con returns unit
local unit a=null
local unit i
local integer b=0
call GroupClear(g)
call GroupEnumUnitsInRange(g, x, y, range, con)
loop
set i=FirstOfGroup(g)
exitwhen i==null
set b=b+1
if (GetRandomInt(1,b) == 1) then
set a = i
endif
call GroupRemoveUnit(g,i)
endloop
set bj_groupRandomCurrentPick=a
set a=null
return bj_groupRandomCurrentPick
endfunction
private struct DrainAndHeal
unit u
unit orb
unit target
real damage
real delay
real duration
real aoe
real healAoe
real xSpell
real ySpell
real drain
real heal
lightning touch
effect sfx
private method destroy takes nothing returns nothing
call KillUnit(.orb)
set .u = null
set .orb = null
set .target = null
call .deallocate()
call .stopPeriodic()
endmethod
private method periodic takes nothing returns nothing
local real xOrb = GetUnitX(.orb)
local real yOrb = GetUnitY(.orb)
local real ang
local real z
if .duration > 0 then
set .duration = .duration - T32_PERIOD
if UnitAlive(.target) then
if DistanceBetweenUnits(.orb, .target) > ORB_DRAIN_RANGE then
set ang = AngleBetweenUnits(.orb, .target)
call SetUnitX(.orb, xOrb + ORB_MOVE_SPEED * Cos(ang))
call SetUnitY(.orb, yOrb + ORB_MOVE_SPEED * Sin(ang))
else
//drain here and add sfx
call MoveLocation(loc, xOrb, yOrb)
set z = GetLocationZ(loc)
call MoveLocation(loc, GetUnitX(.target), GetUnitY(.target))
call MoveLightningEx(.touch, true, xOrb, yOrb, z + ORB_HEIGHT, GetUnitX(.target), GetUnitY(.target), GetLocationZ(loc) + GetUnitFlyHeight(.target))
call DestroyEffect(AddSpecialEffectTarget(DRAIN_SFX, .target, "origin"))
call UnitDamageTarget(.orb, .target, .damage, false, false, ATK, DMG, null)
set .heal = .heal + .damage
//nulling the target so that orb can find a new one
set .target = null
set .delay = 0
endif
else
set .delay = .delay + T32_PERIOD
if .delay > ORB_SEARCH_DELAY then
set DATA = .orb
set .target = GetTarget(.xSpell, .ySpell, .aoe, Condition(function EnemiesOnly))
call MoveLightningEx(.touch, false, 0, 0, 0, 0, 0, 0)
endif
endif
else
if .touch!=null then
call DestroyLightning(.touch)
set .touch = null
endif
//orbs get back
if UnitAlive(.u) then
if DistanceBetweenUnits(.orb, .u) > 50 then
set ang = AngleBetweenUnits(.orb, .u)
call SetUnitX(.orb, xOrb + ORB_MOVE_SPEED * Cos(ang))
call SetUnitY(.orb, yOrb + ORB_MOVE_SPEED * Sin(ang))
else
call SetWidgetLife(.u, GetWidgetLife(.u) + .heal)
call DestroyEffect(AddSpecialEffectTarget(EXPLODE_SFX, .orb, "origin"))
call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX, .u, HEAL_SFX_TARGET))
//deallocating
call .destroy()
endif
else
set DATA = .orb
set .u = GetTarget(xOrb, yOrb, ORB_ALLY_FIND, Condition(function AlliesOnly))
if .u==null then
call .destroy()
endif
endif
endif
endmethod
implement T32x
static method create takes unit orb, integer level, real x, real y returns thistype
local thistype this = allocate()
set .u = null
set .orb = orb
set .target = null
set .xSpell = x
set .ySpell = y
set .aoe = GetOrbAreaSize (level)
set .duration = GetDuration(level)
set .damage = GetDrainDamage(level)
set .touch = AddLightningEx(LIGHTNING, false, 0, 0, 0, 0, 0, 0)
set .delay = 0
set .heal = 0
call SetUnitFlyHeight(orb, ORB_HEIGHT, 0)
call .startPeriodic()
return this
endmethod
endstruct
private struct DelayCreation
unit caster
integer level
integer orbCount
real dur
real xSpell
real ySpell
private method periodic takes nothing returns nothing
if UnitAlive(.caster) and .orbCount > 0 then
set .dur = .dur + T32_PERIOD
if .dur > ORB_CREATION_DELAY then
set .orbCount = .orbCount - 1
set .dur = 0
call DrainAndHeal.create(CreateUnit(GetOwningPlayer(.caster), ORB_ID, GetUnitX(.caster), GetUnitY(.caster), 0), .level, .xSpell, .ySpell)
endif
else
//deallocating
set .caster = null
call .destroy()
call .stopPeriodic()
endif
endmethod
implement T32x
static method create takes unit caster, real x, real y returns thistype
local thistype this = allocate()
set .caster = caster
set .dur = 0
set .xSpell = x
set .ySpell = y
set .level = GetUnitAbilityLevel(caster, SPELL_ID)
set .orbCount = GetOrbAmount(.level)
call .startPeriodic()
return this
endmethod
endstruct
private function Cast takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call DelayCreation.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerAddCondition(t,Condition(function Cast))
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
set t = null
endfunction
endlibrary
//TESH.scrollpos=6
//TESH.alwaysfold=0
/***************************************************************
Healing Arcs v1.3
by mckill2009
****************************************************************
REQUIRED LIBRARIES:
- SpellEffectEvent by Bribe
- Table by Bribe
- DamageEvent by looking_for_help
****************************************************************/
library HealingArcs initializer init uses SpellEffectEvent, Table, DamageEvent
globals
/***********************************************************
* RAW CODES: Press CTRL+D view raw codes from object editor
************************************************************/
private constant integer SPELL_ID = 'A002' //holy light ID
private constant integer DUMMY_ID = 'h001'
private constant integer BOLT_SPELL_ID = 'A006' //firebolt ID with arc
private constant integer BOLT_ORDER_ID = 852231 //firebolt order ID
/***********************************************************
* CONFIGURABLE GLOBALS
************************************************************/
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_DEATH
/***********************************************************
* NON-CONFIGURABLE GLOBALS
************************************************************/
private group g = CreateGroup()
private unit dummy
private Table heal
endglobals
/***********************************************************
* CONFIGURABLE FUNCTIONS
************************************************************/
//Area of effect when searching allies to heal
private function GetAoE takes integer level returns real
return 200. * level + 300 //500, 700, 900, 1100, 1300
endfunction
//Targets only 1 enemy
private function GetDamageAmount takes integer level returns real
return 25. * level + 25 //50, 75, 100, 125, 150
endfunction
//Heals the main ally target
private function GetHealAmount takes integer level returns real
return 50. * level + 50 //100, 150, 200, 250, 300
endfunction
//Heal Amount of the allies nearby
private function GetHealAmountArc takes integer level returns real
return 50. * level + 50 //100, 150, 200, 250, 300
endfunction
private function UnitFilter takes unit u returns boolean
return GetWidgetLife(u) < GetUnitState(u, UNIT_STATE_MAX_LIFE) /*
*/ and not (IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endfunction
/***********************************************************
* NON-CONFIGURABLE FUNCTIONS
************************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private function ArcLands takes nothing returns nothing
if PDDS.source==dummy then
call SetWidgetLife(PDDS.target, GetWidgetLife(PDDS.target) + heal.real[GetHandleId(PDDS.target)])
call heal.remove(GetHandleId(PDDS.target))
endif
endfunction
private function Cast takes nothing returns nothing
local unit first
local unit u = GetSpellTargetUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
local real healAmt = GetHealAmount(level)
local real healAmtArc = GetHealAmountArc(level)
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call SetUnitOwner(dummy, GetTriggerPlayer(), false)
call SetUnitFlyHeight(dummy, GetUnitFlyHeight(u), 0)
if IsUnitEnemy(u, GetTriggerPlayer()) then
call UnitDamageTarget(GetTriggerUnit(), u, GetDamageAmount(level), false, false, ATK, DMG, null)
else
call SetWidgetLife(u, GetWidgetLife(u) + healAmt)
endif
call GroupEnumUnitsInRange(g, x, y, GetAoE(level), null)
loop
set first = FirstOfGroup(g)
exitwhen first==null
if UnitAlive(first) and not IsUnitEnemy(first, GetTriggerPlayer()) and UnitFilter(first) then
set heal.real[GetHandleId(first)] = healAmtArc
call IssueTargetOrderById(dummy, BOLT_ORDER_ID, first)
endif
call GroupRemoveUnit(g, first)
endloop
call SetUnitOwner(dummy, Player(15), false)
set u = null
endfunction
private function init takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function Cast)
call AddDamageHandler(function ArcLands)
set dummy = CreateUnit(Player(15), DUMMY_ID, 0,0,0)
call UnitRemoveAbility(dummy, 'Amov')
call UnitAddAbility(dummy, BOLT_SPELL_ID)
set heal = Table.create()
endfunction
endlibrary
//TESH.scrollpos=18
//TESH.alwaysfold=0
library Conflict initializer init uses Table, RegisterPlayerUnitEvent, RandomUnit
globals
private constant integer SPELL_ID = 'A007'
private constant integer DUMMY_ID = 'h001'
private constant integer POS_ID = 'A008' //inner fire
private constant integer NEG_ID = 'A009' //slow
private constant integer POS_BUFF = 'Binf' //inner fire
private constant integer NEG_BUFF = 'Bslo' //slow
private constant integer POS_ORDER_ID = 852066
private constant integer NEG_ORDER_ID = 852075
private constant real INTERVAL = 0.5
/**************************************************
* NON-ONFIGURABLES
***************************************************/
private Table pos
private Table neg
private Table learn //used by Hero only
//Indexing
private timer periodic = CreateTimer()
private integer allocator = 0
private integer instance = 0
private integer array indexSize
private integer array instanceLoop
private integer DATA
//Variables
private group g = CreateGroup()
private unit dummy
private unit array hero
endglobals
/**************************************************
* CONFIGURABLES
***************************************************/
private function GetAoe takes integer level returns real
return 100. * level + 200 //300, 400, 500, 600, 700
endfunction
private function GetChance takes integer level returns integer
return 10 * level + 10 //20, 30, 40, 50, 60 percent
endfunction
private function GetTargets takes unit u returns boolean
return not (IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MECHANICAL) or IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE))
endfunction
/**************************************************
* NON-CONFIGURABLES
***************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private function GetTarget takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and GetTargets(GetFilterUnit())
endfunction
/**************************************************
* SIMPLE INDEXING
***************************************************/
private function GetIndex takes nothing returns integer
local integer TempIndex = indexSize[0]
if TempIndex==0 then
set allocator = allocator + 1
set TempIndex = allocator
else
set indexSize[0] = indexSize[TempIndex]
endif
return TempIndex
endfunction
private function RemoveIndex takes integer i returns nothing
set indexSize[i] = indexSize[0]
set indexSize[0] = i
endfunction
private function Cast takes unit target, integer orderID, integer dat returns nothing
call PauseUnit(dummy, false)
call SetUnitOwner(dummy, GetOwningPlayer(hero[dat]), false)
call SetUnitX(dummy, GetUnitX(hero[dat]))
call SetUnitY(dummy, GetUnitY(hero[dat]))
call IssueTargetOrderById(dummy, orderID, target)
endfunction
private function EndCast takes nothing returns nothing
if GetTriggerUnit()==dummy then
call SetUnitOwner(dummy, Player(15), false)
call PauseUnit(dummy, true)
endif
endfunction
private function Periodic takes nothing returns nothing
local unit target
local boolean check
local integer random
local integer TempIndex
local integer i = 0
local integer level
local real x
local real y
loop
set i = i+1
set TempIndex = instanceLoop[i]
if UnitAlive(hero[TempIndex]) then
set level = GetUnitAbilityLevel(hero[TempIndex], SPELL_ID)
set x = GetUnitX(hero[TempIndex])
set y = GetUnitY(hero[TempIndex])
set check = false
call GroupEnumUnitsInRange(g, x, y, GetAoe(level), null)
loop
set target = FirstOfGroup(g)
exitwhen target==null
if UnitAlive(target) and IsUnitEnemy(target, GetOwningPlayer(hero[TempIndex])) and GetTargets(target) then
set check = true
exitwhen check
endif
call GroupRemoveUnit(g, target)
endloop
if check then
if GetRandomInt(1, 100) < GetChance(level) then
set target = GetRandomUnitInArea(x, y, GetAoe(level), Filter(function GetTarget))
if target!=null then
if not IsUnitEnemy(target, GetOwningPlayer(hero[TempIndex])) and GetUnitAbilityLevel(target, POS_BUFF)==0 then
call Cast(target, POS_ORDER_ID, TempIndex)
elseif GetUnitAbilityLevel(target, NEG_BUFF)==0 then
call Cast(target, NEG_ORDER_ID, TempIndex)
endif
endif
endif
set target = null
endif
endif
exitwhen i==instance
endloop
endfunction
private function Learn takes nothing returns nothing
local unit u
local integer id
local integer TempIndex
if GetLearnedSkill()==SPELL_ID then
set u = GetTriggerUnit()
set id = GetHandleId(u)
if not learn.has(id) then
set learn[id] = 0
set TempIndex = GetIndex()
set hero[TempIndex] = u
if instance==0 then
call TimerStart(periodic, INTERVAL, true, function Periodic)
endif
set instance = instance + 1
set instanceLoop[instance] = TempIndex
endif
set u = null
endif
endfunction
private function init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function Learn)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_ENDCAST, function EndCast)
set pos = Table.create()
set neg = Table.create()
set learn = Table.create()
set dummy = CreateUnit(Player(15), DUMMY_ID, 0, 0, 0)
call PauseUnit(dummy, true)
call UnitAddAbility(dummy, 'Amov')
call UnitAddAbility(dummy, 'Arav')
call UnitAddAbility(dummy, POS_ID)
call UnitAddAbility(dummy, NEG_ID)
call SetUnitInvulnerable(dummy, true)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ManaOrb //requires Table and DamageEvent
globals
//The id of the spell
private constant integer SPELL_ID = 'A00G' //channel, absorb orderID=852529
private constant integer DUMMY_SPELL_ID = 'A00E' //inner fire
private constant integer ORDER_ID = 852066 //inner fire
private constant integer DUMMY_ID = 'h001'
private unit DUMMY
//The fps of the spell
private constant real FPS = 0.0312500
//The id of the buff
private constant integer BUFF_ID = 'B002'
private constant string SFX = "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"
endglobals
private constant function ManaReplenish takes integer level returns real
return 30. * level + 40 //70,100,130,160,190
endfunction
private constant function Stack takes integer level returns integer
return 3+level //3,6,9,12,15
endfunction
private constant function Duration takes integer level returns real
return 15.
endfunction
private struct MO
unit targ
integer stacks
real mana
real temp
static integer dindex
static thistype array data
static timer period
static Table tb
method destroy takes nothing returns nothing
call tb.remove(GetHandleId(this.targ))
set this.targ = null
call this.deallocate()
endmethod
static method handler takes nothing returns nothing
local thistype this
local real man
if GetUnitAbilityLevel(PDDS.target, BUFF_ID) > 0 then
set man = GetUnitState(PDDS.target, UNIT_STATE_MANA)
if GetUnitState(PDDS.target, UNIT_STATE_MAX_MANA) > man then
set this = tb[GetHandleId(PDDS.target)]
call DestroyEffect(AddSpecialEffectTarget(SFX, PDDS.target, "origin"))
call SetUnitState(PDDS.target, UNIT_STATE_MANA, man + this.mana)
set this.stacks = this.stacks - 1
if this.stacks == 0 then
call UnitRemoveAbility(PDDS.target, BUFF_ID)
endif
endif
endif
endmethod
static method periodic takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > dindex
set this = data[i]
set this.temp = this.temp - FPS
if this.temp <= 0 then
set data[i] = data[dindex]
set i = i - 1
set dindex = dindex - 1
call this.destroy()
endif
set i = i + 1
endloop
endmethod
static method cond takes nothing returns boolean
local thistype this
local unit u
local integer l
if GetSpellAbilityId() == SPELL_ID then
set u = GetTriggerUnit()
set l = GetUnitAbilityLevel(u, SPELL_ID)
set this = allocate()
set this.stacks = Stack(l)
set this.mana = ManaReplenish(l)
set this.temp = Duration(l)
set this.targ = GetSpellTargetUnit()
set tb[GetHandleId(this.targ)] = this
call SetUnitOwner(DUMMY, GetTriggerPlayer(), false)
call SetUnitPosition(DUMMY, GetUnitX(this.targ), GetUnitY(this.targ))
call SetUnitAbilityLevel(DUMMY, DUMMY_SPELL_ID, l)
call IssueTargetOrderById(DUMMY, 852066, this.targ)
set dindex = dindex + 1
set data[dindex] = this
if dindex == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
endif
set u = null
endif
return false
endmethod
static method fin takes nothing returns boolean
if GetSpellAbilityId() == DUMMY_SPELL_ID then
call SetUnitOwner(DUMMY, Player(15), false)
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(t, Condition(function thistype.fin))
set dindex = -1
set period = CreateTimer()
set tb = Table.create()
call AddDamageHandler(function thistype.handler)
set DUMMY = CreateUnit(Player(15), DUMMY_ID, 0, 0, 0)
call UnitAddAbility(DUMMY, 'Aloc')
call UnitAddAbility(DUMMY, 'Araw')
call UnitRemoveAbility(DUMMY, 'Amov')
call UnitAddAbility(DUMMY, DUMMY_SPELL_ID)
call ShowUnit(DUMMY, false)
set t = null
endmethod
endstruct
endscope
//TESH.scrollpos=30
//TESH.alwaysfold=0
/***********************************************************
* FireStorm v1.0
* by Freyleyes
* edited by mckill2009
************************************************************/
scope FireStorm initializer Init //uses T32
globals
private constant integer SpellId = 'A00I'
//This is the spell's raw code.
private constant integer EntityUnit = 'h001'
//This is the dummy unit
private constant integer MaxDist = 400
//This is the maximum distance that the fire balls will move away from the cast point
private constant integer MinDist = 100
//This is the minimum distance when created
private constant real MaxHeight = 600
//This is the maximum height the fire balls will travel
private constant real UnitTime = 6
//This is the dummy units timed life
private constant real DetectDist = 100
//This is the distance that an unit will be detected.
private constant string ModelPath = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
//This is the fire ball's model path
private constant string Effect = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
//This is the colision effect
private constant string BirthEffect = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
//This is the birth effect
private integer counter = 0
private timer TIM = CreateTimer()
private firedata array Data
private group TempG = CreateGroup()
private constant real CREATION_INTERVAL = 0.2
endglobals
private function GetDamage takes integer level returns real
return 10. * level + 30
endfunction
private function GetEntityCount takes integer level returns integer
return 12 //3 * level + 5
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
struct firedata
unit entity
player pl
real damage
real a
real x
real y
real z
real d
real xC
real yC
effect s
static method detectUnit takes firedata dat, unit u, real x, real y returns integer
local unit n
call GroupEnumUnitsInRange(TempG, x, y, DetectDist, null)
loop
set n = FirstOfGroup(TempG)
exitwhen n == null
if IsUnitEnemy(n, dat.pl) and UnitAlive(n) then
set n = null
return 1
endif
call GroupRemoveUnit(TempG, n)
endloop
return 0
endmethod
static method onLoop takes nothing returns nothing
local firedata dat
local integer i = 0
local unit n
loop
set i = i + 1
set dat = Data[i]
if UnitAlive(dat.entity) then
//This is the onLoop actions
set dat.a = dat.a + 5 //rotation
set dat.x = dat.xC + dat.d * Cos(dat.a * bj_DEGTORAD)
set dat.y = dat.yC + dat.d * Sin(dat.a * bj_DEGTORAD)
call SetUnitX(dat.entity, dat.x)
call SetUnitY(dat.entity, dat.y)
set dat.z = dat.z + 20
call SetUnitFlyHeight(dat.entity, dat.z, 40)
if firedata.detectUnit(dat, dat.entity, dat.x, dat.y) == 1 then
call GroupEnumUnitsInRange(TempG, GetUnitX(dat.entity), GetUnitY(dat.entity), DetectDist, null)
loop
set n = FirstOfGroup(TempG)
exitwhen n == null
if IsUnitEnemy(n, dat.pl) and UnitAlive(n) then
call UnitDamageTarget(dat.entity, n, dat.damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
call DestroyEffect(AddSpecialEffectTarget(Effect, n, "chest"))
endif
call GroupRemoveUnit(TempG, n)
endloop
call KillUnit(dat.entity)
endif
else
//End of onLoop actions
call DestroyEffect(AddSpecialEffectTarget(Effect, dat.entity, "origin"))
call DestroyEffect(dat.s)
set dat.entity = null
set dat.pl = null
call dat.destroy()
set Data[i] = Data[counter]
set Data[counter] = dat
set counter = counter - 1
set i = i - 1
if counter == 0 then
call PauseTimer(TIM)
endif
endif
exitwhen i==counter
endloop
endmethod
static method start takes player p, real x, real y, real dam returns nothing
local firedata dat = firedata.allocate()
local integer ran = GetRandomInt(MinDist, MaxDist)
set dat.pl = p //set dat.caster = u
set dat.xC = x
set dat.yC = y
set dat.d = I2R(ran)
set dat.a = GetRandomReal(-3, 3) * bj_RADTODEG
set dat.x = dat.xC + dat.d * Cos(dat.a * bj_DEGTORAD)
set dat.y = dat.yC + dat.d * Sin(dat.a * bj_DEGTORAD)
set dat.entity = CreateUnit(p, EntityUnit, dat.x, dat.y, dat.a)
set dat.s = AddSpecialEffectTarget(ModelPath, dat.entity, "origin")
set dat.damage = dam
call DestroyEffect(AddSpecialEffect(BirthEffect, dat.x, dat.y))
call UnitApplyTimedLife(dat.entity, 'BFLT', UnitTime)
if counter == 0 then
call TimerStart(TIM, 0.03, true, function firedata.onLoop)
endif
set counter = counter + 1
set Data[counter] = dat
endmethod
endstruct
private struct Interval
unit caster
real xSpell
real ySpell
real damage
real period
integer count
player pl
private method periodic takes nothing returns nothing
if .count > 0 then
set .period = .period + T32_PERIOD
if .period > CREATION_INTERVAL then
set .period = 0
set .count = .count - 1
call firedata.start(.pl, .xSpell, .ySpell, .damage)
endif
else
set .caster = null
set .pl = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method interval takes unit caster, real x, real y returns nothing
local thistype this = allocate()
local integer level = GetUnitAbilityLevel(caster, SpellId)
set .caster = caster
set .pl = GetOwningPlayer(.caster)
set .xSpell = x
set .ySpell = y
set .damage = GetDamage(level)
set .count = GetEntityCount(level)
set .period = 0
call .startPeriodic()
endmethod
endstruct
private function FireStormCast takes nothing returns boolean
if GetSpellAbilityId() == SpellId then
call Interval.interval(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function FireStormCast ) )
set t = null
endfunction
endscope
//TESH.scrollpos=10
//TESH.alwaysfold=0
/************************************
edited by mckill2009
*************************************/
scope DarkLightningNova initializer init
/***********************************************************************************/
/* Dark Lightning Nova v1.3 */
/* by: msongyyy */
/* */
/* requires: JNGP 1.5e or better */
/* WorldBounds by Nestharus */
/* */
/* Big thanks to JetFangInferno for the DarkLightningNova and DarkLightning Models */
/* */
/* HOW TO IMPORT Dark Lightning Nova */
/* 1. Copy the dummy/spell into your map */
/* 2. Import the icon/models to the correct paths */
/* 3. Set the first 4 configurables to the right path */
/* the DLN_NOVA = the imported DarkLightningNova path */
/* the DLN_LIGHT = the imported DarkLightning path */
/* the DLN_ID = Spell Rawcode ID for Dark Lightning Nova */
/* the DLN_VISION_DUMMY = Unit Rawcode ID for Vision Dummy */
/* 4. Set the rest of the configurables to your liking ^^ */
/* */
/* */
/* ENJOY - PLEASE REPORT ALL BUGS TO ME */
/* AT HIVEWORKSHOP.COM */
/* */
/***********************************************************************************/
globals
private constant string NOVA = "war3mapImported\\DarkLightningNova.mdx"
private constant string LIGHT = "war3mapImported\\DarkLightning.mdx"
private constant integer ID = 'A00J'
private constant integer VISION_DUMMY = 'h001'
/***********************************************************************************/
/* */
/* START OF CONFIGURABLES :) */
/* LEVEL = Level of DLN for unit - not really a configurable lol */
/* */
/* NOVA_AOE = AoE real of the initial lightning */
/* LIGHT_AOE = AoE real of the lightning lines after initial */
/* */
/* MAX_DIST_INC = Increment of max distance traveled by LEVEL */
/* MAX_DIST_BASE = Base distance traveled by DLN */
/* MAX_DIST = MAX_DIST_INC * LEVEL + MAX_DIST_BASE */
/* */
/* NDMG_INC = Increment of damage of initial lightning by LEVEL */
/* NDMG_BASE = Base damage of initial lightning */
/* NOVA_DAMAGE = NDMG_INC * LEVEL + NDMG_BASE (Total Damage) */
/* */
/* LDMG_INC = Increment of damage of lightning after initial by LEVEL */
/* LDMG_BASE = Base damage of lightning after initial */
/* LIGHT_DAMAGE = LDMG_INC * LEVEL + LDMG_BASE (Total Damage) */
/* */
/* TIME_INC = How often each lighting strike fires off */
/* DIST_INC = Distance between each instance */
/* */
/***********************************************************************************/
private constant real NOVA_AOE = 200.00
private constant real LIGHT_AOE = 135.00
private constant real DIST_INC = 50.00
private constant real TIME_INC = 0.03125
private timer TMR = CreateTimer()
endglobals
/***********************************************************************************/
/* DLN_MAX_DIST = Max distance traveled by DLN */
/***********************************************************************************/
private constant function MAX_DIST takes real level returns real
return 200. * level + 500
endfunction
/***********************************************************************************/
/* DLN_NOVA_DAMAGE = Dealt by the initial lightning */
/***********************************************************************************/
private constant function NOVA_DAMAGE takes real level returns real
return 1.0 //100. * level + 100
endfunction
/***********************************************************************************/
/* DLN_LIGHT_DAMAGE = Damage dealt by each of the lightning strikes after the */
/* initial lightning */
/***********************************************************************************/
private constant function LIGHT_DAMAGE takes real level returns real
return 50. * level + 50
endfunction
/***********************************************************************************/
/* */
/* END OF CONFIGURABLES, DON'T TOUCH PAST HERE :( */
/* */
/***********************************************************************************/
globals
private group g = CreateGroup()
private unit fog
private unit array caster
private player array play
private real array x
private real array y
private real array dist
private real array maxDist
private real array ang
private real array novadamage
private real array lightdamage
private group array damgrp
private integer array next
private integer array prev
private integer array rn
private integer ic = 0
endglobals
private function dlnLight takes nothing returns nothing
local integer this = next[0]
local unit dummy
loop
if next[0] == 0 then
call PauseTimer(TMR)
endif
if dist[this] > maxDist[this] then
call DestroyGroup(damgrp[this])
set damgrp[this] = null
set caster[this] = null
set play[this] = null
set prev[next[this]] = prev[this]
set next[prev[this]] = next[this]
set rn[this] = rn[0]
set rn[0] = this
return
else
set dummy = CreateUnit(play[this], VISION_DUMMY, x[this], y[this], 0)
call UnitApplyTimedLife(dummy, 'BTLF', .6)
if dist[this] == 0 then
call DestroyEffect(AddSpecialEffect(NOVA, x[this], y[this]))
call DestroyEffect(AddSpecialEffect(LIGHT, x[this], y[this]))
call GroupEnumUnitsInRange(g, x[this], y[this], NOVA_AOE, null)
loop
set fog = FirstOfGroup(g)
exitwhen fog == null
if IsUnitEnemy(fog, play[this]) then
call UnitDamageTarget(dummy, fog, novadamage[this], false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
endif
call GroupRemoveUnit(g, fog)
endloop
elseif dist[this] >= NOVA_AOE and dist[this] <= maxDist[this] then
call DestroyEffect(AddSpecialEffect(LIGHT, x[this], y[this]))
call GroupEnumUnitsInRange(g, x[this], y[this], LIGHT_AOE, null)
loop
set fog = FirstOfGroup(g)
exitwhen fog == null
if IsUnitEnemy(fog, play[this]) and not IsUnitInGroup(fog, damgrp[this]) then
call GroupAddUnit(damgrp[this], fog)
call UnitDamageTarget(dummy, fog, lightdamage[this], false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
endif
call GroupRemoveUnit(g, fog)
endloop
endif
endif
set dummy = null
set dist[this] = dist[this] + DIST_INC
set x[this] = x[this] + DIST_INC * Cos(ang[this])
set y[this] = y[this] + DIST_INC * Sin(ang[this])
if x[this] > I2R(WorldBounds.maxX) then
set x[this] = I2R(WorldBounds.maxX) - 25
endif
if x[this] < I2R(WorldBounds.minX) then
set x[this] = I2R(WorldBounds.minX) + 25
endif
if y[this] > I2R(WorldBounds.maxY) then
set y[this] = I2R(WorldBounds.maxY) - 25
endif
if y[this] < I2R(WorldBounds.minY) then
set y[this] = I2R(WorldBounds.minY) + 25
endif
set this = next[this]
exitwhen this == 0
endloop
endfunction
private function dlnCreate takes unit u, real xc, real yc, real r returns nothing
local integer this = rn[0]
local integer level = GetUnitAbilityLevel(u, ID)
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set caster[this] = u
set dist[this] = 0
set x[this] = xc
set y[this] = yc
set ang[this] = r
set play[this] = GetOwningPlayer(caster[this])
set novadamage[this] = NOVA_DAMAGE(level)
set lightdamage[this] = LIGHT_DAMAGE(level)
set maxDist[this] = MAX_DIST(level)
set damgrp[this] = CreateGroup()
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
if prev[this] == 0 then
call TimerStart(TMR, TIME_INC, true, function dlnLight)
endif
endfunction
private function dlnNova takes nothing returns boolean
local unit lvUnit = GetTriggerUnit()
local real lvAng = Atan2(GetSpellTargetY() - GetUnitY(lvUnit), GetSpellTargetX() - GetUnitX(lvUnit))
if GetSpellAbilityId() == ID then
call dlnCreate(lvUnit, GetSpellTargetX(), GetSpellTargetY(), lvAng)
endif
set lvUnit = null
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function dlnNova))
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**********************************************
ChargeStrike v1.0
by mckill2009
***********************************************/
library ChargeStrike uses T32, SpellEffectEvent, TerrainPathability, TimedEffect, GroupUtils
globals
private constant integer SPELL_ID = 'A00T'
private constant integer DUMMY_ID = 'h007'
//70, recommended
private constant real MOVE_SPEED = 70
//250, recommended
private constant real DAMAGE_AOE = 200
private constant string DAM_SFX_ATTACHMENT = "chest"
private constant string DAMAGE_SFX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private attacktype ATK = ATTACK_TYPE_HERO
private damagetype DMG = DAMAGE_TYPE_NORMAL
/**********************************************
* THIS IS ONLY FOR THE TRAIL
***********************************************/
private constant string TRAIL_SFX = "Environment\\UndeadBuildingFire\\UndeadLargeBuildingFire1.mdl"
//0.5, recommended
private constant real EFFECT_DURATION = 0.5
//ALPHA_FADE_SPEED must be greater than 1, //15, recommended
private constant integer ALPHA_FADE_SPEED = 15
//10, recommended
private constant integer COLOR_R_FADE = 10
//7, recommended
private constant integer COLOR_G_FADE = 7
//8, recommended
private constant integer COLOR_B_FADE = 8
//animation of the trail
private constant string ANIMATION = "attack"
//attachments of the trail
private constant string SFX_ATTACHMENT = "origin"
endglobals
/**********************************************
* CONFIGURABLES
***********************************************/
private function FilterTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
private function GetDamage takes integer level returns real
return 25. * level + 25
endfunction
/**********************************************
* NON-CONFIGURABLES
***********************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private struct DummyFade
unit dummy
integer alpha
integer colorR
integer colorG
integer colorB
private method periodic takes nothing returns nothing
if .alpha > 0 then
set .colorR = .colorR - COLOR_R_FADE
set .colorG = .colorG - COLOR_G_FADE
set .colorB = .colorB - COLOR_B_FADE
set .alpha = .alpha - ALPHA_FADE_SPEED
call SetUnitVertexColor(.dummy, .colorR, .colorG, .colorB, .alpha)
else
call UnitApplyTimedLife(.dummy, 'BTLF', 0.1)
call RemoveUnit(.dummy)
set .dummy = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method startFade takes unit d returns nothing
local thistype this = allocate()
set .dummy = d
set .alpha = 255
set .colorR = 255
set .colorG = 255
set .colorB = 255
call .startPeriodic()
endmethod
endstruct
private struct Cast
unit caster
real damage
real angle
real angleDeg
real dist
real distX
player pl
group g
private static group grp = CreateGroup()
private method hitThem takes nothing returns nothing
local TimedEffect eff
local unit first
call GroupEnumUnitsInRange(grp, GetUnitX(.caster), GetUnitY(.caster), DAMAGE_AOE, null)
loop
set first = FirstOfGroup(grp)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, .pl) and not IsUnitInGroup(first, .g) and FilterTargets(first) then
call GroupAddUnit(.g, first)
call UnitDamageTarget(.caster, first, .damage, false, false, ATK, DMG, null)
set eff = eff.createOnUnit(DAMAGE_SFX, first, DAM_SFX_ATTACHMENT, EFFECT_DURATION)
endif
call GroupRemoveUnit(grp, first)
endloop
endmethod
private method periodic takes nothing returns nothing
local real x
local real y
local unit dummy
local TimedEffect eff
if .dist > .distX then
set .distX = .distX + MOVE_SPEED
set x = GetUnitX(.caster) + MOVE_SPEED * Cos(.angle)
set y = GetUnitY(.caster) + MOVE_SPEED * Sin(.angle)
if IsTerrainWalkable(x, y) then
call SetUnitX(.caster, x)
call SetUnitY(.caster, y)
call .hitThem()
set dummy = CreateUnit(.pl, DUMMY_ID, x, y, .angleDeg)
call SetUnitFlyHeight(dummy, GetUnitFlyHeight(.caster), 0)
call SetUnitAnimation(dummy, ANIMATION)
set eff = eff.createOnUnit(TRAIL_SFX, dummy, SFX_ATTACHMENT, EFFECT_DURATION)
call DummyFade.startFade(dummy)
set dummy = null
else
set .distX = .dist
endif
else
call SetUnitPathing(.caster, true)
set .caster = null
set .pl = null
call ReleaseGroup(.g)
set .g = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
set .pl = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .angle = Atan2(GetSpellTargetY()-y, GetSpellTargetX()-x)
set .angleDeg = .angle * bj_RADTODEG
set .dist = SquareRoot((GetSpellTargetX()-x)*(GetSpellTargetX()-x) + (GetSpellTargetY()-y)*(GetSpellTargetY()-y))
set .distX = 0
set .g = NewGroup()
set .damage = GetDamage(level)
call SetUnitPathing(.caster, false)
call UnitAddAbility(.caster, 'Arav')
call UnitRemoveAbility(.caster, 'Arav')
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/***************************************************
by Septimus
edited by mckill2009
****************************************************/
library MultiShock initializer Init
globals
private constant integer ACTIVATOR_RAWCODE = 'A00P' //carrion swarm
private constant integer DUMMY_SPELL_ID = 'A00Q' //carrion swarm
private constant integer DUMMY_RAWCODE = 'h001'
private constant integer DUMMY_ORDER_ID = 852218 //carrion swarm
private constant real TARGET_ARC = 400
private constant integer WAVE_NUMBER_PER_LEVEL = 3
private constant integer WAVE_NUMBER_BASE = 0
private constant real TARGET_ARC_CUTOFF = TARGET_ARC/6.28319
private constant real TARGET_OFFSET = 150
private unit DUMMY
endglobals
private function MSCondition takes nothing returns boolean
return GetSpellAbilityId() == ACTIVATOR_RAWCODE
endfunction
private function MultiShock takes nothing returns nothing
local unit tu = GetTriggerUnit()
local location tl = GetSpellTargetLoc()
local integer im = WAVE_NUMBER_BASE + GetUnitAbilityLevel(tu,ACTIVATOR_RAWCODE) * WAVE_NUMBER_PER_LEVEL
local integer i = 0
local real x = GetUnitX(tu)
local real y = GetUnitY(tu)
local real tx = GetLocationX(tl)
local real ty = GetLocationY(tl)
local real distance = SquareRoot((x-tx)*(x-tx)+(y-ty)*(y-ty))
local real circum
local real r
call RemoveLocation(tl)
set tl = null
if distance > TARGET_ARC_CUTOFF then
set circum = TARGET_ARC/distance
set r = Atan2(ty-y,tx-x) - circum/2
else
set circum = 6.28319
set r = GetUnitFacing(tu)*bj_DEGTORAD
endif
set circum = circum/im
call UnitAddAbility(DUMMY, DUMMY_SPELL_ID)
call SetUnitOwner(DUMMY, GetTriggerPlayer(), false)
loop
exitwhen i == im
call SetUnitPosition(DUMMY, x, y)
call IssuePointOrderById(DUMMY, DUMMY_ORDER_ID, x + TARGET_OFFSET * Cos (r), y + TARGET_OFFSET * Sin(r))
set r = r + circum
set i = i + 1
endloop
call UnitRemoveAbility(DUMMY, DUMMY_SPELL_ID)
set tu = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function MSCondition))
call TriggerAddAction(t,function MultiShock)
set DUMMY = CreateUnit(Player(15), DUMMY_RAWCODE, 0, 0, 0)
call UnitAddAbility(DUMMY, DUMMY_SPELL_ID)
call UnitAddAbility(DUMMY, 'Aloc')
call UnitRemoveAbility(DUMMY, 'Amov')
set t = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*********************************************************
Ground Tremor v1.0
by mckill2009
**********************************************************/
scope GroundTremor
globals
private constant integer SPELL_ID = 'A00Z'
private constant real DAMAGE_AOE = 110 //recommended
private constant string LINE_SFX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant attacktype ATK = ATTACK_TYPE_NORMAL
private constant damagetype DMG = DAMAGE_TYPE_NORMAL
endglobals
private function GetDamage takes integer level returns real
return 20 * level + 10.
endfunction
private function GetAdditionalRange takes integer level returns real
return 200 * level + 100.
endfunction
private function FilterOutTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private struct GT
unit caster
player owner
real damage
real distance
real distx
real angle
real xLoc
real yLoc
private method periodic takes nothing returns nothing
local unit first
local real x = .xLoc + .distx * Cos(.angle)
local real y = .yLoc + .distx * Sin(.angle)
if .distance > .distx then
set .distx = .distx + DAMAGE_AOE
call DestroyEffect(AddSpecialEffect(LINE_SFX, x,y))
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, DAMAGE_AOE, null)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, .owner) and FilterOutTargets(first) then
call UnitDamageTarget(.caster, first, .damage, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
else
set .caster = null
set .owner = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
private static method cast takes nothing returns nothing
local thistype this = allocate()
local unit u = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x1 = GetUnitX(target)
local real y1 = GetUnitY(target)
local integer level = GetUnitAbilityLevel(u, SPELL_ID)
set .owner = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .angle = Atan2(y1-y, x1-x)
set .distance = (SquareRoot((x1-x) * (x1-x) + (y1-y) * (y1-y))) + GetAdditionalRange(level)
set .distx = 0
set .damage = GetDamage(level)
set .xLoc = GetUnitX(u)
set .yLoc = GetUnitY(u)
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.cast)
endmethod
endstruct
endscope
//TESH.scrollpos=36
//TESH.alwaysfold=0
/**************************************************************
Summon From v1.0
by mckill2009
Summons units from XY
***************************************************************/
library SummonFrom uses T32, SpellEffectEvent, IsUnitChanneling, SummonedEscort
globals
private constant integer SPELL_ID = 'A00U'
private constant integer DUMMY_ID = 'h003'
private constant real INTERVAL = 2.0
private constant real OFFSET_FROM_CASTER = 200
private constant real HEIGHT = 500
private constant real SPEED = 40
private string SFX = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
private integer array unitType
private real array xLoc
private real array yLoc
private integer count = 0
private integer countLoc = 0
endglobals
private function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)//Standard parabola
endfunction
private function GetDistanceEx takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction
private struct Summon
private unit summoner
private real angle
private real distance
private real distX
private real xPoint
private real yPoint
private real height
private method periodic takes nothing returns nothing
local integer random
local unit sum
if .distance > .distX then
set .distX = .distX + SPEED
call SetUnitX(.summoner, GetUnitX(.summoner) + SPEED * Cos(.angle))
call SetUnitY(.summoner, GetUnitY(.summoner) + SPEED * Sin(.angle))
call SetUnitFlyHeight(.summoner, GetParabolaZ(HEIGHT, .distance, .distX) ,0)
else
set random = GetRandomInt(1, count)
set sum = CreateUnit(GetOwningPlayer(.summoner), unitType[random], .xPoint, .yPoint, 0)
call DestroyEffect(AddSpecialEffectTarget(SFX, sum, "origin"))
call UnitApplyTimedLife(.summoner, 'BTLF', 0.1)
call SE.summoned(null, sum)
set sum = null
set .summoner = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
static method start takes unit u, real x, real y returns nothing
local thistype this = allocate()
local real xU = GetUnitX(u)
local real yU = GetUnitY(u)
set .angle = Atan2(y - yU, x - xU)
set .summoner = u
set .distance = GetDistanceEx(x, y, xU, yU)
set .xPoint = x
set .yPoint = y
set .distX = 0
call .startPeriodic()
endmethod
endstruct
struct Fish
private unit caster
private real delay
private player pl
private method periodic takes nothing returns nothing
local unit summoner
local real xCaster
local real yCaster
local real angle
local integer random
if IsUnitChanneling(.caster) then
set .delay = .delay + T32_PERIOD
if .delay > INTERVAL then
set .delay = 0
set angle = GetRandomReal(-3, 3)
set xCaster = GetUnitX(.caster) + OFFSET_FROM_CASTER * Sin(angle)
set yCaster = GetUnitY(.caster) + OFFSET_FROM_CASTER * Cos(angle)
set random = GetRandomInt(1, countLoc)
set summoner = CreateUnit(.pl, DUMMY_ID, xLoc[random], yLoc[random], 0)
call DestroyEffect(AddSpecialEffectTarget(SFX, summoner, "origin"))
call Summon.start(summoner, xCaster, yCaster)
set summoner = null
endif
else
set .caster = null
set .pl = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
set .pl = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .delay = 0
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
/*******************************************************
* API
********************************************************/
static method add takes integer unitID returns nothing
set count = count + 1
set unitType[count] = unitID
endmethod
static method remove takes integer unitID returns nothing
local integer i = 0
loop
set i = i + 1
if unitType[i]==unitID then
set unitType[i] = unitType[count]
set count = count - 1
exitwhen true
endif
exitwhen i==count
endloop
endmethod
static method setPoint takes real x, real y returns nothing
set countLoc = countLoc + 1
set xLoc[countLoc] = x
set yLoc[countLoc] = y
endmethod
static method removePoint takes real x, real y returns nothing
local integer i = 0
loop
set i = i + 1
if xLoc[i]==x and yLoc[i]==y then
set xLoc[i] = xLoc[countLoc]
set yLoc[i] = yLoc[countLoc]
set countLoc = countLoc - 1
exitwhen true
endif
exitwhen i==countLoc
endloop
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***************************************************************************************************************
//* *
//* Death Carrier (vJASSified). *
//* By Moyack. *
//* V.2.0. *
//* *
//***************************************************************************************************************
// Made for the spell contest No 13 (for the bad luck maybe??)
// Requires TimerUtils (http://www.wc3c.net/showthread.php?t=101322) by Vexorian.
library DeathCarrier initializer init requires TimerUtils
// Configuration part...
globals
private constant integer SpellID = 'A00K' // Sets the ability Rawcode
private constant real TIMEOUT = 0.5 // Sets the timer frequency
private constant attacktype ATTACK = ATTACK_TYPE_NORMAL // Sets the type of attack that deals the spell
private constant damagetype DAMAGE = DAMAGE_TYPE_NORMAL // Sets the type of damage that deals the spell
endglobals
private constant function Damage takes integer lvl returns real
return 100. + 70. * (lvl - 1)
endfunction
private constant function AOE takes integer lvl returns real
return 500. // I left it in this way so it can be configurable to a variable area
endfunction
private constant function Jumps takes integer lvl returns integer
return 5 // sets the number of times the maks jumps on units before explode
endfunction
// end configuration part...
private function GetEnemies takes nothing returns boolean
return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405 and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(bj_groupRandomCurrentPick))
endfunction
private struct data
group g
unit c
integer counter = 0
private method onDestroy takes nothing returns nothing
call GroupClear(.g)
set .c = null
endmethod
private static method PickRandomUnit takes nothing returns nothing
set bj_groupRandomConsidered = bj_groupRandomConsidered + 1
if GetWidgetLife(GetEnumUnit()) > 0.405 and GetRandomInt(1,bj_groupRandomConsidered) == 1 then
set bj_groupRandomCurrentPick = GetEnumUnit()
endif
endmethod
static method effect takes nothing returns nothing
local data d = thistype( GetTimerData(GetExpiredTimer()) )
local real x
local real y
set bj_groupRandomConsidered = 0
set bj_groupRandomCurrentPick = null
call ForGroup(d.g, function thistype.PickRandomUnit)
if bj_groupRandomCurrentPick == null then
call d.destroy()
call ReleaseTimer(GetExpiredTimer())
return
endif
call DestroyEffect(AddSpellEffectTargetById(SpellID, EFFECT_TYPE_SPECIAL, bj_groupRandomCurrentPick, "overhead"))
set d.counter = d.counter + 1
if d.counter > Jumps(GetUnitAbilityLevel(d.c, SpellID)) then
set x = GetUnitX(bj_groupRandomCurrentPick)
set y = GetUnitY(bj_groupRandomCurrentPick)
call DestroyEffect(AddSpecialEffect(GetAbilityEffectById(SpellID, EFFECT_TYPE_SPECIAL, 1), x, y))
// at this point, d.g is not needed, so I'll use to do the final task :P
set bj_groupRandomCurrentPick = d.c
call GroupEnumUnitsInRange(d.g, x, y, 0.5 * AOE(GetUnitAbilityLevel(d.c, SpellID)), Condition(function GetEnemies))
loop
set bj_groupRandomCurrentPick = FirstOfGroup(d.g)
exitwhen bj_groupRandomCurrentPick == null
call UnitDamageTarget(d.c, bj_groupRandomCurrentPick, Damage(GetUnitAbilityLevel(d.c, SpellID)), true, true, ATTACK, DAMAGE, WEAPON_TYPE_ROCK_HEAVY_BASH)
call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById(SpellID, EFFECT_TYPE_SPECIAL, 2), bj_groupRandomCurrentPick, "chest"))
call GroupRemoveUnit(d.g, bj_groupRandomCurrentPick)
endloop
call d.destroy()
call ReleaseTimer(GetExpiredTimer())
else
call UnitDamageTarget(d.c, bj_groupRandomCurrentPick, GetRandomReal(0, Damage(GetUnitAbilityLevel(d.c, SpellID))), true, false, ATTACK, DAMAGE, WEAPON_TYPE_ROCK_HEAVY_BASH)
endif
endmethod
static method Start takes unit c, real x, real y returns nothing
local data d = data.allocate()
local timer t = NewTimer()
if d.g == null then
set d.g = CreateGroup()
endif
set d.c = c
set bj_groupRandomCurrentPick = c
call GroupEnumUnitsInRange(d.g, x, y, AOE(GetUnitAbilityLevel(c, SpellID)), Condition(function GetEnemies))
call SetTimerData(t, integer(d))
call TimerStart(t, TIMEOUT, true, function data.effect)
set t = null
endmethod
endstruct
private function Conditions takes nothing returns boolean
if GetSpellAbilityId() == SpellID then
call data.Start(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
set t = null
endfunction
endlibrary
//TESH.scrollpos=136
//TESH.alwaysfold=0
scope Haunt initializer init
//===================================================================================
//= Haunt by Ciebron v1.2
//=
//= Requires: -The Custom Model in the Import list
//=
//=
//= Description: Shoots a projectile towards target unit it will deal Damage to him
//= and then return to the caster and heal him for % of the damage
//=
//= Extra: This spell needs the imported model 'dummy.mdx'. else you wont be able to
//= attach a SFX to the dummy
//===================================================================================
globals
//The RawCode of the spell
private constant integer Abil_id = 'A00V'
//The RawCode of the dummy
private constant integer Dummy_id = 'h001'
//NOTE: only change this if u have changed the crow from ability in the editor
private constant integer Fly_id = 'Amrf'
//The SFX that will apear when the projectile hits the Target
private constant string HitSFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//The SFX that will apear when the projectile hits the Caster
private constant string HealSFX = "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
//The SFX that will attach too the projectile when it travels to the target
private constant string Projectile1 = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
//The SFX that will attach too the projectile when it travels back to the caster
private constant string Projectile2 = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//Where the SFX will get attached to the projectile
private constant string AttachPoint = "origin"
//Where the SFX will attach when the projectile hits the target/caster
private constant string AttachTargetPoint = "origin"
// Defines how fast the projectile will move
private constant real Move_Speed = 20.
//How much the caster will be healed of the procentage. eg. 1. is 100% of the dmg, 0.75 is 75% of the damage.
private constant real Heal_Amount = .50
//The Dummy's Fly Height (set it to what ever that fit's your SFX)
private constant real Dummy_Height = 75.
//The Attacktype of the spell
//Usefull information about damage types. http://www.wc3campaigns.net/showpost.php?p=1030046&postcount=19
private constant attacktype AtkType = ATTACK_TYPE_MAGIC
//The Damagetype of the spell
private constant damagetype DmgType = DAMAGE_TYPE_MAGIC
//The Weapontype of the spell (sound)
private constant weapontype WepType = null
//Timer Intervals
private constant real Interval = 0.03
endglobals
//This function is for setting the spells damage
private constant function Damage takes integer Level returns real
return 100.+(Level*50)
endfunction
//===========================================================================================
globals
private constant real Projectile_Size = Move_Speed * 2 + 1
endglobals
private struct Data
unit Caster
unit Target
unit Dummy
real Damage
real z
player Play
effect SFX
static integer array Ar
static integer Total = 0
static timer Time = CreateTimer()
static real x
static real y
static real tx
static real ty
static real x2
static real y2
static real angle
static real nH
method NewHeight takes real h returns real // A method used for setting the missile's height
set .nH = (h-.z) / ( SquareRoot((.tx-.x)*(.tx-.x)+(.ty - .y)*(.ty-.y)) / Move_Speed * Interval ) //DSG - Works out rate of change needed by working out the change in height and the time to reach target.
if .nH < 0 then //DSG - If rate of change of height is - it will not work so this inverts it to be positive.
set .nH = -.nH
endif
call SetUnitFlyHeight(.Dummy, h+Dummy_Height, .nH ) // Setting the missiles new height at a calculated rate
return h
endmethod
static method create takes unit u,unit t returns Data
local Data Dat = Data.allocate()
local real Height = GetUnitFlyHeight(t)
set Dat.Caster = u
set Dat.Target = t
set Dat.x = GetUnitX(Dat.Caster)
set Dat.y = GetUnitY(Dat.Caster)
set Dat.tx = GetUnitX(Dat.Target)
set Dat.ty = GetUnitY(Dat.Target)
set Dat.angle = Atan2(Dat.ty-Dat.y,Dat.tx-Dat.x)
set Dat.Play = GetOwningPlayer(Dat.Caster)
set Dat.Dummy = CreateUnit(Dat.Play,Dummy_id,Dat.x+50*Cos(Dat.angle),Dat.y+50*Sin(Dat.angle),(Dat.angle*57.29582))
set Dat.Damage = Damage(GetUnitAbilityLevel(Dat.Caster,Abil_id))
set Dat.SFX = AddSpecialEffectTarget(Projectile1,Dat.Dummy,AttachPoint)
set Dat.z = Dummy_Height
call UnitAddAbility(Dat.Dummy, Fly_id)
call SetUnitFlyHeight(Dat.Dummy,Dummy_Height,0.)
call UnitRemoveAbility(Dat.Dummy, Fly_id)
if Height > 0. then
set Dat.z = Dat.NewHeight(Height)
endif
if Dat.Total == 0 then
call TimerStart(Dat.Time, Interval, true, function Data.Loop)
endif
set Dat.Ar[Dat.Total] = Dat
set Dat.Total = Dat.Total + 1
set u = null
set t = null
return Dat
endmethod
static method Loop takes nothing returns nothing
local Data Dat
local integer i = 0
loop
exitwhen i >= Dat.Total
set Dat = Dat.Ar[i]
set Dat.x = GetUnitX(Dat.Dummy)
set Dat.y = GetUnitY(Dat.Dummy)
set Dat.tx = GetUnitX(Dat.Target)
set Dat.ty = GetUnitY(Dat.Target)
set Dat.x2 = Dat.tx-Dat.x
set Dat.y2 = Dat.ty-Dat.y
if SquareRoot(Dat.x2 * Dat.x2 + Dat.y2 * Dat.y2) <= Projectile_Size then
if Dat.Target != Dat.Caster then
call DestroyEffect(AddSpecialEffectTarget(HitSFX,Dat.Target,AttachTargetPoint))
call DestroyEffect(Dat.SFX)
call KillUnit(Dat.Dummy)
if not IsUnitType(Dat.Target,UNIT_TYPE_MAGIC_IMMUNE) and GetWidgetLife(Dat.Target) > .305 then
call UnitDamageTarget(Dat.Caster,Dat.Target,Dat.Damage,false,false,AtkType,DmgType,WepType)
set Dat.Target = Dat.Caster
set Dat.x = GetUnitX(Dat.Target)
set Dat.y = GetUnitY(Dat.Target)
set Dat.angle = Atan2(Dat.y-Dat.ty,Dat.x-Dat.tx)
//! Yes i could reuse the old dummy but cause it will look wierd i create a new one
set Dat.Dummy = CreateUnit(Dat.Play,Dummy_id,Dat.tx+50*Cos(Dat.angle),Dat.ty+50*Sin(Dat.angle),Dat.angle*57.29582)
//! New dummy new "fly hack"
call UnitAddAbility(Dat.Dummy, Fly_id)
call SetUnitFlyHeight(Dat.Dummy, Dat.z,0. )
call UnitRemoveAbility(Dat.Dummy, Fly_id)
//! Make so it will fly down to the caster again smoothly
call Dat.NewHeight(GetUnitFlyHeight(Dat.Target))
set Dat.SFX = AddSpecialEffectTarget(Projectile2,Dat.Dummy,AttachPoint)
else
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
else
call SetWidgetLife(Dat.Caster,GetWidgetLife(Dat.Caster)+(Dat.Damage*Heal_Amount))
call DestroyEffect(AddSpecialEffectTarget(HealSFX,Dat.Caster,AttachTargetPoint))
call KillUnit(Dat.Dummy)
call DestroyEffect(Dat.SFX)
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
else
set Dat.angle = Atan2(Dat.ty-Dat.y,Dat.tx-Dat.x)
call SetUnitX(Dat.Dummy,Dat.x+Move_Speed*Cos(Dat.angle))
call SetUnitY(Dat.Dummy,Dat.y+Move_Speed*Sin(Dat.angle))
call SetUnitFacing(Dat.Dummy,(Dat.angle*57.29582))
endif
set i = i + 1
endloop
if Dat.Total == 0 then
call PauseTimer(Dat.Time)
endif
endmethod
method onDestroy takes nothing returns nothing
set .Caster = null
set .Target = null
set .Play = null
set .Dummy = null
set .SFX = null
endmethod
endstruct
private function OnCast takes nothing returns boolean
local Data Dat
local unit u
local unit t
if GetSpellAbilityId()==Abil_id then
set u = GetTriggerUnit()
set t = GetSpellTargetUnit()
set Dat = Data.create(u,t)
set u = null
set t = null
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(trig,Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(trig,Filter(function OnCast))
call Preload(HitSFX)
call Preload(HealSFX)
call Preload(Projectile1)
call Preload(Projectile2)
set trig = null
endfunction
endscope
//TESH.scrollpos=54
//TESH.alwaysfold=0
/*******************************************************************
Fallen Souls v1.0
by mckill2009
********************************************************************/
library FallenSouls uses T32, SpellEffectEvent, IsUnitChanneling
globals
/**************************************************
* RAW CODES: must be matched according to the object editor
***************************************************/
private constant integer SPELL_ID = 'A00S'
private constant integer DUMMY_ID = 'h008'
/**************************************************
* CONFIGURABLE GLOBALS:
***************************************************/
private constant real CREATION_DELAY = 1.0
private constant real OFFSET_SPEED = 2.0
private constant real ROTATE_SPEED = 0.04
private constant real HEIGHT_SPEED = 2.0
private constant real FALL_SPEED = 50.0
private constant real START_HEIGHT = -150
private constant real MAX_HEIGHT = 800
private constant real MAX_OFFSET = 400
private constant real OFFSET_MIN_DROP = 100
private constant real DAMAGE_AOE = 135
private constant real DAMAGE_BIG_AOE = 250
//for small damage, DAMAGE_AOE
private constant real DAMAGE_DELAY = 1.0
private constant string START_SFX = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarCaster.mdl"
private constant string FINISH_SFX = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
private attacktype ATK = ATTACK_TYPE_CHAOS
private damagetype DMG = DAMAGE_TYPE_DEATH
/**************************************************
* NON-CONFIGURABLE GLOBALS:
***************************************************/
private group dam = CreateGroup()
endglobals
/**************************************************
* CONFIGURABLE FUNCTIONS:
***************************************************/
private function GetDamage takes integer level returns real
return 50. * level + 100
endfunction
private function GetDuration takes integer level returns real
return 25.
endfunction
private function GetDamageDrop takes integer level returns real
return 150. * level + 200
endfunction
private function FilterEnemies takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_MECHANICAL) and not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
/**************************************************
* NON-CONFIGURABLE FUNCTIONS: May NOT be editable below this line
***************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction
private function FilterRandom takes nothing returns boolean
return UnitAlive(GetFilterUnit())
endfunction
private function Damage takes unit orb, real damage, real aoe returns nothing
local unit first
call GroupEnumUnitsInRange(dam, GetUnitX(orb), GetUnitY(orb), aoe, null)
loop
set first = FirstOfGroup(dam)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(orb)) and FilterEnemies(first) then
call UnitDamageTarget(orb, first, damage, false, false, ATK, DMG, null)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, first, "chest"))
endif
call GroupRemoveUnit(dam, first)
endloop
endfunction
private struct Rotate
unit caster
unit orb
real angle
real damage
real damageDrop
real damageDelay
real height
real offset
real angleRan
real offsetRan
real x
real y
boolean up
boolean isOn
private method fall takes boolean damageThem returns nothing
set .height = .height - FALL_SPEED
call SetUnitX(.orb, .x + .offsetRan * Cos(.angleRan))
call SetUnitY(.orb, .y + .offsetRan * Sin(.angleRan))
call SetUnitFlyHeight(.orb, .height, 0)
if damageThem then
if .height < 1 then
call Damage(.orb, .damageDrop, DAMAGE_BIG_AOE)
call DestroyEffect(AddSpecialEffect(FINISH_SFX, GetUnitX(.orb), GetUnitY(.orb)))
set .isOn = false
endif
endif
endmethod
private method periodic takes nothing returns nothing
if IsUnitChanneling(.caster) and .isOn then
if MAX_OFFSET > .offset then
set .offset = .offset + OFFSET_SPEED
endif
if .up then
set .angle = .angle + ROTATE_SPEED
if .height > 10 then
set .damageDelay = .damageDelay + T32_PERIOD
if .damageDelay > DAMAGE_DELAY then
set .damageDelay = 0
call Damage(.orb, .damage, DAMAGE_AOE)
endif
endif
if MAX_HEIGHT > .height then
set .height = .height + HEIGHT_SPEED
else
set .up = false
endif
call SetUnitX(.orb, .x + .offset * Cos(.angle))
call SetUnitY(.orb, .y + .offset * Sin(.angle))
call SetUnitFlyHeight(.orb, .height, 0)
else
call .fall(true)
endif
else
if .height > 0 then
call .fall(false)
else
call UnitApplyTimedLife(.orb, 'BTLF', 0.1)
set .caster = null
set .orb = null
call .stopPeriodic()
call .deallocate()
endif
endif
endmethod
implement T32x
static method start takes unit caster, real damage, real damageD returns nothing
local thistype this = allocate()
set .caster = caster
set .angle = GetUnitFacing(.caster) * bj_DEGTORAD
set .orb = CreateUnit(GetOwningPlayer(.caster), DUMMY_ID, 0, 0, 0)
set .x = GetUnitX(caster)
set .y = GetUnitY(caster)
set .angleRan = GetRandomReal(-3, 3)
set .damage = damage
set .damageDrop = damageD
set .damageDelay = 0
set .offset = 0
set .offsetRan = GetRandomReal(OFFSET_MIN_DROP, I2R(R2I(MAX_OFFSET)))
set .height = START_HEIGHT
set .up = true
set .isOn = true
call SetUnitFlyHeight(.orb, .height, 0)
call .startPeriodic()
endmethod
endstruct
private struct C
unit caster
real delay
real damage
real damageDrop
real duration
private method periodic takes nothing returns nothing
if IsUnitChanneling(.caster) then
if .duration > 0 then
set .duration = .duration - T32_PERIOD
set .delay = .delay + T32_PERIOD
if .delay > CREATION_DELAY then
set .delay = 0
call Rotate.start(.caster, .damage, .damageDrop)
endif
else
call IssueImmediateOrderById(.caster, 851972)
endif
else
set .caster = null
call .stopPeriodic()
call .deallocate()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
local unit u = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(u, SPELL_ID)
local integer i = 0
call DestroyEffect(AddSpecialEffectTarget(START_SFX, u, "overhead"))
set .damage = GetDamage(level)
set .damageDrop = GetDamageDrop(level)
set .duration = GetDuration(level)
set .caster = u
set .delay = 0
call .startPeriodic()
set u = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*******************************************************************
Bleed v1.0
by mckill2009
********************************************************************
REQUIRED LIBRARIES:
- Table by Bribe
- SpellEffectEvent by Bribe
- DamageEvent by looking_for_help
********************************************************************/
library Bleed uses SpellEffectEvent, DamageEvent, Table
globals
/**************************************************
* RAW CODES: must be matched according to the object editor
***************************************************/
private constant integer SPELL_ID = 'A00Y'
/**************************************************
* CONFIGURABLE GLOBALS:
***************************************************/
private constant real DAMAGE_DIVIDER = 10
private constant string SELF_DAMAGE_SFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_DEATH
/**************************************************
* NON-CONFIGURABLE GLOBALS:
***************************************************/
private group damGrp = CreateGroup()
private Table tb
endglobals
/**************************************************
* CONFIGURABLE FUNCTIONS:
***************************************************/
private function GetChance takes integer level returns integer
return 35 //5 * level + 10
endfunction
private function GetDamage takes integer level returns real
return 20. * level + 10
endfunction
private function GetDuration takes integer level returns real
return 25. //150. * level + 200
endfunction
private function FilterOutTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_MECHANICAL) and not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
/**************************************************
* NON-CONFIGURABLE FUNCTIONS: May NOT be editable below this line
***************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private struct Bleed
unit caster
real damage
real damageSelf
real duration
integer chance
integer level
private static real interval = 2.0
private static integer ind = 0
private static integer array indAR
private static timer t = CreateTimer()
private static thistype dat
private static method onDamage takes nothing returns nothing
if tb.has(GetHandleId(PDDS.source)) then
set dat = tb[GetHandleId(PDDS.source)]
if GetRandomInt(0, 100) < dat.chance then
call UnitDamageTarget(PDDS.source, PDDS.target, dat.damage, false, false, ATK, DMG, null)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, PDDS.target, "origin"))
endif
endif
endmethod
private static method periodic takes nothing returns nothing
local thistype this
local integer i = 0
loop
set i = i + 1
set this = indAR[i]
if UnitAlive(.caster) and .duration > 0 then
set .duration = .duration - interval
call DestroyEffect(AddSpecialEffectTarget(SELF_DAMAGE_SFX, .caster, "chest"))
call SetWidgetLife(.caster, GetWidgetLife(.caster)-.damageSelf)
else
call tb.remove(GetHandleId(.caster))
set .caster = null
call .deallocate()
set indAR[i] = indAR[ind]
set ind = ind - 1
set i = i - 1
if ind==0 then
call PauseTimer(t)
endif
endif
exitwhen i==ind
endloop
endmethod
private static method onCast takes nothing returns nothing
local thistype this = allocate()
set .level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
set .caster = GetTriggerUnit()
set .duration = GetDuration(.level)
set .chance = GetChance(.level)
set .damage = GetDamage(.level)
set .damageSelf = .damage/DAMAGE_DIVIDER
set tb[GetHandleId(.caster)] = this
if ind==0 then
call TimerStart(t, interval, true, function thistype.periodic)
endif
set ind = ind + 1
set indAR[ind] = this
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
call AddDamageHandler(function thistype.onDamage)
set tb = Table.create()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*********************************************************
Ground Bash v1.0
by mckill2009
**********************************************************/
scope GroundBash
globals
/***********************************************
* ID codes
************************************************/
private constant integer SPELL_ID = 'A00X'
/***********************************************
* CONFIGURABLE GLOBALS
************************************************/
private constant real DAMAGE_AOE = 150 //explosion
private constant real SPEED = 20.
private constant real EXPLODE_DELAY = 0.5
private constant real JUMP_HEIGHT = 300
private constant string SFX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant string EXPLODE_SFX = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl"
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_DEATH
endglobals
/***********************************************
* CONFIGURABLE FUNCTIONS
************************************************/
private function GetAreaOfEffect takes integer level returns real
return 300.
endfunction
private function GetDamage takes integer level returns real
return 10. * level + 10
endfunction
private function GetExplodeCount takes integer level returns integer
return 2 * level + 3
endfunction
private function FilterOutTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/***********************************************
* NON-CONFIGURABLE FUNCTIONS and STRUCTS
************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private function GetParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)//Standard parabola
endfunction
private function GetAngle takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2-y1, x2-x1)
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
private struct GroundBash
unit hero
real aoe
real angle
real facing
real damage
real distanceH
real distX
real delay
integer count
boolean sfxOnly //one time hits the ground sfx
private method damageThem takes real aoeD, real damage, real x, real y returns nothing
local unit first
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoeD, null)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
if UnitAlive(first) and IsUnitEnemy(.hero, GetOwningPlayer(first)) and FilterOutTargets(first) then
call UnitDamageTarget(.hero, first, .damage, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
endmethod
private method destroy takes nothing returns nothing
call SetUnitFlyHeight(.hero, GetUnitDefaultFlyHeight(.hero), 0)
set .hero = null
call .stopPeriodic()
call .deallocate()
endmethod
private method periodic takes nothing returns nothing
local real xDam
local real yDam
local real xU
local real yU
local real ranAngle
local real ranOffset
if UnitAlive(.hero) then
set xU = GetUnitX(.hero)
set yU = GetUnitY(.hero)
if .distanceH > .distX then
set .distX = .distX+SPEED
call SetUnitX(.hero, xU + SPEED * Cos(.angle))
call SetUnitY(.hero, yU + SPEED * Sin(.angle))
call SetUnitFlyHeight(.hero, GetParabolaZ(JUMP_HEIGHT, .distanceH, .distX), 0)
elseif .sfxOnly then
set .sfxOnly = false
call DestroyEffect(AddSpecialEffect(SFX, xU, yU))
call SetUnitPropWindow(.hero, 1)
call SetUnitInvulnerable(.hero, false)
call UnitRemoveAbility(.hero, 'Abun')
call .damageThem(.aoe, .damage, xU, yU)
else
//explodex here
set .delay = .delay + T32_PERIOD
if .delay > EXPLODE_DELAY then
set .delay = 0
if .count > 0 then
set .count = .count - 1
set ranOffset = GetRandomReal(50, .aoe)
set ranAngle = GetRandomReal(-3, 3)
set xDam = xU + ranOffset * Cos(ranAngle)
set yDam = yU + ranOffset * Sin(ranAngle)
call DestroyEffect(AddSpecialEffect(EXPLODE_SFX, xDam, yDam))
call .damageThem(DAMAGE_AOE, .damage, xDam, yDam)
else
call .destroy()
endif
endif
endif
else
call .destroy()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
set .hero = GetTriggerUnit()
set .damage = GetDamage(level)
set .angle = GetAngle(GetUnitX(.hero), GetUnitY(.hero), GetSpellTargetX(), GetSpellTargetY())
set .distanceH = GetDistance(GetUnitX(.hero), GetUnitY(.hero), GetSpellTargetX(), GetSpellTargetY())
set .distX = 0
set .sfxOnly = true
set .delay = 0
set .count = GetExplodeCount(level)
set .aoe = GetAreaOfEffect(level)
if UnitAddAbility(.hero,'Arav') then
call UnitRemoveAbility(.hero,'Arav')
endif
call SetUnitPropWindow(.hero, 0)
call SetUnitInvulnerable(.hero, true)
call UnitAddAbility(.hero, 'Abun')
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**************************************************
Furious Rocks v1.0
by mckill2009
Originally named Landslide by Xiliger
***************************************************
REQUIRED LIBRARIES:
- T32 by Jesus4lyf
- SpellEffectEvent by Bribe
***************************************************/
library FuriosRocks uses T32, SpellEffectEvent
globals
/**************************************************
* RAW CODES: must be matched according to the object editor
***************************************************/
private constant integer SPELL_ID = 'A011'
private constant integer DUMMY_ID = 'h00A'
/**************************************************
* CONFIGURABLE GLOBALS:
***************************************************/
private constant real DAMAGE_AOE = 150
private constant real SPEED = 20
private constant real DUMMY_SCALE = 2.0
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_DEATH
/**************************************************
* NON-CONFIGURABLE GLOBALS:
***************************************************/
private group damGrp = CreateGroup()
endglobals
/**************************************************
* CONFIGURABLE FUNCTIONS:
***************************************************/
private function GetDamage takes integer level returns real
return 50. * level + 100
endfunction
private function GetMaxRocks takes integer level returns integer
return 2 * level + 6
endfunction
private function FilterTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/**************************************************
* NON-CONFIGURABLE FUNCTIONS: May NOT be editable below this line
***************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private struct FR
unit u
effect model
player owner
real d
real c
real a
real h
real dmg
private method periodic takes nothing returns nothing
local unit first
local real x = GetUnitX(this.u) + SPEED * Cos(this.a)
local real y = GetUnitY(this.u) + SPEED * Sin(this.a)
set this.c = this.c + SPEED
call SetUnitX(this.u, x)
call SetUnitY(this.u, y)
call SetUnitFlyHeight(this.u, (4 * this.h / this.d) * (this.d - this.c) * (this.c / this.d), 0)
if this.c > this.d then
call GroupEnumUnitsInRange(damGrp, x, y, DAMAGE_AOE, null)
loop
set first = FirstOfGroup(damGrp)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, .owner) and FilterTargets(first) then
call UnitDamageTarget(this.u, first, this.dmg, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(damGrp, first)
endloop
call KillUnit(this.u)
set this.u = null
call .stopPeriodic()
call this.deallocate()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
local integer i = 0
local integer maxRocks = GetMaxRocks(level)
local real damage = GetDamage(level)
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
loop
set this = allocate()
set this.a = GetRandomReal(-3, 3)
set this.d = GetRandomInt(150, 400)
set this.h = GetRandomInt(300, 600)
set this.c = 0
set this.owner = GetTriggerPlayer()
set this.u = CreateUnit(GetTriggerPlayer(), DUMMY_ID, x, y, a)
set this.dmg = damage
call this.startPeriodic()
set i = i + 1
exitwhen i==maxRocks
endloop
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*******************************************************************
Blazing Rocks v1.0 (unit target version)
by mckill2009
********************************************************************
REQUIRED LIBRARIES:
- T32 by Jesus4lyf
- SpellEffectEvent by Bribe
********************************************************************/
library BlazingRocksUNITVERSION uses SpellEffectEvent, T32
globals
/**************************************************
* RAW CODES: must be matched according to the object editor
***************************************************/
private constant integer SPELL_ID = 'A012'
private constant integer DUMMY_ID = 'h001'
/**************************************************
* CONFIGURABLE GLOBALS:
***************************************************/
private constant real DAMAGE_AOE = 150
private constant real START_HEIGHT = 1000
private constant real SCALE = 1.5
private constant real DAMAGE_MULTIPLIER = 1.5
private constant integer MIN_DROP_SPEED = 10
private constant integer MAX_DROP_SPEED = 40
private constant string DUMMY_MODEL = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
private constant string EXPLODE = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_DEATH
/**************************************************
* NON-CONFIGURABLE GLOBALS:
***************************************************/
private group damG = CreateGroup()
endglobals
/**************************************************
* CONFIGURABLE FUNCTIONS:
***************************************************/
private function GetDamage takes integer level returns real
return 25. * level + 50
endfunction
private function FilterTargets takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/**************************************************
* NON-CONFIGURABLE FUNCTIONS:
***************************************************/
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u)!=0
endfunction
private function AngularHeightDrop takes real height, real distance, real speed returns real
return (distance/height) * speed
endfunction
private struct BlazingRocks
unit rock
player owner
effect model
real angle
real dam
real dist
real distX
real dropSpeed
real spellX
real spellY
real z
private method periodic takes nothing returns nothing
local unit first
local real x = GetUnitX(.rock)
local real y = GetUnitY(.rock)
if .z > 0 then
set .z = .z - .dropSpeed
call SetUnitFlyHeight(.rock, .z, 0)
call SetUnitX(.rock, x + .distX * Cos(.angle))
call SetUnitY(.rock, y + .distX * Sin(.angle))
else
call DestroyEffect(AddSpecialEffect(EXPLODE, x, y))
call GroupEnumUnitsInRange(damG, x, y, DAMAGE_AOE, null)
loop
set first = FirstOfGroup(damG)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.rock)) and FilterTargets(first) then
call UnitDamageTarget(.rock, first, .dam, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(damG, first)
endloop
call DestroyEffect(.model)
call KillUnit(.rock)
set .rock = null
set .model = null
set .owner = null
call .deallocate()
call .stopPeriodic()
endif
endmethod
implement T32x
private static method onCast takes nothing returns nothing
local thistype this = allocate()
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
set .rock = CreateUnit(GetTriggerPlayer(), DUMMY_ID, x, y, 0)
set .spellX = GetUnitX(GetSpellTargetUnit())
set .spellY = GetUnitY(GetSpellTargetUnit())
set .angle = Atan2(.spellY-y, .spellX-x)
set .dropSpeed = GetRandomReal(I2R(MIN_DROP_SPEED), I2R(MAX_DROP_SPEED))
set .dist = SquareRoot((.spellX-x)*(.spellX-x)+(.spellY-y)*(.spellY-y))
set .distX = AngularHeightDrop(START_HEIGHT, .dist, .dropSpeed)
set .model = AddSpecialEffectTarget(DUMMY_MODEL, .rock, "origin")
set .z = START_HEIGHT
set .dam = GetDamage(level) + (.dropSpeed * DAMAGE_MULTIPLIER)
call SetUnitScale(.rock, SCALE, SCALE, SCALE)
call .startPeriodic()
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary