Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AllInCreepTimeMultiplier | real | No | 0.25 |
AllInFrequency | integer | No | 15 |
AllTowers | group | No | |
antiCheat | integer | Yes | -1 |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
Armor | boolean | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorFrequency | integer | No | 4 |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
b | boolean | No | |
BossFrequency | integer | No | 10 |
BurnDamageBase | integer | No | 1 |
BurnDamageIncrement | integer | No | 1 |
BurnDurationBase | real | No | 2.00 |
BurnDurationIncrement | real | No | 1.25 |
BurnPeriodBase | real | No | 1.00 |
BurnPeriodIncrement | real | No | 0.25 |
BurstFrequency | integer | No | 3 |
BurstSpawnTimeMultiplier | real | No | 0.25 |
BurstWaveSpeedMultiplier | real | No | 3.00 |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CreepCurrentAmount | integer | No | |
CreepIncrementorFrequency | real | No | 1.00 |
CreepIncrementorHPBonus | real | No | 0.01 |
CreepPool | unit | Yes | |
CreepPoolIndex | integer | No | |
CreepPoolMax | integer | No | 2 |
CreepSpeedBase | real | No | 348.00 |
CreepSpeedBonusMultiplier | real | No | 1.50 |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterMinAmount | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
EndgameButton | button | No | |
EnhancedDamageTarget | unit | No | |
Explosion | boolean | No | |
ExplosionDamageBase | real | No | 0.25 |
ExplosionDamageIncrement | real | No | 0.15 |
ExplosionRangeBase | real | No | 50.00 |
ExplosionRangeIncrement | real | No | 20.00 |
Fast | boolean | No | |
FastFrequency | integer | No | 3 |
firstTime | boolean | No | |
ForWho | player | No | |
GameButtons | button | Yes | |
GameLengths | integer | No | 4 |
GamemodePick | dialog | No | |
HashMovement | hashtable | No | |
Healer | boolean | No | |
HealerFrequency | integer | No | 13 |
HeavyCreepIntensityMultiplier | real | No | 2.00 |
HeavyCreepMultiplier | real | No | 0.25 |
HeavyCreepTimeMultiplier | real | No | 2.00 |
HeavyFrequency | integer | No | 6 |
i | integer | No | |
Immune | boolean | No | |
ImmuneFrequency | integer | No | 17 |
Incrementor | boolean | No | |
IncrementorFrequency | integer | No | 19 |
Intensity | integer | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
j | integer | No | |
k | handle | No | |
k2 | handle | No | |
k3 | handle | No | |
k4 | handle | No | |
l | location | No | |
l2 | location | No | |
l3 | location | No | |
LaunchImpact | real | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
MainBoard | multiboard | Yes | |
mainMenu | unit | Yes | |
MinutePerGame | integer | No | 15 |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
p | player | No | |
p2 | player | No | |
PassSound | sound | Yes | |
PassSoundIndex | integer | No | |
placed | boolean | Yes | |
r | rect | No | |
r2 | rect | No | |
r3 | rect | No | |
real | real | No | |
real2 | real | No | |
real3 | real | No | |
Reducer | boolean | No | |
ReducerFrequency | integer | No | 5 |
Regenerator | boolean | No | |
RegeneratorFrequency | integer | No | 7 |
RegionSize | real | No | 80.00 |
s | string | No | |
ScoreColor | string | Yes | |
ScoreColorIndex | integer | No | |
ScoreColorTimer | timer | No | |
ScoreSound | sound | Yes | |
ScoreSoundIndex | integer | No | |
SlowDurationBase | real | No | 2.00 |
SlowDurationIncrement | real | No | 1.25 |
SlowIntensityBase | real | No | 1.00 |
SlowIntensityIncrement | real | No | 0.13 |
SpawnFrequencyBase | real | No | 1.00 |
SpawnPoint | location | Yes | |
SpecialFrequencyStart | integer | No | 5 |
Splitter | boolean | No | |
SplitterFrequency | integer | No | 11 |
SwarmCreepIntensityMultiplier | real | No | 0.50 |
SwarmCreepMultiplier | real | No | 3.00 |
SwarmFrequency | integer | No | 4 |
SwarmSpawnTimeMultiplier | real | No | 0.33 |
t | timer | No | |
t2 | timer | No | |
tmpDamage | real | No | |
TowerAttackSpeedBase | real | No | 3.00 |
TowerAttackSpeedDecrement | real | No | 0.10 |
TowerProjectileSpeedBase | real | No | 500.00 |
TowerProjectileSpeedIncrement | real | No | 150.00 |
tw | timerdialog | No | |
u | unit | No | |
u2 | unit | No | |
ug | group | No | |
ug2 | group | No | |
ut | unitcode | No | |
WaveArmorIncreaseFlat | integer | No | 1 |
WaveBaseNumberOfCreeps | integer | No | 30 |
WaveFastIncrease | real | No | 1.50 |
WaveHealerIncrease | real | No | 1.50 |
WaveImmuneIncrease | real | No | 1.50 |
WaveIncrementorIncrease | real | No | 0.50 |
WaveInitialPoint | integer | No | 20 |
WavePointBase | integer | No | 2 |
WavePointDecrease | real | No | 0.05 |
WavePointIncrease | real | No | 0.30 |
WaveReducerIncrease | real | No | 2.00 |
WaveRegeneratorIncreaseFlat | integer | No | 1 |
WaveSplitterIncrease | real | No | 1.00 |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
Where | location | No | |
whosyourdaddy | boolean | Yes | |
x | integer | No | |
y | integer | No |
//===========================================================================
//
// Damage Engine 5.7.1.2 - update requires replacing the JASS script.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method getIndex takes trigger t, string eventName, real value returns integer
static method registerTrigger takes trigger whichTrig, string var, real weight returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method operator [] takes code c returns trigger
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = CreateTrigger()
private trigger t2 = CreateTrigger()
private trigger t3 = CreateTrigger() //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfiguration" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
*/
struct DamageTrigger extends array
//Map-makers should comment-out any booleans they will never need to check for.
method checkConfiguration takes nothing returns boolean
if this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif udg_DamageEventAmount > this.damageMin then
return true
endif
return false
endmethod
//The below variables are constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean configured
boolean usingGUI
//The below variables are private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceBuff = udg_DamageFilterSourceB
set this.targetBuff = udg_DamageFilterTargetB
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set udg_DamageFilterAttackT =-1
set udg_DamageFilterDamageT =-1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterMinAmount=0.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if var == "udg_DamageModifierEvent" then
if root >= 4 then
set root= SHIELD //4.00 or higher
else
set root= MOD //Less than 4.00
endif
elseif var == "udg_DamageEvent" then
if root == 2 or root == 0 then
set root= ZERO
else
set root= DAMAGE //Above 0.00 but less than 2.00, generally would just be 1.00
endif
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
local thistype index = getIndex(t, eventName, lbs)
if index == 0 then
return false
endif
set prev.next = index.next
set trigIndexStack[index] = trigIndexStack[0]
set trigIndexStack[0] = index
if reset then
call index.configure()
set index.configured = false
set index = index*FILTER_MAX
call index.toggleAllFilters(false)
endif
return true
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if not this.trigFrozen and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and (not this.configured or this.checkConfiguration()) then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if pierce != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call DamageTrigger.AOE.run()
endif
set udg_DamageEventAOE = 0
set udg_DamageEventLevel = 0
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != 0 then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if udg_DamageEventAmount != 0.00 then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if this.damage != 0.00 then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damage != 0.00 and d.damageType == DAMAGE_TYPE_UNKNOWN)
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
if not DamageTrigger.eventIndex.checkConfiguration() then
return
endif
endif
//! endtextmacro
endlibrary
//TESH.scrollpos=58
//TESH.alwaysfold=0
library ReviveUnit /* 2.0.0.0
***************************************************
*
* Resurrects a unit from his corpse, retaining
* its handle ID, facing, and position.
*
***************************************************
*
* ReviveUnit(unit whichUnit) returns boolean
* - Resurrects the input unit.
*
***************************************************
*
* Configurables
* - Remove the ! from //! after saving.
*/
// external ObjectMerger w3a AHre URez anam "Dummy Resurrection" aher 0 acat "" atat "" Hre1 1 1 aare 1 0 aran 1 0 acdn 1 0 amcs 1 0 atar 1 "Air,Dead,Enemy,Friend,Ground,Neutral"
// external ObjectMerger w3u ushd eRez unam "Dummy" uabi "Aloc,Avul" ucbs 0 ucpt 0 umdl ".mdl" usca "0.01" ushu "None" umvh 0 umvs 0 ufoo 0 umpi 100000 umpm 100000 umpr 1000
globals
private constant integer DUMMY = 'h007'
private constant integer RESURRECT = 'A005'
endglobals
/*
***************************************************
*
* Notes
* - Does not work on units without corpses.
* - The resurrected unit's mana is determined
* by the field: "Mana - Initial Amount"
*
***************************************************
*
* Importing: Automatic
* - Copy and paste this trigger.
* - Save the map, close it, and reopen it
* - Remove the exclamation ! from the object
* merger lines above.
*
* Importing: Manual
* - Copy and paste this trigger.
* - Copy and paste the dummy unit and resurrection
* ability from the object editor.
* - Change the configurable raw codes as necessary.
*
***************************************************/
globals
private unit reviver
private real rx
private real ry
endglobals
function ReviveUnit takes unit u returns boolean
local boolean success
if IsUnitType(u, UNIT_TYPE_HERO) == true then
return ReviveHero(u, GetUnitX(u), GetUnitY(u), false)
else
call SetUnitX(reviver, GetUnitX(u))
call SetUnitY(reviver, GetUnitY(u))
set success = IssueImmediateOrderById(reviver, 852094)
call SetUnitX(reviver, rx)
call SetUnitY(reviver, ry)
endif
return success
endfunction
private module Init
private static method onInit takes nothing returns nothing
set rx = GetRectMaxX(bj_mapInitialPlayableArea) - 1
set ry = GetRectMaxY(bj_mapInitialPlayableArea) - 1
set reviver = CreateUnit(Player(15), DUMMY, rx, ry, 0)
call SetUnitPathing(reviver, false)
call UnitAddAbility(reviver, RESURRECT)
endmethod
endmodule
struct Revive extends array
/* For backwards compatibility */
static method Unit takes unit whichUnit returns boolean
return ReviveUnit(whichUnit)
endmethod
implement Init
endstruct
endlibrary
/*
==============================
Key : region
0 : point
1 : point target
2 : region target
==============================
Key : unit
0 : point target
1 : region target
2 : region (temporary for the init)
3 : index
Types :
4) Reducer
5) Splitter
6) Healer
7) Intensity
8) Fast
9) Armor
10) Regenerator
11) Immune
12) Incrementor
Effects :
100) slow timer
101) burn timer
102) burn damage timer
103) incrementor timer
200 : player
==============================
Key : player
0 : spawn point
1 : score
2 : wave intensity
3 : wave indicator
4 : wave timer
5 : wave scored
6 : global timer
7 : global timer window
8 : remaining units of the wave
9 : spawned everything
==============================
Key : timer (effect)
0) unit
1) level
2) type
--- 1) slowness
--- 2) damage length
--- 3) damage period
--- 4) incrementor
3) tower origin
==============================
Key : timer (spawn)
0 : player
1 : creeps left (big)
2 : creeps left (small)
3
4 : burst timer
5 : burst waves left remaining waves of burst
6 : burst left remaining creeps of the current burst
7 : spawn trigger
8 : big creep intensity
9 :
10: burst parent timer
11: burst size for each burst waves
==============================
Key : point
0 : region
===========================================================
Wave types (starting at 5)
Every 3 FAST +50% price Units have +50% speed
Every 4 ARMOR +1 base price Units have -5 from all direct damage
Every 5 REDUCER x2 price Dead creeps will transform instead to a lesser version, until 0
Every 7 REGENERATOR +1 base price Units have +5hp/s
Every 11 SPLITTER x4 price Dead creeps will spawn 2 lesser version, until 0, priority over REDUCER
Every 13 HEALER +50% price Dead creeps will heal their amount of HP to all nearby creeps
Every 17 IMMUNE +50% price Immunity to slowness, burn and explosion
Every 19 INCREMENTOR +1 base price Max HP increases by 1% every seconds, until +100%
Wave form
All else NORMAL
Every 3 BURST Units spawn in burst of group of sqrt of the wave instead of continuous, 3x slower bursts but 4x faster spawn per burst
Every 4 SWARM Units 4x less bulky but 4x more numerous and spawn 2x faster
Every 6 HEAVY Units 4x more bulky but 4x less numerous and spawn 2x slower, priority over SWARM and BURST
Every 10 BOSS One or more super unit, priority over SWARM and HEAVY, BURST and ALL IN
Every 15 ALL IN Units spawn in one single burst, priority over BURST
Wave functioning
☼ Every unit cost 2 points at 0 intensity
☼ Increase the unit cost with the wave type
☼ Divide the wave intensity of the player by the creep cost to get the number of level 0 units
☼ A wave have a base of 40 creeps
☼ Edit the number of creeps
☼ Fuse the two weakest util it's bellow the number of creeps
► In case of boss, set its intensity to the closest log2 of the sum of the intensities
► If there's more than 2 intensities type left, drop all the smaller ones
☼ Spawn the wave starting from the big ones
☼ When the wave finishes, 50% of the killed points is added to the wave intensity
☼ The player score are added from 100% of the killed points
☼ The next wave is launched when the player upgrades something or build a tower
☼ The game finishes at 1 hour
*/
library FoTD
globals
group Gug=CreateGroup()
trigger unitImpactTrig
boolean burn=false
endglobals
function timerExpire takes nothing returns nothing
local timer t=GetExpiredTimer()
local timer t2
local integer k=GetHandleId(t)
local integer k2
local unit u=LoadUnitHandle(udg_HashMovement,k,0)
local integer level=LoadInteger(udg_HashMovement,k,1)
local integer effectType=LoadInteger(udg_HashMovement,k,2)
local effect e=null
local real increase
local unit tower
if u==null then
return
endif
// slow
if effectType==1 then
if LoadBoolean(udg_HashMovement,GetHandleId(u),8) then
call SetUnitMoveSpeed(u,udg_CreepSpeedBase*udg_CreepSpeedBonusMultiplier)
else
call SetUnitMoveSpeed(u,udg_CreepSpeedBase)
endif
call UnitRemoveAbility(u,'A002')
endif
// burn
if effectType==2 then
call UnitRemoveAbility(u,'A003')
set k2=GetHandleId(u)
set t2=LoadTimerHandle(udg_HashMovement,k2,102)
call FlushChildHashtable(udg_HashMovement,GetHandleId(t2))
call DestroyTimer(t2)
set t2=null
endif
// burn damage
if effectType==3 then
set e=AddSpecialEffectTarget("Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl",u,"chest")
call DestroyEffect(e)
set tower=LoadUnitHandle(udg_HashMovement,k,3)
if level>=R2I(GetWidgetLife(u)) then
//call DisplayTextToPlayer(Player(0),0,0,"Burn kill at "+R2S(GetWidgetLife(u)))
set burn=true
call killCreep.evaluate(u,tower)
set burn=false
set effectType=2 // to clear it just after
else
call SetWidgetLife(u,GetWidgetLife(u)-level)
//call DisplayTextToPlayer(Player(0),0,0,"It's now at "+R2S(GetWidgetLife(u)))
endif
set tower=null
set e=null
endif
// incrementor
if effectType==4 then
if level>=100 then
set effectType=2 // to clear it just after
set level=100
else
set level=level+1
endif
set increase=getCreepMaxLife.evaluate(u)*udg_CreepIncrementorHPBonus
call BlzSetUnitMaxHP(u,R2I(getCreepMaxLife.evaluate(u)+increase*level))
call SetWidgetLife(u,GetWidgetLife(u)+increase)
call SaveInteger(udg_HashMovement,k,1,level)
endif
// destroy non-looped timers
if effectType==1 or effectType==2 then
call DestroyTimer(t)
call FlushChildHashtable(udg_HashMovement,k)
endif
set t=null
set u=null
endfunction
function configureSpawn takes integer intensity, integer wave, player p returns nothing
local integer delayedWave=wave-udg_SpecialFrequencyStart
set udg_Intensity=intensity
if delayedWave>=0 then
set udg_Fast= delayedWave>=udg_FastFrequency and ModuloInteger(delayedWave,udg_FastFrequency)==0
set udg_Armor= delayedWave>=udg_ArmorFrequency and ModuloInteger(delayedWave,udg_ArmorFrequency)==0
set udg_Reducer= delayedWave>=udg_ReducerFrequency and ModuloInteger(delayedWave,udg_ReducerFrequency)==0 and ModuloInteger(delayedWave,udg_SplitterFrequency)!=0
set udg_Regenerator= delayedWave>=udg_RegeneratorFrequency and ModuloInteger(delayedWave,udg_RegeneratorFrequency)==0
set udg_Splitter= delayedWave>=udg_SplitterFrequency and ModuloInteger(delayedWave,udg_SplitterFrequency)==0
set udg_Healer= delayedWave>=udg_HealerFrequency and ModuloInteger(delayedWave,udg_HealerFrequency)==0
set udg_Immune= delayedWave>=udg_ImmuneFrequency and ModuloInteger(delayedWave,udg_ImmuneFrequency)==0
set udg_Incrementor= delayedWave>=udg_IncrementorFrequency and ModuloInteger(delayedWave,udg_IncrementorFrequency)==0
else
set udg_Fast=false
set udg_Armor=false
set udg_Reducer=false
set udg_Splitter=false
set udg_Healer=false
set udg_Immune=false
set udg_Incrementor=false
endif
set udg_ForWho=p
set udg_Where=udg_SpawnPoint[GetPlayerId(p)+1]
endfunction
/*
function spawnTimerSub takes nothing returns nothing
local timer tb=GetExpiredTimer()
local integer kt=GetHandleId(t)
local timer tp=LoadTimerHandle(udg_HashMovement,kt,0)
local integer ktp=GetHandleId(tp)
local integer leftBig=LoadInteger(udg_HashMovement,ktp,1)
local integer leftSmall=LoadInteger(udg_HashMovement,ktp,2)
endfunction
*/
function waveEnd takes player p returns nothing
local integer k=GetHandleId(p)
local timer t=LoadTimerHandle(udg_HashMovement,k,6)
local timerdialog tw=LoadTimerDialogHandle(udg_HashMovement,k,7)
call PauseTimer(t)
set t=null
call TimerDialogSetTitleBJ(tw,"Place a tower or improve a tech")
set tw=null
set udg_placed[GetPlayerId(p)+1]=false
call SetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD,1)
call flushPlayerScore.evaluate(p)
if GetLocalPlayer()==p then
call PlaySoundBJ(gg_snd_ReceiveGold)
endif
call giveMoveTower.evaluate(p)
endfunction
function burstTimerExpires takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer keyt=GetHandleId(t)
local timer parentt=LoadTimerHandle(udg_HashMovement,keyt,10)
local integer keyparentt=GetHandleId(parentt)
local player p=LoadPlayerHandle(udg_HashMovement,keyparentt,0)
local integer keyp=GetHandleId(p)
local integer leftBig=LoadInteger(udg_HashMovement,keyparentt,1)
local integer leftSmall=LoadInteger(udg_HashMovement,keyparentt,2)
local integer wave=LoadInteger(udg_HashMovement,keyp,3)
local trigger spawnFunction=LoadTriggerHandle(udg_HashMovement,keyparentt,7)
local integer intensity=LoadInteger(udg_HashMovement,keyparentt,8)
local integer burstWaveLeft=LoadInteger(udg_HashMovement,keyparentt,5)
local integer burstLeft=LoadInteger(udg_HashMovement,keyparentt,6)
local integer burstSize=LoadInteger(udg_HashMovement,keyparentt,11)
local boolean waveEnded=false
if leftBig>0 then
set leftBig=leftBig-1
endif
if leftBig<=0 then
set intensity=intensity-1
if leftSmall>1 then
set leftSmall=leftSmall-1
endif
if leftSmall<=0 then
set waveEnded=true
endif
endif
if burstLeft>0 then
set burstLeft=burstLeft-1
endif
if burstLeft<=0 then
set waveEnded=true
endif
//call DisplayTextToPlayer(p,0,0,"--- There's "+I2S(burstLeft)+" burst left")
call SaveInteger(udg_HashMovement,keyparentt,1,leftBig)
call SaveInteger(udg_HashMovement,keyparentt,2,leftSmall)
call SaveInteger(udg_HashMovement,keyparentt,6,burstLeft)
call configureSpawn(intensity,wave,p)
call TriggerExecute(spawnFunction)
if waveEnded then
// ==== stop the burst spawn
// ==== the burst finished to spawn
call PauseTimer(t)
if LoadInteger(udg_HashMovement,keyparentt,5)>0 then
//call ResumeTimer(parentt)
//call TimerStart(t,getSpawnTimerLength.evaluate(wave),true,function spawnTimerExpires)
call spawnTimerForceStart.evaluate(parentt,wave)
endif
endif
set parentt=null
set spawnFunction=null
set p=null
set t=null
endfunction
function isBurst takes integer wave returns boolean
//call DisplayTextToPlayer(Player(0),0,0,"Burst Frequency : "+I2S(ModuloInteger(wave,udg_BurstFrequency)))
//call DisplayTextToPlayer(Player(0),0,0,"Heavy Frequency : "+I2S(ModuloInteger(wave,udg_HeavyFrequency)))
//call DisplayTextToPlayer(Player(0),0,0,"Boss Frequency : "+I2S(ModuloInteger(wave,udg_BossFrequency)))
return wave>0 and ModuloInteger(wave,udg_BurstFrequency)==0 and ModuloInteger(wave,udg_HeavyFrequency)!=0 and ModuloInteger(wave,udg_BossFrequency)!=0
endfunction
function spawnTimerExpires takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kt=GetHandleId(t)
local player p=LoadPlayerHandle(udg_HashMovement,kt,0)
local integer kp=GetHandleId(p)
local integer leftBig=LoadInteger(udg_HashMovement,kt,1)
local integer leftSmall=LoadInteger(udg_HashMovement,kt,2)
local integer wave=LoadInteger(udg_HashMovement,kp,3)
local trigger spawnFunction=LoadTriggerHandle(udg_HashMovement,kt,7)
local integer intensity=LoadInteger(udg_HashMovement,kt,8)
local boolean burst=isBurst(wave)
local timer tb=LoadTimerHandle(udg_HashMovement,kt,4)
local integer burstWaveLeft=LoadInteger(udg_HashMovement,kt,5)
local integer burstLeft=LoadInteger(udg_HashMovement,kt,6)
local integer burstSize=LoadInteger(udg_HashMovement,kt,11)
local boolean waveWillEnd=false
if burst then
// save the burst size in the burst left
call SaveInteger(udg_HashMovement,kt,6,burstSize)
// reduce by one step the remaining burst waves
if burstWaveLeft>0 then
set burstWaveLeft=burstWaveLeft-1
endif
// ==== start the burst timer if all burst have not been launched
if burstWaveLeft<=0 then
set waveWillEnd=true
endif
call SaveInteger(udg_HashMovement,kt,5,burstWaveLeft)
//call DisplayTextToPlayer(p,0,0,"There's "+I2S(burstWaveLeft)+" burst wave left")
call PauseTimer(t)
call TimerStart(tb,udg_SpawnFrequencyBase*udg_BurstSpawnTimeMultiplier,true,function burstTimerExpires)
else
//call DisplayTextToPlayer(p,0,0,"Not burst")
if leftBig>0 then
set leftBig=leftBig-1
endif
if leftBig<=0 then
set intensity=intensity-1
if leftSmall>0 then
set leftSmall=leftSmall-1
endif
if leftSmall<=0 then
set waveWillEnd=true
endif
endif
call SaveInteger(udg_HashMovement,kt,1,leftBig)
call SaveInteger(udg_HashMovement,kt,2,leftSmall)
endif
if not burst then
call configureSpawn(intensity,wave,p)
call TriggerExecute(spawnFunction)
endif
if waveWillEnd then
// ==== stop the timer
// ==== the wave finished to spawn
call PauseTimer(t)
// == everything have been spawned
//call DisplayTextToPlayer(p,0,0,"Finished 1")
call SaveBoolean(udg_HashMovement,kp,9,true)
call SaveInteger(udg_HashMovement,kt,1,0)
call SaveInteger(udg_HashMovement,kt,2,0)
endif
set tb=null
set spawnFunction=null
set p=null
set t=null
endfunction
function spawnTimerForceStart takes timer t, integer wave returns nothing
call TimerStart(t,getSpawnTimerLength.evaluate(wave),true,function spawnTimerExpires)
endfunction
function getCreepPointCost takes integer wave returns integer
local integer specialWave=wave-udg_SpecialFrequencyStart
local real result=udg_WavePointBase
if specialWave>=0 then
// Armor
if specialWave>=udg_ArmorFrequency and ModuloInteger(specialWave,udg_ArmorFrequency)==0 then
set result=result+udg_WaveArmorIncreaseFlat
set udg_Armor=true
else
set udg_Armor=false
endif
// Regenerator
if specialWave>=udg_RegeneratorFrequency and ModuloInteger(specialWave,udg_RegeneratorFrequency)==0 then
set result=result+udg_WaveRegeneratorIncreaseFlat
set udg_Regenerator=true
else
set udg_Regenerator=false
endif
// Fast
if specialWave>=udg_FastFrequency and ModuloInteger(specialWave,udg_FastFrequency)==0 then
set result=result*udg_WaveFastIncrease
set udg_Fast=true
else
set udg_Fast=false
endif
// Splitter
if specialWave>=udg_SplitterFrequency and ModuloInteger(specialWave,udg_SplitterFrequency)==0 then
set result=result*udg_WaveSplitterIncrease
set udg_Splitter=true
set udg_Reducer=false
else
set udg_Splitter=false
// Reducer
if specialWave>=udg_ReducerFrequency and ModuloInteger(specialWave,udg_ReducerFrequency)==0 then
set result=result*udg_WaveReducerIncrease
set udg_Reducer=true
else
set udg_Reducer=false
endif
endif
// Healer
if specialWave>=udg_HealerFrequency and ModuloInteger(specialWave,udg_HealerFrequency)==0 then
set result=result*udg_WaveHealerIncrease
set udg_Healer=true
else
set udg_Healer=false
endif
// Immune
if specialWave>=udg_ImmuneFrequency and ModuloInteger(specialWave,udg_ImmuneFrequency)==0 then
set result=result*udg_WaveImmuneIncrease
set udg_Immune=true
else
set udg_Immune=false
endif
// Incrementor
if specialWave>=udg_IncrementorFrequency and ModuloInteger(specialWave,udg_IncrementorFrequency)==0 then
set result=result*udg_WaveIncrementorIncrease
set udg_Incrementor=true
else
set udg_Incrementor=false
endif
endif
return R2I(result)
endfunction
function getWaveSize takes integer wave returns integer
local real result=udg_WaveBaseNumberOfCreeps
// Boss
if ModuloInteger(wave,udg_BossFrequency)==0 then
set result=1
else
// Heavy
if ModuloInteger(wave,udg_HeavyFrequency)==0 then
set result=result*udg_HeavyCreepMultiplier
else
// Swarm
if ModuloInteger(wave,udg_SwarmFrequency)==0 then
set result=result*udg_SwarmCreepMultiplier
endif
endif
endif
return R2I(result)
endfunction
function getBurstAmount takes integer creeps returns integer
return R2I(SquareRoot(creeps))
endfunction
function getBurstSize takes integer wave, integer creeps returns integer
local integer result=1
// Burst
if ModuloInteger(wave,udg_BurstFrequency)==0 then
set result=getBurstAmount(creeps)
endif
return result
endfunction
function getSpawnTimerLength takes integer wave returns real
local real result=udg_SpawnFrequencyBase
// Heavy
if ModuloInteger(wave,udg_HeavyFrequency)==0 then
set result=result*udg_HeavyCreepTimeMultiplier
else
// Swarm
if ModuloInteger(wave,udg_SwarmFrequency)==0 then
set result=result*udg_SwarmSpawnTimeMultiplier
endif
// Burst
if ModuloInteger(wave,udg_BurstFrequency)==0 and ModuloInteger(wave,udg_AllInFrequency)!=0 then
set result=result*udg_BurstWaveSpeedMultiplier
endif
endif
if ModuloInteger(wave,udg_AllInFrequency)==0 then
set result=result*udg_AllInCreepTimeMultiplier
endif
return result
endfunction
function getCreepScore takes unit u returns integer
local real result=udg_WavePointBase
local integer k=GetHandleId(u)
// Armor
if isCreepArmor.evaluate(u) then
set result=result+udg_WaveArmorIncreaseFlat
endif
// Regenerator
if isCreepRegenerator.evaluate(u) then
set result=result+udg_WaveRegeneratorIncreaseFlat
endif
// Fast
if isCreepFast.evaluate(u) then
set result=result*udg_WaveFastIncrease
endif
// Healer
if isCreepHealer.evaluate(u) then
set result=result*udg_WaveHealerIncrease
endif
// Immune
if isCreepImmune.evaluate(u) then
set result=result*udg_WaveImmuneIncrease
endif
// Incrementor
if isCreepIncrementor.evaluate(u) then
set result=result*udg_WaveIncrementorIncrease
endif
return R2I(result)*(getCreepIntensity.evaluate(u)+1)
endfunction
function addPlayerScore takes player p, unit u returns nothing
local integer score=getCreepScore(u)
local integer k=GetHandleId(p)
call SaveInteger(udg_HashMovement,k,1,LoadInteger(udg_HashMovement,k,1)+score)
call SaveInteger(udg_HashMovement,k,5,LoadInteger(udg_HashMovement,k,5)+score)
endfunction
function flushPlayerScore takes player p returns nothing
local integer k=GetHandleId(p)
local integer score=LoadInteger(udg_HashMovement,k,5)
local integer difficulty=R2I(I2R(score)*udg_WavePointIncrease)
local integer previousDifficulty=LoadInteger(udg_HashMovement,k,2)
set difficulty=difficulty-R2I(previousDifficulty*udg_WavePointDecrease)
//call DisplayTextToPlayer(p,0,0,"Scored "+I2S(score))
//set score=R2I(I2R(score)*udg_WavePointIncrease)
if difficulty<0 then
call DisplayTextToPlayer(p,0,0,"Difficulty decreased by "+I2S(difficulty*100/previousDifficulty)+"%%")
else
if difficulty>0 then
call DisplayTextToPlayer(p,0,0,"Difficulty increased by "+I2S(difficulty*100/previousDifficulty)+"%%")
else
call DisplayTextToPlayer(p,0,0,"No difficulty change.")
endif
endif
call SaveInteger(udg_HashMovement,k,5,0)
set difficulty=previousDifficulty+difficulty
if difficulty<udg_WaveInitialPoint then
set difficulty=udg_WaveInitialPoint
endif
call SaveInteger(udg_HashMovement,k,2,difficulty)
//call DisplayTextToPlayer(p,0,0,"Difficulty is now "+I2S(LoadInteger(udg_HashMovement,k,2)))
endfunction
function giveMoveTower takes player p returns nothing
local unit u
local integer ut
call GroupEnumUnitsOfPlayer(Gug,p,null)
loop
set u=FirstOfGroup(Gug)
exitwhen u==null
set ut=GetUnitTypeId(u)
if ut=='h000' or ut=='h009' or ut=='h00A' then
call UnitAddAbility(u,'A00B')
endif
call GroupRemoveUnit(Gug,u)
endloop
endfunction
function initWaveTimer takes timer t returns nothing
local integer k=GetHandleId(t)
local integer k2
local player p
local integer array categories
local integer totalCreep
local integer head=0
local integer wave
local integer i
local integer j
local integer creepAmountMax
local timer burstTimer
local boolean survive=true
if t==null then
call DisplayTextToPlayer(Player(0),0,0,"Error : timer is null")
return
endif
set p=LoadPlayerHandle(udg_HashMovement,k,0)
set k2=GetHandleId(p)
set wave=LoadInteger(udg_HashMovement,k2,3)
set totalCreep=LoadInteger(udg_HashMovement,k2,2)/getCreepPointCost(wave)
//call DisplayTextToPlayer(p,0,0,"Total Creep : "+I2S(totalCreep))
if ModuloInteger(wave,udg_BossFrequency)==0 then
// Boss
// Get the nearest power of two
set i=1
loop
exitwhen totalCreep==0
set totalCreep=totalCreep/2
set i=i*2
endloop
// Getting it again
//set totalCreep=LoadInteger(udg_HashMovement,k2,2)/getCreepPointCost(wave)
set j=IAbsBJ(i-totalCreep)
if j<totalCreep/2 then
set i=i/2
endif
set i=i/2 // nerf of bosses
set j=0
loop
exitwhen i==0
set j=j+1
set i=i/2
endloop
// big group
call SaveInteger(udg_HashMovement,k,1,1)
call SaveInteger(udg_HashMovement,k,8,j)
// small group
call SaveInteger(udg_HashMovement,k,2,0)
else
// Non-Boss
set creepAmountMax=getWaveSize(wave)
//call DisplayTextToPlayer(p,0,0,"Max creep = "+I2S(creepAmountMax))
set categories[head]=totalCreep
if wave>=udg_SpecialFrequencyStart and ModuloInteger(wave-udg_SpecialFrequencyStart,udg_SplitterFrequency)==0 then
loop
exitwhen totalCreep<=creepAmountMax
set i=categories[head]
exitwhen i==0
if i>4 then
// Fuse 4 to get one bigger
set categories[head]=categories[head]-4
set categories[head+1]=categories[head+1]+1
set totalCreep=totalCreep-3
else
// Fuse one and its predecessor to get one bigger
// So i.e 1 1 1 1 1 1 -> 0 0 0 0 0 0 1
// 2nd i.e 1 1 0 1 0 1 -> 0 0 0 0 0 0 1
if i==1 and head>=1 then
if categories[head-1]==1 and totalCreep>creepAmountMax then
set categories[head-1]=0
set categories[head]=0
set categories[head+1]=categories[head+1]+1
set totalCreep=totalCreep-1
endif
endif
set head=head+1
endif
endloop
else
loop
exitwhen totalCreep<=creepAmountMax
set i=categories[head]
exitwhen i==0
if i>2 then
// Fuse 2 to get one bigger
set categories[head]=categories[head]-2
set categories[head+1]=categories[head+1]+1
set totalCreep=totalCreep-1
else
// Fuse one and its predecessor to get one bigger
// So i.e 1 1 1 1 1 1 -> 0 0 0 0 0 0 1
// 2nd i.e 1 1 0 1 0 1 -> 0 0 0 0 0 0 1
if i==1 and head>=1 then
if categories[head-1]==1 and totalCreep>creepAmountMax then
set categories[head-1]=0
set categories[head]=0
set categories[head+1]=categories[head+1]+1
set totalCreep=totalCreep-1
endif
endif
set head=head+1
endif
endloop
endif
/*set j=0
if totalCreep<creepAmountMax then
loop
exitwhen j<head
endloop
endif*/
set j=0
loop
exitwhen j>head
//call DisplayTextToPlayer(p,0,0,"categories["+I2S(j)+"] : "+I2S(categories[j]))
set j=j+1
endloop
loop
exitwhen categories[head+1]==0
set head=head+1
endloop
// big group
call SaveInteger(udg_HashMovement,k,1,categories[head])
call SaveInteger(udg_HashMovement,k,8,head)
//call DisplayTextToPlayer(p,0,0,"Big Creep : "+I2S(categories[head]))
// small group
if head>0 then
call SaveInteger(udg_HashMovement,k,2,categories[head-1])
else
call SaveInteger(udg_HashMovement,k,2,0)
endif
//call DisplayTextToPlayer(p,0,0,"Small Creep : "+I2S(LoadInteger(udg_HashMovement,k,2)))
// Burst
set burstTimer=LoadTimerHandle(udg_HashMovement,k,4)
// Create the timer if not existent
if burstTimer==null then
set burstTimer=CreateTimer()
call SaveTimerHandle(udg_HashMovement,k,4,burstTimer)
set i=GetHandleId(burstTimer)
call SaveTimerHandle(udg_HashMovement,i,10,t)
endif
if isBurst(wave) then
set i=getBurstAmount(categories[head]+categories[head-1])
// Burst size
call SaveInteger(udg_HashMovement,k,11,i)
// Burst wave left
call SaveInteger(udg_HashMovement,k,5,i)
// call TimerStart(burstTimer,udg_SpawnFrequencyBase*udg_BurstWaveSpeedMultiplier,true,null)
endif
endif
call BlzSetAbilityExtendedTooltip('S000',playerGetWaveTypeText.evaluate(wave,false),0)
call BlzSetAbilityExtendedTooltip('S001',playerGetWaveTypeText.evaluate(wave+1,false),0)
//if GetLocalPlayer()==p then
call PlaySoundBJ(gg_snd_RaiseSkeleton)
//endif
call playerDisplayWaveType.evaluate(p,getWave.evaluate(p))
call SaveBoolean(udg_HashMovement,k2,9,false)
call SaveInteger(udg_HashMovement,k2,8,0)
call TimerStart(t,getSpawnTimerLength(wave),true,function spawnTimerExpires)
set burstTimer=null
endfunction
function initPlayerWaveTimer takes player p returns nothing
local integer k=GetHandleId(p)
local timer t=LoadTimerHandle(udg_HashMovement,k,4)
call initWaveTimer(t)
set t=null
endfunction
function stringBackReturn takes boolean forMessage returns string
if forMessage then
return "\n\n"
endif
return "|n|n"
endfunction
function playerGetWaveTypeText takes integer wave, boolean forMessage returns string
local integer specialWave=wave-udg_SpecialFrequencyStart
local boolean isNormal=true
local string s=""
if wave<=0 then
set s=s+"|cffFF2222The wave "+I2S(wave)+" doesn't exist... you are not supposed to see that."
return s
endif
set s=s+"|cffFF8822Wave |cffFFFF00"+I2S(wave)
if forMessage then
set s=s+"|r\n"
else
set s=s+"|r|n"
endif
if ModuloInteger(wave,udg_BossFrequency)==0 then
set isNormal=false
set s=s+"--|cffFF0000[Boss |cffFFFFFF- one big creep"+stringBackReturn(forMessage)
else
if ModuloInteger(wave,udg_HeavyFrequency)==0 then
set s=s+"--|cffFF8822[Heavy |cffFFFFFF- bigger and fewer creeps, slower spawn"+stringBackReturn(forMessage)
set isNormal=false
else
if ModuloInteger(wave,udg_AllInFrequency)==0 then
set s=s+"--|cffFFFF00[All in |cffFFFFFF- every creep in a single burst"+stringBackReturn(forMessage)
set isNormal=false
else
if ModuloInteger(wave,udg_BurstFrequency)==0 then
set s=s+"--|cff7777FF[Burst |cffFFFFFF- creeps spawn in bursts"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(wave,udg_SwarmFrequency)==0 then
set s=s+"--|cff77FF77[Swarm |cffFFFFFF- smaller and more numerous creeps, faster spawn"+stringBackReturn(forMessage)
set isNormal=false
endif
endif
endif
endif
if specialWave>0 then
if ModuloInteger(specialWave,udg_FastFrequency)==0 then
set s=s+"--|cff00FFFF[Fast |cffFFFFFF- 50%% increased movement speed"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(specialWave,udg_ArmorFrequency)==0 then
set s=s+"--|cff777777[Armor |cffFFFFFF- Tower damage reduced by -5"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(specialWave,udg_SplitterFrequency)==0 then
set s=s+"--|cff999999[Splitter |cffFFFFFF- dead creeps splits in two smaller"+stringBackReturn(forMessage)
set isNormal=false
else
if ModuloInteger(specialWave,udg_ReducerFrequency)==0 then
set s=s+"--|cff555555[Reducer |cffFFFFFF- dead creeps decrement instead of dying"+stringBackReturn(forMessage)
set isNormal=false
endif
endif
if ModuloInteger(specialWave,udg_RegeneratorFrequency)==0 then
set s=s+"--|cff777777[Regenerator |cffFFFFFF- 5hp/s of regeneration"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(specialWave,udg_HealerFrequency)==0 then
set s=s+"--|cff00FF00[Healer |cffFFFFFF- creeps heals nearby creeps when dying"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(specialWave,udg_ImmuneFrequency)==0 then
set s=s+"--|cff007700[Immune |cffFFFFFF- Immune to slowness, burn and explosion"+stringBackReturn(forMessage)
set isNormal=false
endif
if ModuloInteger(specialWave,udg_IncrementorFrequency)==0 then
set s=s+"--|cff555500[Incrementor |cffFFFFFF- +1%% of HP max per second until +100%%"+stringBackReturn(forMessage)
set isNormal=false
endif
endif
if isNormal then
set s=s+"--|cff2222FF[Normal |cffFFFFFF- Nothing particular"
endif
return s
endfunction
function playerDisplayWaveType takes player p, integer wave returns nothing
local string s=playerGetWaveTypeText(wave,true)
call DisplayTextToPlayer(p,0,0,s)
endfunction
function disableCreep takes unit u returns nothing
call SetUnitPathing(u,false)
call IssueImmediateOrder(u,"stop")
call PauseUnit(u,true)
call ShowUnit(u,false)
call SetUnitInvulnerable(u,true)
call BlzSetUnitMaxHP(u,99999)
call SetWidgetLife(u,99999)
call UnitRemoveAbility(u,'A003')
call UnitRemoveAbility(u,'A002')
endfunction
function enableCreep takes unit u returns nothing
call SetUnitPathing(u,false)
call PauseUnit(u,false)
call ShowUnit(u,true)
call SetUnitInvulnerable(u,false)
call UnitRemoveAbility(u,'A003')
call UnitRemoveAbility(u,'A002')
endfunction
function isCreep takes unit u returns boolean
return GetUnitTypeId(u)=='h005'
endfunction
function isCreepImmune takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),11)
endfunction
function isCreepReducer takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),4)
endfunction
function setCreepReducer takes unit u, boolean b returns nothing
call SaveBoolean(udg_HashMovement,GetHandleId(u),4,b)
endfunction
function isCreepSplitter takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),5)
endfunction
function setCreepSplitter takes unit u, boolean b returns nothing
call SaveBoolean(udg_HashMovement,GetHandleId(u),5,b)
endfunction
function isCreepHealer takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),6)
endfunction
function isCreepFast takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),8)
endfunction
function isCreepArmor takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),9)
endfunction
function isCreepRegenerator takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),10)
endfunction
function getCreepIntensity takes unit u returns integer
return LoadInteger(udg_HashMovement,GetHandleId(u),7)
endfunction
function setCreepIntensity takes unit u, integer intensity returns nothing
if intensity<0 then
set intensity=0
endif
call SaveInteger(udg_HashMovement,GetHandleId(u),7,intensity)
endfunction
function decrementCreepIntensity takes unit u returns nothing
local integer intensity=getCreepIntensity(u)
if intensity>0 then
call setCreepIntensity(u,intensity-1)
else
call setCreepIntensity(u,0)
endif
endfunction
function getCreepMaxLife takes unit u returns integer
return R2I(Pow(2,getCreepIntensity(u))*10)
endfunction
function isCreepIncrementor takes unit u returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(u),12)
endfunction
function getCreepPlayer takes unit u returns player
return LoadPlayerHandle(udg_HashMovement,GetHandleId(u),200)
endfunction
function prepareCreepCopy takes unit u returns nothing
set udg_Intensity=getCreepIntensity(u)
set udg_Where=GetUnitLoc(udg_DamageEventTarget)
set udg_ForWho=getCreepPlayer(u)
set udg_Reducer=isCreepReducer(u)
set udg_Splitter=isCreepSplitter(u)
set udg_Healer=isCreepHealer(u)
set udg_Intensity=getCreepIntensity(u)
set udg_Fast=isCreepFast(u)
set udg_Armor=isCreepArmor(u)
set udg_Regenerator=isCreepRegenerator(u)
set udg_Immune=isCreepImmune(u)
endfunction
function waypointCreepCopy takes unit from, unit target returns nothing
local integer kFrom=GetHandleId(from)
local integer kTarget=GetHandleId(target)
local location l=LoadLocationHandle(udg_HashMovement,kFrom,0)
call SaveLocationHandle(udg_HashMovement,kTarget,0,l)
call SaveRectHandle(udg_HashMovement,kTarget,1,LoadRectHandle(udg_HashMovement,kFrom,1))
call IssuePointOrder(target,"move",GetLocationX(l),GetLocationY(l))
set l=null
endfunction
//===
function getWave takes player p returns integer
return LoadInteger(udg_HashMovement,GetHandleId(p),3)
endfunction
function getScore takes player p returns integer
return LoadInteger(udg_HashMovement,GetHandleId(p),1)
endfunction
function playerAddCreepAmount takes player p returns nothing
call SaveInteger(udg_HashMovement,GetHandleId(p),8,LoadInteger(udg_HashMovement,GetHandleId(p),8)+1)
//call DisplayTextToPlayer(p,0,0,"Increased to "+I2S(LoadInteger(udg_HashMovement,GetHandleId(p),8)))
endfunction
function playerRemCreepAmount takes player p returns nothing
call SaveInteger(udg_HashMovement,GetHandleId(p),8,LoadInteger(udg_HashMovement,GetHandleId(p),8)-1)
//call DisplayTextToPlayer(p,0,0,"Decreased to "+I2S(LoadInteger(udg_HashMovement,GetHandleId(p),8)))
endfunction
function getCreepAmount takes player p returns integer
return LoadInteger(udg_HashMovement,GetHandleId(p),8)
endfunction
function getDifficulty takes player p returns integer
return LoadInteger(udg_HashMovement,GetHandleId(p),2)
endfunction
function isWaveSpawnFinished takes player p returns boolean
return LoadBoolean(udg_HashMovement,GetHandleId(p),9)
endfunction
function getRemainingCreep takes player p returns integer
return LoadInteger(udg_HashMovement,GetHandleId(p),8)
endfunction
//===
function getSlowTimer takes unit u returns timer
return LoadTimerHandle(udg_HashMovement,GetHandleId(u),100)
endfunction
function getSlowIntensity takes player p returns real
return udg_SlowIntensityBase+(udg_SlowIntensityIncrement*I2R(GetPlayerTechCount(p,'R004',true)))
endfunction
function getSlowDuration takes player p returns real
return udg_SlowDurationBase+(udg_SlowDurationIncrement*I2R(GetPlayerTechCount(p,'R005',true)))
endfunction
function getBurnTimer takes unit u returns timer
return LoadTimerHandle(udg_HashMovement,GetHandleId(u),101)
endfunction
function getBurnDuration takes player p returns real
return udg_BurnDurationBase+(udg_BurnDurationIncrement*I2R(GetPlayerTechCount(p,'R006',true)-1))
endfunction
function getBurnDamageTimer takes unit u returns timer
return LoadTimerHandle(udg_HashMovement,GetHandleId(u),102)
endfunction
function getBurnDamage takes player p returns integer
return udg_BurnDamageBase+(GetPlayerTechCount(p,'R007',true))*udg_BurnDamageIncrement
endfunction
function getBurnFrequency takes player p returns real
return udg_BurnPeriodBase/(1.00+(udg_BurnPeriodIncrement*I2R(GetPlayerTechCount(p,'R008',true))))
endfunction
function getTowerDamage takes player p returns integer
return 10+(GetPlayerTechCount(p,'R000',true)*4)
endfunction
function getExplosionIntensity takes player p returns real
return udg_ExplosionDamageBase+(udg_ExplosionDamageIncrement*I2R(GetPlayerTechCount(p,'R009',true)-1))
endfunction
function getExplosionDamage takes player p returns real
return getExplosionIntensity(p)*getTowerDamage(p)
endfunction
function getExplosionRange takes player p returns integer
return R2I(udg_ExplosionRangeBase+(GetPlayerTechCount(p,'R00A',true)*udg_ExplosionRangeIncrement))
endfunction
function getIncrementorTimer takes unit u returns timer
return LoadTimerHandle(udg_HashMovement,GetHandleId(u),103)
endfunction
function startSlowTimer takes player p, unit u returns nothing
local integer slowIntensity=GetPlayerTechCount(p,'R004',true)
local integer slowDuration
local timer t=null
local integer kU
local integer kT
if slowIntensity>0 then
set slowDuration=GetPlayerTechCount(p,'R005',true)
set t=getSlowTimer(u)
set kU=GetHandleId(u)
if t==null then
set t=CreateTimer()
call SaveTimerHandle(udg_HashMovement,kU,100,t)
set kT=GetHandleId(t)
call SaveUnitHandle(udg_HashMovement,kT,0,u)
call SaveInteger(udg_HashMovement,kT,1,slowIntensity)
call SaveInteger(udg_HashMovement,kT,2,1)
call UnitAddAbility(u,'A002')
endif
call TimerStart(t,udg_SlowDurationBase+(udg_SlowDurationIncrement*I2R(slowDuration)),false, function timerExpire)
if isCreepFast(u) then
call SetUnitMoveSpeed(u,(udg_CreepSpeedBase*udg_CreepSpeedBonusMultiplier)/(udg_SlowIntensityBase+(udg_SlowIntensityIncrement*slowIntensity)))
else
call SetUnitMoveSpeed(u,udg_CreepSpeedBase/(udg_SlowIntensityBase+(udg_SlowIntensityIncrement*slowIntensity)))
endif
endif
endfunction
function startBurnTimer takes player p, unit u, unit tower returns nothing
local integer burnDuration=GetPlayerTechCount(p,'R006',true)
local integer burnFrequency
local integer burnDamage
local timer burnTimer=null
local timer burnDamageTimer=null
local integer kU
local integer kDuration
local integer kDamage
if burnDuration>0 then
set burnFrequency=GetPlayerTechCount(p,'R005',true)
set burnTimer=getBurnTimer(u)
set kU=GetHandleId(u)
if burnTimer==null then
// Burn duration
set burnTimer=CreateTimer()
call SaveTimerHandle(udg_HashMovement,kU,101,burnTimer)
set kDuration=GetHandleId(burnTimer)
call SaveUnitHandle(udg_HashMovement,kDuration,0,u)
call SaveInteger(udg_HashMovement,kDuration,2,2)
call UnitAddAbility(u,'A003')
// Burn period
set burnDamageTimer=CreateTimer()
call SaveTimerHandle(udg_HashMovement,kU,102,burnDamageTimer)
set kDamage=GetHandleId(burnDamageTimer)
call SaveUnitHandle(udg_HashMovement,kDamage,0,u)
call SaveInteger(udg_HashMovement,kDamage,1,getBurnDamage(p))
call SaveInteger(udg_HashMovement,kDamage,2,3)
call SaveUnitHandle(udg_HashMovement,kDamage,3,tower)
call TimerStart(burnDamageTimer,getBurnFrequency(p),true,function timerExpire)
endif
call TimerStart(burnTimer,getBurnDuration(p),false, function timerExpire)
endif
endfunction
function startIncrementorTimer takes unit u returns nothing
local timer t=getIncrementorTimer(u)
local integer kU=GetHandleId(u)
local integer kT
if t==null then
set t=CreateTimer()
call SaveTimerHandle(udg_HashMovement,kU,103,t)
set kT=GetHandleId(t)
call SaveUnitHandle(udg_HashMovement,kT,0,u)
call SaveInteger(udg_HashMovement,kT,1,0)
call SaveInteger(udg_HashMovement,kT,2,4)
endif
//call DisplayTextToPlayer(Player(0),0,0,"Started incrementor timer")
call TimerStart(t,udg_CreepIncrementorFrequency,true, function timerExpire)
endfunction
//===
function clearCreepEffects takes unit creep returns nothing
local timer t
// Slow
set t=getSlowTimer(creep)
if t!=null then
call FlushChildHashtable(udg_HashMovement,GetHandleId(t))
call SaveTimerHandle(udg_HashMovement,GetHandleId(t),100,null)
call DestroyTimer(t)
set t=null
endif
// Burn
set t=getBurnTimer(creep)
if t!=null then
call FlushChildHashtable(udg_HashMovement,GetHandleId(t))
call SaveTimerHandle(udg_HashMovement,GetHandleId(t),101,null)
call DestroyTimer(t)
set t=null
endif
set t=getBurnDamageTimer(creep)
if t!=null then
call FlushChildHashtable(udg_HashMovement,GetHandleId(t))
call SaveTimerHandle(udg_HashMovement,GetHandleId(t),102,null)
call DestroyTimer(t)
set t=null
endif
set t=getIncrementorTimer(creep)
if t!=null then
call FlushChildHashtable(udg_HashMovement,GetHandleId(t))
call SaveTimerHandle(udg_HashMovement,GetHandleId(t),103,null)
call DestroyTimer(t)
set t=null
endif
endfunction
function killCreep takes unit creep, unit tower returns nothing
local player p=GetOwningPlayer(tower)
local integer x
local integer y
local timer t
local unit u
local real r
local real r2
local effect e
// Increase the score of the player
call addPlayerScore(p,creep)
call disableCreep(creep)
set udg_DamageEventAmount=0
call clearCreepEffects(creep)
set udg_ScoreSoundIndex=udg_ScoreSoundIndex+1
if udg_ScoreSoundIndex>=20 then
set udg_ScoreSoundIndex=0
endif
call StartSound(udg_ScoreSound[udg_ScoreSoundIndex])
call TimerStart(udg_ScoreColorTimer,0.1,true,null)
set udg_ScoreColorIndex=0
// Explosion
set x=GetPlayerTechCount(p,'R009',true)
if x>0 and not isCreepImmune(creep) and not udg_Explosion and not burn then
set y=GetPlayerTechCount(p,'R00A',true)
set r=getExplosionRange(p)
set r2=getExplosionDamage(p)
call GroupEnumUnitsInRange(Gug,GetWidgetX(creep),GetWidgetY(creep),r,null)
set e=AddSpecialEffect("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl",GetUnitX(creep),GetUnitY(creep))
call BlzSetSpecialEffectScale(e,r/180)
call DestroyEffect(e)
loop
set u=FirstOfGroup(Gug)
exitwhen u==null
if u!=creep and isCreep(u) and not IsUnitPaused(u) and not isCreepImmune(u) then
set udg_Explosion=true
if R2I(GetWidgetLife(u))>r2 then
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncestralGuardianMissile\\AncestralGuardianMissile.mdl",GetWidgetX(u),GetWidgetY(u)))
call SetWidgetLife(u,GetWidgetLife(u)-r2)
else
call killCreep(u,tower)
endif
set udg_Explosion=false
endif
call GroupRemoveUnit(Gug,u)
endloop
endif
// Heal
if isCreepHealer(creep) then
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl",GetWidgetX(creep),GetWidgetY(creep)))
set r=getCreepMaxLife(creep)
call GroupEnumUnitsInRange(Gug,GetWidgetX(creep),GetWidgetY(creep),200,null)
loop
set u=FirstOfGroup(Gug)
exitwhen u==null
if u!=creep and isCreep(u) and not IsUnitPaused(u) then
call SetWidgetLife(u,GetWidgetLife(u)+r)
endif
call GroupRemoveUnit(Gug,u)
endloop
endif
// Split, reducer And basic death
if isCreepReducer(creep) or isCreepSplitter(creep) then
call enableCreep(creep)
if isCreepFast(creep) then
call SetUnitMoveSpeed(creep,udg_CreepSpeedBase*udg_CreepSpeedBonusMultiplier)
else
call SetUnitMoveSpeed(creep,udg_CreepSpeedBase)
endif
call decrementCreepIntensity(creep)
if getCreepIntensity(creep)<=0 then
call setCreepReducer(creep,false)
call setCreepSplitter(creep,false)
call setCreepIntensity(creep,0)
endif
call BlzSetUnitMaxHP(creep,getCreepMaxLife(creep))
call SetWidgetLife(creep,getCreepMaxLife(creep))
set r=80+(10*getCreepIntensity(creep))
call SetUnitScalePercent(creep,r,r,r)
call BlzSetUnitRealFieldBJ(creep,UNIT_RF_SELECTION_SCALE,r/100)
call waypointCreepCopy(creep,creep)
// if splitter, then we create an other one
if isCreepSplitter(creep) then
call prepareCreepCopy(creep)
call TriggerExecute(gg_trg_Spawn_Creep)
call RemoveLocation(udg_Where)
call waypointCreepCopy(creep,udg_CreepPool[udg_CreepPoolIndex])
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Polymorph\\PolyMorphTarget.mdl",GetUnitX(creep),GetUnitY(creep)))
else
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl",GetUnitX(creep),GetUnitY(creep)))
endif
else
set udg_CreepCurrentAmount=udg_CreepCurrentAmount-1
call playerRemCreepAmount(p)
if udg_Explosion then
set e=AddSpecialEffect("Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl",GetUnitX(creep),GetUnitY(creep))
call DestroyEffect(e)
endif
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Flare\\FlareCaster.mdl",GetUnitX(creep),GetUnitY(creep)))
// Finish the wave if it the last of the wave died
if isWaveSpawnFinished(p) then
if getRemainingCreep(p)<=0 then
// WAVE End
call waveEnd(p)
endif
endif
call SetUnitX(creep,9999)
call SetUnitY(creep,9999)
endif
call updateMultiboard.evaluate(p)
endfunction
function unitImpact takes nothing returns nothing
local unit creep=udg_DamageEventTarget
local unit tower=udg_DamageEventSource
local real damage=udg_DamageEventAmount
local integer kC=GetHandleId(creep)
local player p=GetOwningPlayer(tower)
local timer t
local integer kT
local integer x
local integer y
local real r
local real r2
local unit u
local boolean survive=true
if not udg_Explosion then
set damage=BlzGetUnitBaseDamage(tower,0)+1
endif
if isCreepArmor(creep) then
set damage=damage-5
endif
if IsUnitPaused(creep) then
set damage=0
endif
if damage<0 then
set damage=0
endif
set udg_DamageEventAmount=damage
if damage>=R2I(GetWidgetLife(creep)) then// or udg_DamageImpact==1 then
//call DisplayTextToPlayer(p,0,0,"The unit died")
//set udg_LaunchImpact=0
// DEATH
if isCreep(creep) then
set survive=false
call killCreep(creep,tower)
endif
else
if not IsUnitPaused(creep) then
if not isCreepImmune(creep) then
if not udg_Explosion then
// Slow
call startSlowTimer(p,creep)
// Burn
call startBurnTimer(p,creep,tower)
else
call SetWidgetLife(creep,GetWidgetLife(creep)-damage)
endif
endif
endif
endif
set creep=null
set tower=null
set p=null
set t=null
set u=null
set udg_b=survive
endfunction
function unitImpactInit takes nothing returns nothing
set unitImpactTrig=CreateTrigger()
call TriggerRegisterVariableEvent(unitImpactTrig,"udg_DamageEvent",EQUAL,1.0)
call TriggerAddAction(unitImpactTrig,function unitImpact)
endfunction
function unitImpactManual takes unit creep, unit tower, real damage returns boolean
set udg_DamageEventTarget=creep
set udg_DamageEventSource=tower
set udg_DamageEventAmount=damage
call unitImpact()
return udg_b
endfunction
function updateMultiboard takes player p returns nothing
// Player : p
local integer kP=GetHandleId(p)
local integer iP=GetConvertedPlayerId(p)
local real r
local real r2
// wave
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,1,I2S(getWave(p)))
// score
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,2,udg_ScoreColor[udg_ScoreColorIndex]+I2S(getScore(p)))
// Tower firerate
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,3,R2S((udg_TowerAttackSpeedBase-(udg_TowerAttackSpeedDecrement*I2R(GetPlayerTechCount(p,'R002',true))))))
// Tower projectile speed
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,4,I2S((R2I(udg_TowerProjectileSpeedBase+(udg_TowerProjectileSpeedIncrement*GetPlayerTechCount(p,'R003',true))))))
if GetPlayerTechCountSimple('R004',p)>0 then
// Tower Slowness
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,5,R2S(getSlowIntensity(p)))
// Tower Slowness length
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,6,R2S(getSlowDuration(p)))
endif
if GetPlayerTechCount(p,'R006',true)>0 then
// Burn duration
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,7,R2S(getBurnDuration(p)))
// Burn damage
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,8,I2S(getBurnDamage(p)))
// Burn frequency
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,9,R2S(getBurnFrequency(p)))
endif
if GetPlayerTechCount(p,'R009',true)>0 then
// Explosion damage
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,10,R2S(getExplosionIntensity(p)))
// Explosion range
call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,11,I2S(getExplosionRange(p)))
endif
// Remaining creeps
//call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,12,I2S(getCreepAmount(p)))
// Creep score difficulty
//call MultiboardSetItemValueBJ(udg_MainBoard[iP],2,13,I2S(getDifficulty(p)))
endfunction
endlibrary
function Trig_Tak_Actions takes nothing returns nothing
local unit u=GetAttacker()
local integer ut=GetUnitTypeId(u)
local location l=GetUnitLoc(u)
call AddSpecialEffectLocBJ(l,"Abilities\\Weapons\\WitchDoctorMissile\\WitchDoctorMissile.mdl" )
call DestroyEffectBJ(GetLastCreatedEffectBJ())
if ut=='h000' or ut=='h00A' then
call AddSpecialEffectLocBJ(l,"Abilities\\Weapons\\Mortar\\MortarMissile.mdl")
call DestroyEffectBJ(GetLastCreatedEffectBJ())
endif
if ut=='h009' then
call AddSpecialEffectLocBJ(l,"Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl")
call DestroyEffectBJ(GetLastCreatedEffectBJ())
call AddSpecialEffectLocBJ(l,"Abilities\\Weapons\\wyvernspear\\wyvernspearmissile.mdl")
call DestroyEffectBJ(GetLastCreatedEffectBJ())
endif
call RemoveLocation(l)
//call TriggerSleepAction(.25)
//call AddSpecialEffectTargetUnitBJ("head",u,"Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl)
//call BlzSetSpecialEffectTimeScale(GetLastCreatedEffectBJ(),.25)
//call DestroyEffectBJ(GetLastCreatedEffectBJ())
endfunction
//===========================================================================
function InitTrig_Tak takes nothing returns nothing
set gg_trg_Tak = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Tak, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddAction( gg_trg_Tak, function Trig_Tak_Actions )
endfunction