/*
function B2S takes boolean bool returns string
if(bool)then
return "true"
endif
return "false"
endfunction
function Player2S takes player p returns string
return "Player("+I2S(GetPlayerId(p))+")"
endfunction
function Unit2S takes unit u returns string
return GetUnitName(u)+ "_"+I2S(GetHandleId(u)-0x100000)
endfunction
*/
Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AGI_DEFENSE_BASE | real | No | 5.00 |
AGI_DEFENSE_BONUS | real | No | 0.10 |
AlreadyPausedUnits | group | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | 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 | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
AssassinPackSize | integer | No | |
AssassinTimer | timer | No | |
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 | |
BAmr_Attribute | real | Yes | |
BAmr_Boolean | boolean | Yes | |
BAmr_Config_ABSORBTION | real | No | |
BAmr_Config_ATT_BONUS | real | Yes | |
BAmr_Config_BASE_HP | real | No | |
BAmr_Config_BUFF | buffcode | No | |
BAmr_Config_FLAVOR | integer | No | |
BAmr_Config_FLAVOR_PATH | string | Yes | |
BAmr_Config_LVL_HP_BONUS | real | Yes | |
BAmr_Config_PERIODIC | real | No | |
BAmr_Config_RESIST_PHYSICAL | real | No | |
BAmr_Config_RESIST_SPELL | real | No | |
BAmr_Config_SEG_VALUE | real | Yes | |
BAmr_Config_SEGMENT_SPAWNED | integer | No | |
BAmr_Config_SPEF | effect | No | |
BAmr_Config_SPEF_PATH | string | Yes | |
BAmr_Config_SPEF_VALUE | real | Yes | |
BAmr_Config_SPELL_ID | abilcode | No | |
BAmr_Current_Rot_Speed | real | Yes | |
BAmr_DMG_Event | real | No | |
BAmr_Enchanted_Unit | unit | Yes | |
BAmr_Health | real | Yes | |
BAmr_Index | integer | No | |
BAmr_Loop | integer | No | |
BAmr_Loop_Segment | integer | No | |
BAmr_Max | real | Yes | |
BAmr_Point | location | Yes | |
BAmr_Real | real | Yes | |
BAmr_Seg_CValue | integer | No | |
BAmr_Seg_CValue_DeIndex | integer | No | |
BAmr_Segment_Missile | effect | Yes | |
BAmr_Segment_Missile_State | string | Yes | |
BAmr_Spef_Current_Height | real | Yes | |
BAmr_Total | real | Yes | |
BAmr_Unit | unit | Yes | |
Banehallow | unit | No | |
Beast_Attack_Ability_Level | integer | No | |
Beast_Attack_Atribute | integer | No | |
Beast_Attack_Atribute_Damage | real | No | |
Beast_Attack_Caster | unit | No | |
Beast_Attack_Damage_Splitter | integer | No | |
Beast_Attack_Life_Damage | real | No | |
Beast_Attack_Location | location | No | |
Beast_Attack_Location2 | location | No | |
Beast_Attack_Max_Life | real | No | |
Beast_Attack_Target | unit | No | |
Beast_Attack_Total_Damage | real | No | |
BoostLevel | integer | No | |
Boss1Point | location | No | |
BossUnits | group | No | |
BuildingDeadPackSize | integer | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
ChallengerNumber | integer | No | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
CinermaticArthas | unit | No | |
CleanedItem | item | Yes | |
ClockTimer | timer | No | |
ConfirmDialog | dialog | No | |
ConnectedPlayers | force | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CountdownTimer | timer | No | |
CreepTimer | timer | No | |
CreepTimerW | timerdialog | No | |
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 | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageReturnAbsolutes | real | Yes | |
DamageReturnAllowedPlayers | force | No | |
DamageReturnCodeMultiplier | real | No | |
DamageReturnComputeTimes | real | Yes | |
DamageReturnExpireTime | real | No | |
DamageReturnFactor | real | No | |
DamageReturnInputUnit | unit | No | |
DamageReturnMeleeMultiplier | real | No | |
DamageReturnOutputAbsolute | real | No | |
DamageReturnOutputPercentage | real | No | |
DamageReturnPercentages | real | Yes | |
DamageReturnRangedMultiplier | real | No | |
DamageReturnSpellMultiplier | real | No | |
DamageReturnTempInteger | integer | No | |
DamageReturnUnitIndex | integer | 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 | |
DarkBossArmorIncPerPlayer | real | No | |
DarkBossArmorIncPerSqrtDiff | real | No | |
DarkBossArmorInit | real | No | |
DarkBossStatsIncPerPlayer | integer | No | |
DarkBossStatsIncPerSqrtDiff | integer | No | |
DarkBossStatsInit | integer | No | |
DarkCome | rect | Yes | |
DarkHeroAbilities | abilcode | Yes | |
DarkHeroArmorIncPerSqrtDiffLvl | real | No | |
DarkHeroArmorInit | real | No | |
DarkHeroStatsIncPerSqrtDiffLvl | integer | No | |
DarkHeroStatsInit | integer | No | |
DarkHeroType | unitcode | Yes | |
DarkTowerDestroyedCount | integer | Yes | 0 |
DarkUnitType | unitcode | Yes | |
DeathEvent | real | No | |
DEFENSE_ARMOR | real | No | 0.06 |
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 | |
DefensePoint | location | No | |
DefenseTypeDebugStr | string | Yes | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
Difficulty | integer | No | 1 |
DotaHashtable | hashtable | No | |
DragonAttackPeriod | real | No | |
DragonAttackPoint | location | Yes | |
DragonAttackTypes | unitcode | Yes | |
DragonPackSize | integer | No | |
DragonTimer | timer | No | |
DualHeroChange | boolean | Yes | |
DualHeroPoint | location | Yes | |
EasyItem__ERRORMESSAGE | string | No | |
EasyItem__ERRORSOUND | string | No | |
EasyItem__ShopChargedItemCount | integer | No | |
EasyItem__ShopDummyCharges | itemcode | Yes | |
EasyItem__ShopRealCharges | itemcode | Yes | |
EasyItem__SPLIT | boolean | No | |
EasyItem__SPLITDROP | boolean | No | |
EasyItem__SPLITSIZE | integer | No | |
EasyItem__SPLITSTACK | boolean | No | |
EasyItem__SPLITSTACKDELAY | real | No | |
EasyItem__USEITEMLEVEL | boolean | No | |
EasyItem_integer | integer | Yes | |
EasyItem_item | item | No | |
EasyItem_items | item | Yes | |
EasyItem_loopIndex | integer | No | |
EasyItem_point | location | Yes | |
EasyItem_sound | sound | No | |
EasyItem_string | string | Yes | |
EasyItem_timer | timer | No | |
EasyItem_unit | unit | No | |
EasyItem_units | unit | Yes | |
EffectCenter | effect | No | |
EffectIn1 | effect | Yes | |
EffectIn2 | effect | Yes | |
EffectIn3 | effect | Yes | |
EffectIn4 | effect | Yes | |
EffectOut1 | effect | Yes | |
EffectOut2 | effect | Yes | |
EnhancedDamageTarget | unit | No | |
ExtremeGroup | group | No | |
ExtremePowerupPeriod | real | No | |
FarmEventCooldown | real | No | |
FarmEventDuration | real | No | |
FarmEventMaxFrequency | real | No | |
FarmEventRespawnPending | boolean | Yes | |
FarmEventSpawns | group | Yes | |
FarmEventTimer | timer | Yes | |
FarmUnitType | unitcode | Yes | |
FarmUnitTypeIndex | integer | Yes | |
FinalBossCenter | location | No | |
FinalWaveArmorIncPerPlayer | real | No | |
FinalWaveArmorIncPerSqrtDiff | real | No | |
FinalWaveArmorInit | real | No | |
FinalWaveCooldown | real | No | |
FinalWaveStatsIncPerPlayer | integer | No | |
FinalWaveStatsIncPerSqrtDiff | integer | No | |
FinalWaveStatsInit | integer | No | |
GameLevel | integer | Yes | 0 |
GameLevelCooldowns | real | Yes | |
GlobalTempAbilityCode | abilcode | No | |
GlobalTempBoolean | boolean | No | |
GlobalTempForce | force | No | |
GlobalTempGroup | group | No | |
GlobalTempInteger | integer | No | |
GlobalTempInteger1 | integer | No | |
GlobalTempItem | item | No | |
GlobalTempItem1 | item | No | |
GlobalTempPlayer | player | No | |
GlobalTempPlayer1 | player | No | |
GlobalTempPoint | location | No | |
GlobalTempReal | real | No | |
GlobalTempReal1 | real | No | |
GlobalTempRegion | rect | No | |
GlobalTempString | string | No | |
GlobalTempUnit | unit | No | |
GlobalTempUnitType | unitcode | No | |
HeroAttackInterval | real | No | |
HeroBaseDamage | integer | No | |
HeroDefense | real | No | |
HeroMaxHP | integer | No | |
Host | player | No | |
IceGates | destructable | Yes | |
IcePillars | unit | Yes | |
IceTowers | unit | Yes | |
IceWayOpened | boolean | Yes | |
InitialPlayers | force | No | |
InnerCircleHeroCount | integer | No | 11 |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
ItemAbilities | abilcode | Yes | |
ItemAbilityCount | integer | No | |
ItemCleanupFlag | boolean | No | |
ItemCleanupTimer | timer | No | |
ItemsToClean | integer | No | |
KillerOfUnit | unit | Yes | |
Kills | integer | Yes | 0 |
Knockback_Loc1 | location | No | |
Knockback_Loc2 | location | No | |
Knockback_Target | unit | No | |
KnockbackAngle | real | No | |
KnockbackDistance | real | No | |
KnockbackSpeed | real | No | |
KnockbackTable | hashtable | No | |
KnockbackUnits | group | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LevelDragonTypes | unitcode | Yes | |
LifeStealAllowedPlayers | force | No | |
LifeStealCodeMultiplier | real | No | |
LifeStealComputeTimes | real | Yes | |
LifeStealExpireTime | real | No | |
LifeStealFactor | real | No | |
LifeStealInputUnit | unit | No | |
LifeStealMeleeMultiplier | real | No | |
LifeStealOutputPercentage | real | No | |
LifeStealPercentages | real | Yes | |
LifeStealRangedMultiplier | real | No | |
LifeStealSpellMultiplier | real | No | |
LifeStealUnitIndex | integer | No | |
LightHeroes | unit | Yes | |
LightHeroesAddedStats | integer | Yes | |
LightHeroRestTime | real | No | 0.00 |
LightHeroRestTimers | timer | Yes | |
LightHeroSaveDirection | real | Yes | 0 |
LightHeroSavePoint | location | Yes | |
LightHeroTimerW | timerdialog | Yes | |
LightningSwordEventDuration | real | No | |
LocalTempAbilityCode | abilcode | No | |
LocalTempGroup | group | No | |
LocalTempIndex | integer | No | |
LocalTempIndex1 | integer | No | |
LocalTempInteger | integer | No | |
LocalTempInteger1 | integer | No | |
LocalTempItem | item | No | |
LocalTempItem1 | item | No | |
LocalTempPlayer | player | No | |
LocalTempPlayer1 | player | No | |
LocalTempPoint | location | No | |
LocalTempPoint1 | location | No | |
LocalTempPoint2 | location | No | |
LocalTempReal | real | No | |
LocalTempString | string | No | |
LocalTempUnit | unit | No | |
LocalTempUnit1 | unit | No | |
Loop | integer | No | |
ModeEasy | boolean | No | |
ModeRandom | boolean | No | |
ModeSame | boolean | No | |
MUAdditionalAbilities | abilcode | Yes | |
MUAdditionalAbilitiesCount | integer | No | |
MUAttackSpeedBonusPercent | real | No | |
MUBaseDamageBonus | integer | No | |
MUBaseDamageBonusPercent | real | No | |
MUDefenseBonus | real | No | |
MUDefenseBonusPercent | real | No | |
MUI_3 | integervar | No | |
MUMaxHPBonus | integer | No | |
MUMaxHPBonusPercent | real | No | |
MUPrevAdditionalAbilities | abilcode | Yes | |
MUPrevAdditionalAbilitiesCount | integer | No | |
MUPrevAttackSpeedBonusPercent | real | No | |
MUPrevBaseDamageBonus | integer | No | |
MUPrevBaseDamageBonusPercent | real | No | |
MUPrevDefenseBonus | real | No | |
MUPrevDefenseBonusPercent | real | No | |
MUPrevMaxHPBonus | integer | No | |
MUPrevMaxHPBonusPercent | real | No | |
Muradin | unit | No | |
MuradinEventCooldown | real | No | |
MuradinEventDuration | real | No | |
MURefreshTrigger | trigger | No | |
MURegisteredPlayers | force | No | |
MusicPoint | integer | No | 1 |
MUTempIndex | integer | No | |
MUTempReal | real | No | |
MUTempUnit | unit | No | |
MUTempUnitGroup | group | No | |
NeutralHeroType | unitcode | Yes | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
OnDamageEvent | real | No | |
OptionGameButtonEasy | button | No | |
OptionGameButtonExtreme | button | No | |
OptionGameButtonNormal | button | No | |
OptionGameDialog | dialog | No | |
OptionHeroButtonDual | button | No | |
OptionHeroButtonDualRandom | button | No | |
OptionHeroButtonDualSame | button | No | |
OptionHeroButtonNormal | button | No | |
OptionHeroButtonRandom | button | No | |
OptionHeroButtonSame | button | No | |
OptionHeroDialog | dialog | No | |
OuterCircleHeroCount | integer | No | 19 |
PDex | integer | No | |
PickMockHeroes | unit | Yes | |
PlayerColors | string | Yes | |
PlayerCount | integer | No | |
PlayerScore | integer | Yes | 0 |
PlayerSelection | group | Yes | |
PlayerSelectionEvent | real | No | |
POINT | location | No | |
PowerUpDummy | group | No | |
PreDamageEvent | real | No | |
Quests | quest | Yes | |
RandomHero | integer | Yes | 0 |
RandomNumber | integer | Yes | |
RemoveDamageEvent | boolean | No | |
RemovedPlayerIndex | integer | No | |
RingOfSuperiorityEventDuration | real | No | |
RosHashtable | hashtable | No | |
RunePoint | location | No | |
RuneTypeCount | integer | No | |
RuneTypes | itemcode | Yes | |
Scream_Ability_Level | integer | No | |
Scream_Area_of_Effect | real | No | |
Scream_Base_Area_of_Effect | real | No | |
Scream_Base_Damage | real | No | |
Scream_Bounus_Area_of_Effect | real | No | |
Scream_Caster | unit | No | |
Scream_Damage_Group | group | No | |
Scream_Dummy_Ability | abilcode | No | |
Scream_Location | location | No | |
Scream_Owner | player | No | |
Scream_Sound | sound | No | |
Scream_Sound_Volume | real | No | |
Scream_Total_Damage | real | No | |
SelectAreaCenter | location | No | |
SelectedHero | unit | Yes | |
SilentAssassinAttackPeriod | real | No | |
SilentAssassinTypes | unitcode | Yes | |
SourceDamageEvent | real | No | |
SPAgainstHeroModifier | real | No | |
SPAttributeDamageModifier | real | Yes | |
Special23ArmorIncPerSqrtDiff | real | No | |
Special23ArmorInit | real | No | |
Special23StatsIncPerSqrtDiff | integer | No | |
Special23StatsInit | integer | No | |
Special4Challenger | integer | No | |
Special4Group | group | No | |
Special5Challenger | integer | No | |
Special5Group | group | No | |
Special67ArmorIncPerSqrtDiff | real | No | |
Special67ArmorInit | real | No | |
Special67StatsIncPerSqrtDiff | integer | No | |
Special67StatsInit | integer | No | |
Special8Group | group | No | |
SpecialArea | rect | Yes | |
SpecialArenaCenter | location | No | |
Specials04Check | boolean | Yes | false |
Specials05Check | boolean | Yes | false |
SpecialsButtonExtreme1 | button | No | |
SpecialsButtonExtreme2 | button | No | |
SpecialsButtonExtreme3 | button | No | |
SpecialsButtonExtreme4 | button | No | |
SpecialsDialog | dialog | No | |
SpecialsExit | button | No | |
SpecialsNo | button | No | |
SpecialsYes | button | No | |
SpecialTimer | timer | No | |
SpecialTimerW | timerdialog | No | |
SpellDummyEffect | effect | Yes | |
SpellDummyUnit | unit | Yes | |
SPTempReal | real | No | |
StartPoint | location | No | |
SummonerOfUnit | unit | Yes | |
SuperItemTypeCount | integer | No | |
SuperItemTypes | itemcode | Yes | |
Survival2Center | location | No | |
SurvivalBountyPerPlayer | integer | No | |
SurvivalCome | rect | Yes | |
SurvivalWave | integer | No | |
TCAAvalancheCaster | unit | No | |
TCAFixAbilityCount | integer | No | |
TCAFixAbilityList | abilcode | Yes | |
TCAFixDeathTriggers | trigger | Yes | |
TCAFixOrderIssuedTriggers | trigger | Yes | |
TCAFixRegisteredUnits | group | No | |
TCAFixResumeHoldPosTrigger | trigger | No | |
TCAFixTargetAcquiredTriggers | trigger | Yes | |
TCAFixTempBoolean | boolean | No | |
TCAFixTempBoolean1 | boolean | No | |
TCAFixTempInteger | integer | No | |
TCAFixTempInteger1 | integer | No | |
TCAFixTempPoint | location | No | |
TCAFixTempPoint1 | location | No | |
TCAFixTempString0 | string | No | |
TCAFixTempString1 | string | No | |
TCAFixTempString2 | string | No | |
TCAFixTempUnit | unit | No | |
TCAFixUnitAttackedTrigger | trigger | No | |
TCAFixUnitHoldPositionBroken | boolean | Yes | |
TCAFixUnitHoldsPosition | boolean | Yes | |
TCAFixUnitLastAcquireTime | real | Yes | |
TCAFixUnitLastAttackTime | real | Yes | |
TCAFixUnitPatrols | boolean | Yes | |
TCATempIndex | integer | No | |
TempAvalancheDamages | real | No | |
TempTossCaster | unit | No | |
TempTossDamages | real | No | |
TempTossProjectedUnit | unit | No | |
TomesCount | integer | No | 3 |
TYPE | unitcode | No | |
UDex | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexUnits | unit | Yes | |
UG | group | No | |
UNIT | unit | No | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
UnitAttackInterval | real | No | |
UnitBaseDamage | integer | No | |
UnitDefense | real | No | |
UnitInAction | boolean | Yes | |
UnitInActionEvent | real | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitMaxHP | integer | No | |
UnitQuantity | integer | Yes | 0 |
UnitRace | integer | Yes | 0 |
UnitType | integer | Yes | 0 |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
VictoryCooldown | real | No | |
ViewCircle | fogmodifier | Yes | |
WarnTimer | timer | No | |
WaveCome | rect | Yes | |
WaveKills | integer | Yes | 0 |
WaveNumber | integer | No | |
WavePeriod | real | No | |
WaveTimer | timer | No | |
WaveTimerW | timerdialog | No | |
WaveUnitType | unitcode | Yes | |
WayCount | integer | No | 0 |
WayGates | destructable | Yes | |
WayNecropolis | unit | Yes | |
WayOpened | boolean | Yes | false |
WayTowers | unit | Yes | |
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 | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
ZeroDamageEvent | real | No |
library DebugLogger requires TimeUtils
globals
// --------------------------------------------------------------------
// Enum log levels
// --------------------------------------------------------------------
constant integer LVL_DEBUG = 0
constant integer LVL_INFO = 1
constant integer LVL_WARN = 2
constant integer LVL_ERROR = 3
private constant integer LVL_NONE = 999 // Only for internal reference, do not use
private string array LevelTags [4]
private string array ColorTags [4]
// --------------------------------------------------------------------
// Config: display
// --------------------------------------------------------------------
private integer DISPLAY_LEVEL = LVL_NONE // Everything of lower level is not displayed
private constant real DISPLAY_TIME = 3.00 // Display time in seconds
// --------------------------------------------------------------------
// Config: write
// --------------------------------------------------------------------
private integer WRITE_LEVEL = LVL_NONE
private integer WRITENOW_LEVEL = LVL_NONE
private constant integer FILE_MAX_ENTRIES = 500 // Min 1, Max 8192
private constant string OUTPUT_FILE_NAME = "XndHeroSiegeLog" // Output file prefix. File number & .txt extensions are automatically added.
// --------------------------------------------------------------------
// Internal
// --------------------------------------------------------------------
private string array WriteLogs
private integer FirstWriteLogIndex = -1 // Start iterator (for read)
private integer LastWriteLogIndex = -1 // End iterator (for read & write)
private integer FileIndex = 0
endglobals
static if (FILTER_USERS) then
// --------------------------------------------------------------------
// DebugUserFilter: logs will display only to the players matching it
// Does not impact log writing in text file.
// --------------------------------------------------------------------
private function DebugUserFilter takes nothing returns boolean
local integer index = 0
loop
if ( GetPlayerName(GetEnumPlayer()) == ONLY_USERS[index] ) then
return true
endif
set index = index + 1
exitwhen (index >= ONLY_USERS.size)
endloop
return false
endfunction
endif
// --------------------------------------------------------------------
// SetLogLevel: set display & write log level
// --------------------------------------------------------------------
function SetLogLevel takes integer displayLevel, integer writeLevel, integer writeNowLevel returns nothing
set DISPLAY_LEVEL = displayLevel
set WRITE_LEVEL = writeLevel
set WRITENOW_LEVEL = writeNowLevel
endfunction
// --------------------------------------------------------------------
// WriteInFile: write up to last 8191 logs to the output file
// --------------------------------------------------------------------
function WriteInFile takes nothing returns nothing
local integer index
// There are logs to write in file
call PreloadGenClear()
call PreloadGenStart()
call Preload("Log file")
if ( (FirstWriteLogIndex != -1) and (LastWriteLogIndex != -1) ) then
set index = FirstWriteLogIndex
loop
call Preload(WriteLogs[index])
set index = index + 1
if ( index == 8191 ) then
set index = 0
endif
exitwhen index == LastWriteLogIndex
endloop
else
call Preload("<Empty log file>")
endif
call PreloadGenEnd(OUTPUT_FILE_NAME + "-" + I2S(FileIndex) + ".txt" )
endfunction
// --------------------------------------------------------------------
// DisplayLog: displays log as text
// --------------------------------------------------------------------
private function DisplayLog takes integer level, string message returns nothing
call DisplayTimedTextToForce( GetPlayersAll() , DISPLAY_TIME, LevelTags[level] + " " + "|c00" + ColorTags[level] + message +"|r" )
endfunction
// --------------------------------------------------------------------
// SavePrintLog: format logs and save them internally.
// If reached max file entry: prints file and goes to next file index.
// If level >= WRITENOW_LEVEL, then calls the WriteInFile() function.
// --------------------------------------------------------------------
private function SavePrintLog takes integer level, string message returns nothing
local string printMessage = ""
local real elapsedTime = TimerGetElapsed(udg_ClockTimer)
local string elapsedTimeString = FormatTime(elapsedTime)
if (FILE_MAX_ENTRIES == LastWriteLogIndex + 1 ) then
// Write this log file to disk and go to the next log file
call WriteInFile()
set FileIndex = FileIndex + 1
set FirstWriteLogIndex = -1
set LastWriteLogIndex = -1
endif
// Move last cursor
set LastWriteLogIndex = ModuloInteger(LastWriteLogIndex + 1, 8191)
// Move first cursor (when it is pushed front by last cursor)
if ( -1 == FirstWriteLogIndex ) then
set FirstWriteLogIndex = 0 // Start
elseif ( FirstWriteLogIndex == LastWriteLogIndex ) then
set FirstWriteLogIndex = ModuloInteger(FirstWriteLogIndex + 1, 8191) // Rolling logs
endif
// Print formating
set printMessage = LevelTags[level] + " [" + elapsedTimeString + "] " + message
// Save logs in a string array
set WriteLogs[LastWriteLogIndex] = printMessage
if (level >= WRITENOW_LEVEL) then
// Write this log file to disk
call WriteInFile()
endif
endfunction
// --------------------------------------------------------------------
// DebugLog: API function to push a new log.
// --------------------------------------------------------------------
function DebugLog takes integer level, string message returns nothing
if ( level >= DISPLAY_LEVEL ) then
call DisplayLog(level, message)
endif
if ( level >= WRITE_LEVEL ) then
call SavePrintLog(level, message)
endif
endfunction
// ----------------------------------------------------------------------------
// onInit: system initializer
// ----------------------------------------------------------------------------
private module M
private static method onInit takes nothing returns nothing
set LevelTags[LVL_DEBUG] = "[DEBUG]"
set LevelTags[LVL_INFO] = "[INFO] "
set LevelTags[LVL_WARN] = "[WARN] "
set LevelTags[LVL_ERROR] = "[ERROR]"
set ColorTags[LVL_DEBUG] = "999999"
set ColorTags[LVL_INFO] = "fffff"
set ColorTags[LVL_WARN] = "ff7f00"
set ColorTags[LVL_ERROR] = "ff0000"
endmethod
endmodule
private struct S extends array
implement M
endstruct
endlibrary
// Just set the log levels when REPLAY is detected
library LogDuringReplay requires DebugLogger, GameStatus
private module LogDuringReplayInit
private static method onInit takes nothing returns nothing
if ( GAME_STATUS_REPLAY == GetGameStatus() ) then
call SetLogLevel(LVL_ERROR, LVL_DEBUG, LVL_DEBUG)
endif
endmethod
endmodule
private struct LogDuringReplay
implement LogDuringReplayInit
endstruct
endlibrary
// -------------------------------------------------------------------------------
// Library: automatically log some primitives known for desync
// -------------------------------------------------------------------------------
library PrimitiveDebugAutomation requires DebugLogger
// -------------------------------------------------------------------------------
// LOG_NATIVE: macro that adds a log function to a native (with a hook)
// -------------------------------------------------------------------------------
//! textmacro LOG_NATIVE takes NATIVE, PARAMETERS, LOG_LEVEL
public function on$NATIVE$ takes $PARAMETERS$ returns nothing
call DebugLog(LVL_$LOG_LEVEL$, "$NATIVE$")
endfunction
hook $NATIVE$ on$NATIVE$
//! endtextmacro
// -------------------------------------------------------------------------------
// Logged native declarations
// -------------------------------------------------------------------------------
/* Natives that may be watched for desync debugging
GetDestructableName
GetSoundDuration
GetSoundFileDuration
GetCameraBoundMinX
GetCameraBoundMinY
GetCameraBoundMaxX
GetCameraBoundMaxY
GetCameraField
GetCameraTargetPositionX
GetCameraTargetPositionY
GetCameraTargetPositionZ
GetCameraTargetPositionLoc
GetCameraEyePositionX
GetCameraEyePositionY
GetCameraEyePositionZ
GetCameraEyePositionLoc
GetObjectName
IsMultiboardMinimized
GetLocalPlayer
GetLocationZ
GetLocalizedString
GetLocalizedHotkey
GetUnitName
BlzGetLocalUnitZ
BlzGetUnitZ
GetItemName
BlzGetItemDescription
BlzGetItemTooltip
BlzGetItemExtendedTooltip
SmartCameraPanBJ
GetPlayerSlotState
GetPlayerController
BlzGetLocalSpecialEffectX
BlzGetLocalSpecialEffectY
BlzGetLocalSpecialEffectZ
*/
////! runtextmacro LOG_NATIVE ("GetDestructableName", "destructable d", "WARN")
//! runtextmacro LOG_NATIVE ("GetSoundDuration", "sound soundHandle", "WARN")
//! runtextmacro LOG_NATIVE ("GetSoundFileDuration", "string musicFileName", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraBoundMinX", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraBoundMinY", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraBoundMaxX", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraBoundMaxY", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraField", "camerafield whichField", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraTargetPositionX", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraTargetPositionY", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraTargetPositionZ", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraTargetPositionLoc", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraEyePositionX", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraEyePositionY", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraEyePositionZ", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetCameraEyePositionLoc", "nothing", "WARN")
////! runtextmacro LOG_NATIVE ("GetObjectName", "integer objectId", "WARN")
//! runtextmacro LOG_NATIVE ("IsMultiboardMinimized", "multiboard lb", "WARN")
//! runtextmacro LOG_NATIVE ("GetLocalPlayer", "nothing", "WARN")
//! runtextmacro LOG_NATIVE ("GetLocationZ", "location whichLocation", "WARN")
//! runtextmacro LOG_NATIVE ("GetLocalizedString", "string source", "WARN")
//! runtextmacro LOG_NATIVE ("GetLocalizedHotkey", "string source", "WARN")
////! runtextmacro LOG_NATIVE ("GetUnitName", "unit whichUnit", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetLocalUnitZ", "unit whichUnit", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetUnitZ", "unit whichUnit", "WARN")
////! runtextmacro LOG_NATIVE ("GetItemName", "item whichItem", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetItemDescription", "item whichItem", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetItemTooltip", "item whichItem", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetItemExtendedTooltip", "item whichItem", "WARN")
//! runtextmacro LOG_NATIVE ("SmartCameraPanBJ", "player whichPlayer, location loc, real duration", "WARN")
//! runtextmacro LOG_NATIVE ("GetPlayerSlotState", "player whichPlayer", "WARN")
//! runtextmacro LOG_NATIVE ("GetPlayerController", "player whichPlayer", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetLocalSpecialEffectX", "effect whichEffect", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetLocalSpecialEffectY", "effect whichEffect", "WARN")
//! runtextmacro LOG_NATIVE ("BlzGetLocalSpecialEffectZ", "effect whichEffect", "WARN")
// ----------------------------------------------------------------------------
// onInit: system initializer
// ----------------------------------------------------------------------------
//private module M
// private static method onInit takes nothing returns nothing
// endmethod
//endmodule
//private struct S extends array
// implement M
//endstruct
endlibrary
// -------------------------------------------------------------------------------
// DECLARE_LOG_FUNCTIONS: automatically log all global triggers.
// -------------------------------------------------------------------------------
library TriggerDebugAutomation requires DebugLogger
//! textmacro TRIGGER_IS_READY takes GLOBALVARIABLENAME
call TriggerIsReady($GLOBALVARIABLENAME$, "$GLOBALVARIABLENAME$")
//! endtextmacro
//! textmacro EVENTID takes GLOBALVARIABLENAME
if (whichEvent == EVENT_$GLOBALVARIABLENAME$) then
return "$GLOBALVARIABLENAME$"
endif
//! endtextmacro
globals
private hashtable pData
private integer kIsRegistered = StringHashBJ("IsRegistered")
private integer kHasConditions = StringHashBJ("HasConditions")
private integer kHasActions = StringHashBJ("HasAction")
private integer kDisplayName = StringHashBJ("DisplayName")
private integer kCondition = StringHashBJ("Condition")
private integer kConditionValue = StringHashBJ("ConditionValue")
private integer iLastTriggerIndex = 0
private trigger array aRegisteredTriggers
endglobals
// -------------------------------------------------------------------------------
// getEventName: returns the name of an event.
// -------------------------------------------------------------------------------
private function getEventName takes eventid whichEvent returns string
if (whichEvent == EVENT_GAME_VICTORY) then
return "MAP_INIT"
endif
//! runtextmacro EVENTID("GAME_END_LEVEL")
//! runtextmacro EVENTID("GAME_VARIABLE_LIMIT")
//! runtextmacro EVENTID("GAME_STATE_LIMIT")
//! runtextmacro EVENTID("GAME_TIMER_EXPIRED")
//! runtextmacro EVENTID("GAME_ENTER_REGION")
//! runtextmacro EVENTID("GAME_LEAVE_REGION")
//! runtextmacro EVENTID("GAME_TRACKABLE_HIT")
//! runtextmacro EVENTID("GAME_TRACKABLE_TRACK")
//! runtextmacro EVENTID("GAME_SHOW_SKILL")
//! runtextmacro EVENTID("GAME_BUILD_SUBMENU")
//! runtextmacro EVENTID("PLAYER_STATE_LIMIT")
//! runtextmacro EVENTID("PLAYER_ALLIANCE_CHANGED")
//! runtextmacro EVENTID("PLAYER_DEFEAT")
//! runtextmacro EVENTID("PLAYER_VICTORY")
//! runtextmacro EVENTID("PLAYER_LEAVE")
//! runtextmacro EVENTID("PLAYER_CHAT")
//! runtextmacro EVENTID("PLAYER_END_CINEMATIC")
//! runtextmacro EVENTID("PLAYER_UNIT_ATTACKED")
//! runtextmacro EVENTID("PLAYER_UNIT_RESCUED")
//! runtextmacro EVENTID("PLAYER_UNIT_DEATH")
//! runtextmacro EVENTID("PLAYER_UNIT_DECAY")
//! runtextmacro EVENTID("PLAYER_UNIT_DETECTED")
//! runtextmacro EVENTID("PLAYER_UNIT_HIDDEN")
//! runtextmacro EVENTID("PLAYER_UNIT_SELECTED")
//! runtextmacro EVENTID("PLAYER_UNIT_DESELECTED")
//! runtextmacro EVENTID("PLAYER_UNIT_CONSTRUCT_START")
//! runtextmacro EVENTID("PLAYER_UNIT_CONSTRUCT_CANCEL")
//! runtextmacro EVENTID("PLAYER_UNIT_CONSTRUCT_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_UPGRADE_START")
//! runtextmacro EVENTID("PLAYER_UNIT_UPGRADE_CANCEL")
//! runtextmacro EVENTID("PLAYER_UNIT_UPGRADE_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_TRAIN_START")
//! runtextmacro EVENTID("PLAYER_UNIT_TRAIN_CANCEL")
//! runtextmacro EVENTID("PLAYER_UNIT_TRAIN_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_RESEARCH_START")
//! runtextmacro EVENTID("PLAYER_UNIT_RESEARCH_CANCEL")
//! runtextmacro EVENTID("PLAYER_UNIT_RESEARCH_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_ISSUED_ORDER")
//! runtextmacro EVENTID("PLAYER_UNIT_ISSUED_POINT_ORDER")
//! runtextmacro EVENTID("PLAYER_UNIT_ISSUED_TARGET_ORDER")
//! runtextmacro EVENTID("PLAYER_UNIT_ISSUED_UNIT_ORDER")
//! runtextmacro EVENTID("PLAYER_HERO_LEVEL")
//! runtextmacro EVENTID("PLAYER_HERO_SKILL")
//! runtextmacro EVENTID("PLAYER_HERO_REVIVABLE")
//! runtextmacro EVENTID("PLAYER_HERO_REVIVE_START")
//! runtextmacro EVENTID("PLAYER_HERO_REVIVE_CANCEL")
//! runtextmacro EVENTID("PLAYER_HERO_REVIVE_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_SUMMON")
//! runtextmacro EVENTID("PLAYER_UNIT_DROP_ITEM")
//! runtextmacro EVENTID("PLAYER_UNIT_PICKUP_ITEM")
//! runtextmacro EVENTID("PLAYER_UNIT_USE_ITEM")
//! runtextmacro EVENTID("PLAYER_UNIT_LOADED")
//! runtextmacro EVENTID("UNIT_DAMAGED")
//! runtextmacro EVENTID("UNIT_DEATH")
//! runtextmacro EVENTID("UNIT_DECAY")
//! runtextmacro EVENTID("UNIT_DETECTED")
//! runtextmacro EVENTID("UNIT_HIDDEN")
//! runtextmacro EVENTID("UNIT_SELECTED")
//! runtextmacro EVENTID("UNIT_DESELECTED")
//! runtextmacro EVENTID("UNIT_STATE_LIMIT")
//! runtextmacro EVENTID("UNIT_ACQUIRED_TARGET")
//! runtextmacro EVENTID("UNIT_TARGET_IN_RANGE")
//! runtextmacro EVENTID("UNIT_ATTACKED")
//! runtextmacro EVENTID("UNIT_RESCUED")
//! runtextmacro EVENTID("UNIT_CONSTRUCT_CANCEL")
//! runtextmacro EVENTID("UNIT_CONSTRUCT_FINISH")
//! runtextmacro EVENTID("UNIT_UPGRADE_START")
//! runtextmacro EVENTID("UNIT_UPGRADE_CANCEL")
//! runtextmacro EVENTID("UNIT_UPGRADE_FINISH")
//! runtextmacro EVENTID("UNIT_TRAIN_START")
//! runtextmacro EVENTID("UNIT_TRAIN_CANCEL")
//! runtextmacro EVENTID("UNIT_TRAIN_FINISH")
//! runtextmacro EVENTID("UNIT_RESEARCH_START")
//! runtextmacro EVENTID("UNIT_RESEARCH_CANCEL")
//! runtextmacro EVENTID("UNIT_RESEARCH_FINISH")
//! runtextmacro EVENTID("UNIT_ISSUED_ORDER")
//! runtextmacro EVENTID("UNIT_ISSUED_POINT_ORDER")
//! runtextmacro EVENTID("UNIT_ISSUED_TARGET_ORDER")
//! runtextmacro EVENTID("UNIT_HERO_LEVEL")
//! runtextmacro EVENTID("UNIT_HERO_SKILL")
//! runtextmacro EVENTID("UNIT_HERO_REVIVABLE")
//! runtextmacro EVENTID("UNIT_HERO_REVIVE_START")
//! runtextmacro EVENTID("UNIT_HERO_REVIVE_CANCEL")
//! runtextmacro EVENTID("UNIT_HERO_REVIVE_FINISH")
//! runtextmacro EVENTID("UNIT_SUMMON")
//! runtextmacro EVENTID("UNIT_DROP_ITEM")
//! runtextmacro EVENTID("UNIT_PICKUP_ITEM")
//! runtextmacro EVENTID("UNIT_USE_ITEM")
//! runtextmacro EVENTID("UNIT_LOADED")
//! runtextmacro EVENTID("WIDGET_DEATH")
//! runtextmacro EVENTID("DIALOG_BUTTON_CLICK")
//! runtextmacro EVENTID("DIALOG_CLICK")
//! runtextmacro EVENTID("GAME_LOADED")
//! runtextmacro EVENTID("GAME_TOURNAMENT_FINISH_SOON")
//! runtextmacro EVENTID("GAME_TOURNAMENT_FINISH_NOW")
//! runtextmacro EVENTID("GAME_SAVE")
//! runtextmacro EVENTID("PLAYER_ARROW_LEFT_DOWN")
//! runtextmacro EVENTID("PLAYER_ARROW_LEFT_UP")
//! runtextmacro EVENTID("PLAYER_ARROW_RIGHT_DOWN")
//! runtextmacro EVENTID("PLAYER_ARROW_RIGHT_UP")
//! runtextmacro EVENTID("PLAYER_ARROW_DOWN_DOWN")
//! runtextmacro EVENTID("PLAYER_ARROW_DOWN_UP")
//! runtextmacro EVENTID("PLAYER_ARROW_UP_DOWN")
//! runtextmacro EVENTID("PLAYER_ARROW_UP_UP")
//! runtextmacro EVENTID("PLAYER_UNIT_SELL")
//! runtextmacro EVENTID("PLAYER_UNIT_CHANGE_OWNER")
//! runtextmacro EVENTID("PLAYER_UNIT_SELL_ITEM")
//! runtextmacro EVENTID("PLAYER_UNIT_SPELL_CHANNEL")
//! runtextmacro EVENTID("PLAYER_UNIT_SPELL_CAST")
//! runtextmacro EVENTID("PLAYER_UNIT_SPELL_EFFECT")
//! runtextmacro EVENTID("PLAYER_UNIT_SPELL_FINISH")
//! runtextmacro EVENTID("PLAYER_UNIT_SPELL_ENDCAST")
//! runtextmacro EVENTID("PLAYER_UNIT_PAWN_ITEM")
//! runtextmacro EVENTID("UNIT_SELL")
//! runtextmacro EVENTID("UNIT_CHANGE_OWNER")
//! runtextmacro EVENTID("UNIT_SELL_ITEM")
//! runtextmacro EVENTID("UNIT_SPELL_CHANNEL")
//! runtextmacro EVENTID("UNIT_SPELL_CAST")
//! runtextmacro EVENTID("UNIT_SPELL_EFFECT")
//! runtextmacro EVENTID("UNIT_SPELL_FINISH")
//! runtextmacro EVENTID("UNIT_SPELL_ENDCAST")
//! runtextmacro EVENTID("UNIT_PAWN_ITEM")
return null
endfunction
// -------------------------------------------------------------------------------
// getTriggerDisplayName: retrieves the trigger display name, or a default string if if does not exist.
// -------------------------------------------------------------------------------
private function getTriggerDisplayName takes trigger whichTrigger returns string
local integer iTriggerHandleId = GetHandleId(whichTrigger)
local string sTriggerName
set sTriggerName = LoadStr(pData, kDisplayName, iTriggerHandleId)
if (sTriggerName == null) then
set sTriggerName = "Unknown" + I2S(iTriggerHandleId)
endif
return sTriggerName
endfunction
// -------------------------------------------------------------------------------
// dumpTriggerParams: formats a string with the trigger context.
// -------------------------------------------------------------------------------
private function dumpTriggerContext takes nothing returns string
local trigger pTrigger = GetTriggeringTrigger()
local integer iEvalCount = GetTriggerEvalCount(pTrigger)
local integer iExecCount = GetTriggerExecCount(pTrigger)
local string sTriggerName = getTriggerDisplayName(pTrigger)
return "[" + sTriggerName + "(" + I2S(iExecCount) + "/" + I2S(iEvalCount) + ")]"
endfunction
// -------------------------------------------------------------------------------
// dumpTriggerParams: format a string with some of the trigger params.
// -------------------------------------------------------------------------------
private function dumpTriggerParams takes nothing returns string
local string sParams = ""
local eventid pEvent = GetTriggerEventId()
local unit pUnit = GetTriggerUnit()
local player pPlayer = GetTriggerPlayer()
local destructable pDestructable = GetTriggerDestructable()
local string sChatTxt = GetEventPlayerChatString()
local integer iIssuedOrder = GetIssuedOrderIdBJ()
local integer iAbility = GetSpellAbilityId()
set sParams = sParams + " |event=" + getEventName(pEvent)
if (null != pUnit) then
set sParams = sParams + "|unit=" + GetUnitName(pUnit)
if (null == pPlayer) then
set pPlayer = GetOwningPlayer(pUnit)
endif
endif
if (null != pPlayer) then
set sParams = sParams + "|player=" + GetPlayerName(pPlayer)
endif
if (null != pDestructable) then
set sParams = sParams + "|destr=" + GetDestructableName(pDestructable)
endif
if (null != sChatTxt) then
set sParams = sParams + "|chat=" + sChatTxt
endif
if (iIssuedOrder > 0) then
set sParams = sParams + "|order=" + OrderId2StringBJ(iIssuedOrder)
endif
if (iAbility > 0) then
set sParams = sParams + "|ability=" + GetAbilityName(iAbility)
endif
return sParams
endfunction
// -------------------------------------------------------------------------------
// beforeCondition: a fonction registered as first true-condition for logging.
// -------------------------------------------------------------------------------
private function beforeCondition takes nothing returns boolean
local string sDebugText = dumpTriggerContext() + " Checking conditions" + dumpTriggerParams()
call DebugLog(LVL_DEBUG, sDebugText)
//call DisplayTextToForce( GetPlayersAll(), sDebugText )
return true
endfunction
// -------------------------------------------------------------------------------
// ifConditionsTrue: a fonction registered as condition for logging when conditions are validated.
// -------------------------------------------------------------------------------
private function ifConditionsTrue takes nothing returns boolean
local string sDebugText = dumpTriggerContext() + " Conditions TRUE"
call DebugLog(LVL_DEBUG, sDebugText)
//call DisplayTextToForce( GetPlayersAll(), sDebugText )
return true
endfunction
// -------------------------------------------------------------------------------
// ifConditionsFalse: a fonction registered as condition for logging when conditions are invalidated.
// -------------------------------------------------------------------------------
private function ifConditionsFalse takes nothing returns boolean
local string sDebugText = dumpTriggerContext() + " Conditions FALSE"
call DebugLog(LVL_DEBUG, sDebugText)
//call DisplayTextToForce( GetPlayersAll(), sDebugText )
return false
endfunction
// -------------------------------------------------------------------------------
// beforeAction: a fonction registered as first action for logging.
// -------------------------------------------------------------------------------
private function beforeAction takes nothing returns nothing
local string sDebugText = dumpTriggerContext() + " Starts" + dumpTriggerParams()
call DebugLog(LVL_DEBUG, sDebugText)
//call DisplayTextToForce( GetPlayersAll(), sDebugText )
endfunction
// -------------------------------------------------------------------------------
// afterAction: a fonction registered as last action for logging.
// -------------------------------------------------------------------------------
private function afterAction takes nothing returns nothing
local string sDebugText = dumpTriggerContext() + " Done"
call DebugLog(LVL_DEBUG, sDebugText)
//call DisplayTextToForce( GetPlayersAll(), sDebugText )
endfunction
// -------------------------------------------------------------------------------
// saveTriggerDisplayName: declare a display name for trigger logs.
// -------------------------------------------------------------------------------
private function saveTriggerDisplayName takes trigger whichTrigger, string displayName returns nothing
local integer iTriggerHandleId = GetHandleId(whichTrigger)
set aRegisteredTriggers[iLastTriggerIndex] = whichTrigger
call SaveStr(pData, kDisplayName, iTriggerHandleId, displayName)
endfunction
// -------------------------------------------------------------------------------
// onTriggerAddCondition: a hook executed right before TriggerAddCondition() call, allowing to add a first true-condition for logging.
// -------------------------------------------------------------------------------
private function onTriggerAddCondition takes trigger whichTrigger, boolexpr condition returns nothing
local integer iTriggerHandleId = GetHandleId(whichTrigger)
local boolean bHasConditions = false
set bHasConditions = LoadBoolean(pData, kHasConditions, iTriggerHandleId)
if (not bHasConditions) then
// It is the first one
call SaveBoolean(pData, kHasConditions, iTriggerHandleId, true)
call SaveBooleanExprHandle(pData, kCondition, iTriggerHandleId, condition)
endif
endfunction
hook TriggerAddCondition onTriggerAddCondition
// -------------------------------------------------------------------------------
// onTriggerAddAction: a hook executed right before TriggerAddAction() call, allowing to add a first action for logging.
// -------------------------------------------------------------------------------
private function onTriggerAddAction takes trigger whichTrigger, code actionFunc returns nothing
local integer iTriggerHandleId = GetHandleId(whichTrigger)
local boolean bHasActions = false
set bHasActions = LoadBoolean(pData, kHasActions, iTriggerHandleId)
if (not bHasActions) then
// It is the first one
call SaveBoolean(pData, kHasActions, iTriggerHandleId, true)
call TriggerAddAction(whichTrigger, function beforeAction)
endif
endfunction
hook TriggerAddAction onTriggerAddAction
//private function TriggerDebugAutomationOnTime0
//endfunction
// -------------------------------------------------------------------------------
// TriggerIsReady: function to call after the trigger is fully created (actions, conditions).
// -------------------------------------------------------------------------------
public function TriggerIsReady takes trigger whichTrigger, string displayName returns nothing
local integer iTriggerHandleId = GetHandleId(whichTrigger)
local boolexpr pCondition = LoadBooleanExprHandle(pData, kCondition, iTriggerHandleId)
local boolexpr pWrappedCondition
local boolean bTriggerHasConditions
local boolean bTriggerHasActions
if (whichTrigger == null) then
call DebugLog(LVL_DEBUG, displayName + " is not a trigger, is disabled, or is not ready yet")
return
endif
// Save the display name
call saveTriggerDisplayName(whichTrigger, displayName)
set bTriggerHasConditions = false
set bTriggerHasConditions = LoadBoolean(pData, kHasConditions, iTriggerHandleId)
set bTriggerHasActions = false
set bTriggerHasActions = LoadBoolean(pData, kHasActions, iTriggerHandleId)
if (bTriggerHasConditions and bTriggerHasActions) then
// We have logs for beforeCondition, ifConditionsFalse, beforeAction, afterAction
call TriggerClearConditions(whichTrigger)
set pWrappedCondition = Or(And(function beforeCondition, pCondition), function ifConditionsFalse)
call TriggerAddCondition(whichTrigger, pWrappedCondition)
call TriggerAddAction(whichTrigger, function afterAction)
elseif (bTriggerHasConditions) then
// We have logs for beforeCondition, ifConditionsTrue, ifConditionsFalse
call TriggerClearConditions(whichTrigger)
set pWrappedCondition = Or(And(And(function beforeCondition, pCondition), function ifConditionsTrue), function ifConditionsFalse)
call TriggerAddCondition(whichTrigger, pWrappedCondition)
elseif (bTriggerHasActions) then
// We have logs for beforeAction, afterAction
call TriggerAddAction(whichTrigger, function afterAction)
endif
endfunction
// -------------------------------------------------------------------------------
// TriggerDebugAutomationOnMapInit: code executed on map init (the sooner after all GUI triggers are fully created).
// -------------------------------------------------------------------------------
function TriggerDebugAutomationOnMapInit takes nothing returns nothing
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Debug_Logger")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Debug_Log_During_Replay")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Primitive_Debug_Automation")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Trigger_Debug_Automation")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Trigger_Debug_Automation_Initializer")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Trigger_Debug_Automation_Time0")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_ForTestingPurposeOnly")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Dota_Initialization")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Framework")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Avalanche")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_CraggyExterior")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_GrabTree")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Grow")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Toss")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_GameStatus")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_MathsLib")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Logarithm")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_ArmorLib")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GameClock_VariableCreator")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_TimeUtils")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Item_Cleanup")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ItemTimedLife")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Unit_Event_Config")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Unit_Event")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Damage_Engine_Config")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Damage_Engine")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Open_List")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Events_for_Cancel_List_ESC")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Cancel_List_ESC")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Cancel_List_Item")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_EasyItemStacknSplitGUI_config")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_EasyItemStacknSplitGUI")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MinionsUpgrade")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LifeSteal_Configuration")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LifeSteal_Execute")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DamageReturn_Configuration")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DamageReturn_Execute")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DamageReturn_ApplyArmor")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_InvisibleBuffCorrector")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_BossRegister")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BossUnregister")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Functions")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BossRearFlankAttack")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_DefendAgainstDamage")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Initialization")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Beast_Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_KnockbackUnits")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Import_Instructions")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BAmr_Config")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BAmr_Cast")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BAmr_Block")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BAmr_Periodic")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_BoneArmorAOE_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BoneArmorAOE_GUI")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Scream")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CleaveFix")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_TCAFix_Config")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_TCAFix_UnitIndexed")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_TCAFix_UnitLearnsSkill")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_TCAFix_UnitDeindexed")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EtherealFix_OnDamage")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HealFix_Unblock")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GrabTreeFix_Unblock")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_PauseAllUnits")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_UnpauseAllUnits")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Init_sequence")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Abilities")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Alliances")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Buildings")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DarkUnitVars")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Flags")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Hashtables")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Items")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_NeutralUnitVars")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Points")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Quests")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Regions")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Times")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DarkUnits")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Music")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_NeutralUnits")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Invulnerables")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Shops")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Check")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_StartGame")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OptionsGame")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OptionsDifficulty")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OptionsHeroes")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OptionsTimeOut")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ModeNormal")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ModeRandom")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ModeExtreme")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ModeEasy")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ReviveTrees")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CastleUnderAttack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_StopAttackCastle")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinHelp")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinAttacked")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BuyLevels")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BuyTomes")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CloseWay")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ExtremeLevel")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Fog")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Commands")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Host")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Info")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Kick")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OpenWay")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Random")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Rebuy")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Repick")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RepickTip")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ShortBuffAfterReincarnation")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_FullRestoration")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SuperItems")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AutoPotionOfGreaterHealing")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LeaderBoard")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LeaderBoardAdd")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect1a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect1b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect2a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect2b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect3a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect3b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect4a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect4b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect5a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect5b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect6a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect6b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect7a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect7b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect8a")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSelect8b")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSetup")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroDead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ControlSharing")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EasyPowerUp")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroSetupDual")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroDeadDual")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroChange")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroChangeShared")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroStats")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroLevel")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroMoveItem")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroUseItem")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroAcquireItem")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroLoseItem")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_DualHeroCooldown")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_BoostLevel")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EnableHeroAbilities")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EnableItemAbilities")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Level20Abilities")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Armor")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ArtifactCollector")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttributeBonusPerLevel")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AuraOfBlight")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Bomb")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CooldownsReduction")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CriticalStrikeAura")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_CursedClaws")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DamageDealtMalus")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DamageTakenMalus")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DeathCoil")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DebilitationAura")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Doom")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Earthquake")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EarthquakeStop")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Ensnare")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_FanOfKnives_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_FanOfKnives")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_FrostParalysisAura")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Hex_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Hex")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HolyLight")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Immolation")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ImmolationGhost")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_InnerFire")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_KnightsChallenge")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LifeRegenerationAura")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LightFrenzy")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LightningAttackOnOff")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MagicDefenseOnOff")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MorphingCopyStats")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_OwlScout")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_PermanentLightning")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_Polymorph_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Polymorph")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RefreshCooldownChance")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RuneClockCreate")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RuneClockDestroy")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RunicWeaponCreate")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_ShadowStrike_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ShadowStrike")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_ShockWave_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ShockWave")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpiritPig")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpiritualPresence")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_StormBolt_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_StormBolt")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_ThunderClap_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ThunderClap")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_TrueTank")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WardsMastery")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_WarStomp_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WarStomp")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Whirlwind")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttackStart")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Kills100")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Kills500")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Kills1000")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Kills2000")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttackCome")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttackCheck")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttackTower")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_AttackNecropolis")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_ExtremePowerUp")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_DragonAttack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_HeroAttack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_LightningAttack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SilentAssassin")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Rune")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GameLevel1")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WarnBeforeGameLevel2")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GameLevel2")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GameLevel3")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_GameLevel4")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveTimer")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveAttack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveKills20")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveKills40")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveKills60")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_WaveKills80")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_FinalWaveCheckIfReady")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_FinalWaveStart")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival1CheckIfReady")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival1Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival1Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival2Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival2Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival3Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Survival3Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss1Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss1Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss2Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss2Leave")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss3Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss4Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss5Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss6Come")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss6Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss6Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss7Come")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss7Colour")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss7Power")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Boss7Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special4Agree")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special4Won")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special4Failed")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special5Agree")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special5EnableAbilities")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special5Won")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special5Failed")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Timer")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Stop")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Leave")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8AntiHack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special8Move")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinClap_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinClap")
////! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinBolt_JASS")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_MuradinBolt")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Timer")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Attack")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Corpse")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Stop")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special1Dead")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special2Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special2Stop")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special2Won")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special2TimeOut")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special2Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3Start")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3Stop")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3Count")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3Won")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3TimeOut")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special3Teleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special6Agree")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Special7Agree")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXDialog")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXStart")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXDisagree")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXRevive")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXTeleport")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXPause")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXResume")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_SpecialXCancel")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Victory")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_YouLose")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EndGame")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_Disconnect")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RemovePlayer")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EndPitch")
endfunction
// -------------------------------------------------------------------------------
// TriggerDebugAutomationOnTime0: code executed after 0seconds elapsed (the sooner after all library init are fully done).
// -------------------------------------------------------------------------------
function TriggerDebugAutomationOnTime0 takes nothing returns nothing
//! runtextmacro TRIGGER_IS_READY ("gg_trg_EasyItemStacknSplit")
//! runtextmacro TRIGGER_IS_READY ("gg_trg_RealmOfSoul")
//! runtextmacro TRIGGER_IS_READY ("udg_MURefreshTrigger")
//! runtextmacro TRIGGER_IS_READY ("udg_TCAFixUnitAttackedTrigger")
//! runtextmacro TRIGGER_IS_READY ("udg_TCAFixResumeHoldPosTrigger")
endfunction
// ----------------------------------------------------------------------------
// onInit: system initializer
// ----------------------------------------------------------------------------
private module M
private static method onInit takes nothing returns nothing
//local trigger pTime0Trigger = CreateTrigger()
set pData = InitHashtable()
//call TriggerRegisterTimerEventSingle( pTime0Trigger, 0.00 )
//call TriggerAddAction(pTime0Trigger , function TriggerDebugAutomationOnTime0)
endmethod
endmodule
private struct S extends array
implement M
endstruct
endlibrary
// -------------------------------------------------------------------------------
// Conditions - begin ------------------------------------------------------------
function AlwaysTrueCondition takes nothing returns boolean
return true
endfunction
function IsUnitUnknownOrDead takes unit loc_unit01 returns boolean
return GetUnitTypeId(loc_unit01)<1 or IsUnitType(loc_unit01,UNIT_TYPE_DEAD)==true
endfunction
function IsCourrierType takes unit loc_unit01 returns boolean
//return GetUnitTypeId(loc_unit01)=='n00I' or GetUnitTypeId(loc_unit01)=='n022' or GetUnitTypeId(loc_unit01)=='n021' or GetUnitTypeId(loc_unit01)=='n023' or GetUnitTypeId(loc_unit01)=='n024' or GetUnitTypeId(loc_unit01)=='n025' or GetUnitTypeId(loc_unit01)=='e01H' or GetUnitTypeId(loc_unit01)=='e01Z' or GetUnitTypeId(loc_unit01)=='n00M' or GetUnitTypeId(loc_unit01)=='n0HV'
return false
endfunction
function IsInvalidTargetType takes unit loc_unit01 returns boolean
//local integer loc_integer01=GetUnitTypeId(loc_unit01)
//return loc_integer01=='n004' or loc_integer01=='n01G' or loc_integer01=='n01C' or loc_integer01=='n018' or loc_integer01=='e00K' or loc_integer01=='e00I' or loc_integer01=='e00L' or loc_integer01=='e01J'
return false
endfunction
// TODO : update when trees are added
function IsTreeDestructableType takes destructable loc_destructable01 returns boolean
//return GetDestructableTypeId(loc_destructable01)=='NTtc' or GetDestructableTypeId(loc_destructable01)=='NTtw' or GetDestructableTypeId(loc_destructable01)=='ATtr' or GetDestructableTypeId(loc_destructable01)=='B002' or GetDestructableTypeId(loc_destructable01)=='B003' or GetDestructableTypeId(loc_destructable01)=='B005'
return false
endfunction
function TargetFilterNoAncients takes nothing returns boolean
return IsUnitEnemy(udg_TempTossProjectedUnit,GetOwningPlayer(GetFilterUnit()))and(GetUnitAbilityLevel(GetFilterUnit(),'A069')==0 and IsUnitUnknownOrDead(GetFilterUnit())==false)and(IsUnitType(GetFilterUnit(),UNIT_TYPE_ANCIENT)==false or IsInvalidTargetType(GetFilterUnit()))
endfunction
function IsUnitFlying takes unit loc_unit01 returns boolean
//return GetUnitTypeId(loc_unit01)=='H00F' or GetUnitTypeId(loc_unit01)=='H00E' or GetUnitTypeId(loc_unit01)=='H00G' or GetUnitTypeId(loc_unit01)=='O017'
return false
endfunction
// Conditions - end --------------------------------------------------------------
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
// Maths - begin -----------------------------------------------------------------
function MathsAtan2 takes real loc_real01,real loc_real02,real loc_real03,real loc_real04 returns real
return bj_RADTODEG*Atan2(loc_real04-loc_real02,loc_real03-loc_real01)
endfunction
// Coord X1, Coord Y1, Coord X2, Coord Y2
function DistanceBetweenPointsByCoord takes real loc_real01,real loc_real02,real loc_real03,real loc_real04 returns real
return SquareRoot(((loc_real01-loc_real03)*(loc_real01-loc_real03))+((loc_real02-loc_real04)*(loc_real02-loc_real04)))
endfunction
function DistanceBetweenUnits takes unit loc_unit01,unit loc_unit02 returns real
local real loc_real01=GetUnitX(loc_unit01)
local real loc_real02=GetUnitY(loc_unit01)
local real loc_real03=GetUnitX(loc_unit02)
local real loc_real04=GetUnitY(loc_unit02)
if loc_unit01==null or loc_unit02==null then
return I2R(2147483648)
else
return SquareRoot((loc_real01-loc_real03)*(loc_real01-loc_real03)+(loc_real02-loc_real04)*(loc_real02-loc_real04))
endif
return 1.0
endfunction
// Maths - end -------------------------------------------------------------------
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
// Actions - begin ---------------------------------------------------------------
function TriggerRegisterAllPlayersUnitEvent takes trigger loc_trigger01,playerunitevent loc_playerunitevent01 returns nothing
local integer loc_integer01=0
loop
call TriggerRegisterPlayerUnitEvent(loc_trigger01,Player(loc_integer01),loc_playerunitevent01,Condition(function AlwaysTrueCondition))
set loc_integer01=loc_integer01+1
exitwhen loc_integer01==12
endloop
endfunction
function DamageUnit takes unit loc_unit01,unit loc_unit02,integer loc_integer01,real loc_real01 returns nothing
if loc_integer01==0 then
return
endif
if loc_integer01==1 then
call UnitDamageTarget(loc_unit01,loc_unit02,loc_real01,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE,WEAPON_TYPE_WHOKNOWS)
elseif loc_integer01==2 then
call UnitDamageTarget(loc_unit01,loc_unit02,loc_real01,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif loc_integer01==3 then
call UnitDamageTarget(loc_unit01,loc_unit02,loc_real01,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_MAGIC,WEAPON_TYPE_WHOKNOWS)
elseif loc_integer01==4 then
call UnitDamageTarget(loc_unit01,loc_unit02,loc_real01,true,true,ATTACK_TYPE_PIERCE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
endfunction
function DisplayError takes player loc_player01,string loc_string01 returns nothing
local sound loc_sound01=CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
if(GetLocalPlayer()==loc_player01)then
call StartSound(loc_sound01)
endif
if(loc_string01!="")and(loc_string01!=null)then
call ClearTextMessages()
call DisplayTimedTextToPlayer(loc_player01,0.50,-1.00,2.00,"|cffffcc00"+loc_string01+"|r")
endif
call KillSoundWhenDone(loc_sound01)
endfunction
function DestroyTreeDestructable takes nothing returns nothing
if IsTreeDestructableType(GetEnumDestructable())then
call KillDestructable(GetEnumDestructable())
endif
endfunction
// Coord X, Coord Y, HalfRangeX, HalfRangeY
function DestroyTreeDestructablesInRegion takes real loc_real01,real loc_real02,real loc_real03 returns nothing
local rect loc_rect01=Rect(loc_real01-loc_real03,loc_real02-loc_real03,loc_real01+loc_real03,loc_real02+loc_real03)
call EnumDestructablesInRectAll(loc_rect01,function DestroyTreeDestructable)
call RemoveRect(loc_rect01)
set loc_rect01=null
endfunction
function StopUnitSilent takes unit loc_unit01 returns nothing
call PauseUnit(loc_unit01,true)
call IssueImmediateOrder(loc_unit01,"stop")
call PauseUnit(loc_unit01,false)
endfunction
function UnitAddPermanentAbility takes unit loc_unit01,integer loc_integer01 returns nothing
call UnitAddAbility(loc_unit01,loc_integer01)
call UnitMakeAbilityPermanent(loc_unit01,true,loc_integer01)
endfunction
function SetAllPlayersAbilityAvailable takes integer loc_integer01 returns nothing
local integer loc_integer02=0
loop
exitwhen loc_integer02>8
call SetPlayerAbilityAvailable(Player(loc_integer02),loc_integer01,false)
set loc_integer02=loc_integer02+1
endloop
endfunction
function SaveUnitInCacheFinish takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
call DebugLog(LVL_DEBUG, "SaveUnitInCacheFinish")
call SaveInteger(udg_DotaHashtable,(GetHandleId(((LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(14)))))),(((LoadInteger(udg_DotaHashtable,(loc_integer01),(33))))),(2))
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DisableTrigger(loc_trigger01)
set loc_trigger01=null
return false
endfunction
function SaveUnitInCacheWithDelay takes unit loc_unit01,integer loc_integer01,real loc_real01 returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerAddCondition(loc_trigger01,Condition(function SaveUnitInCacheFinish))
call TriggerRegisterTimerEvent(loc_trigger01,loc_real01,false)
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "SaveUnitInCacheWithDelay_" + I2S(loc_integer01))
call SaveInteger(udg_DotaHashtable,(GetHandleId((loc_unit01))),((loc_integer01)),(1))
call SaveUnitHandle(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(14),(loc_unit01))
call SaveInteger(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(33),(loc_integer01))
set loc_trigger01=null
endfunction
// Actions - end -----------------------------------------------------------------
// -------------------------------------------------------------------------------
function AvalancheAdditionalDamageTossedUnit takes nothing returns boolean
if((LoadInteger(udg_DotaHashtable,(GetHandleId((GetFilterUnit()))),((4268))))==1)and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(udg_TCAAvalancheCaster))==true then
call DamageUnit(udg_TCAAvalancheCaster,GetFilterUnit(),1,udg_TempAvalancheDamages)
endif
return false
endfunction
function AvalancheAdditionalDamageTossedUnitPeriodic takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(14)))
local real loc_real01=(LoadReal(udg_DotaHashtable,(loc_integer01),(6)))
local real loc_real02=(LoadReal(udg_DotaHashtable,(loc_integer01),(7)))
local unit loc_unit02=CreateUnit(GetOwningPlayer(loc_unit01),'n00E',loc_real01,loc_real02,0)
local integer loc_integer02=GetUnitAbilityLevel(loc_unit01,'A06E')
local group loc_group01=CreateGroup()
call DebugLog(LVL_DEBUG, "AvalancheAdditionalDamageTossedUnitPeriodic")
call UnitApplyTimedLifeBJ(5.00, 'BTLF', loc_unit02)
call UnitAddAbility(loc_unit02,'A06F')
set udg_TCAAvalancheCaster=loc_unit01
if loc_integer02==1 then
set udg_TempAvalancheDamages=75
elseif loc_integer02==2 then
set udg_TempAvalancheDamages=100
elseif loc_integer02==3 then
set udg_TempAvalancheDamages=210
elseif loc_integer02==4 then
set udg_TempAvalancheDamages=230
endif
call SetUnitAbilityLevel(loc_unit02,'A06F',loc_integer02)
call GroupEnumUnitsInRange(loc_group01,loc_real01,loc_real02,299,Condition(function AvalancheAdditionalDamageTossedUnit))
call DestroyGroup(loc_group01)
if GetTriggerEvalCount(loc_trigger01)>6 then
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DisableTrigger(loc_trigger01)
endif
set loc_trigger01=null
set loc_unit01=null
set loc_unit02=null
set loc_group01=null
return false
endfunction
function AvalancheEffect takes nothing returns nothing
local unit loc_unit01=GetTriggerUnit()
local trigger loc_trigger01=CreateTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local location loc_location01=GetSpellTargetLoc()
local unit loc_unit02=CreateUnit(GetOwningPlayer(loc_unit01),'n00E',GetUnitX(loc_unit01),GetUnitY(loc_unit01),0)
local integer loc_integer02=GetUnitAbilityLevel(loc_unit01,'A06E')
call DebugLog(LVL_DEBUG, "AvalancheEffect")
call UnitApplyTimedLifeBJ(5.00, 'BTLF', loc_unit02)
call UnitAddAbility(loc_unit02,'A06H')
call SetUnitAbilityLevel(loc_unit02,'A06H',loc_integer02)
call IssuePointOrder(loc_unit02,"clusterrockets",GetLocationX(loc_location01),GetLocationY(loc_location01))
call TriggerRegisterTimerEvent(loc_trigger01,0.25,true)
call TriggerAddCondition(loc_trigger01,Condition(function AvalancheAdditionalDamageTossedUnitPeriodic))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "AvalancheEffect")
call SaveUnitHandle(udg_DotaHashtable,(loc_integer01),(14),(loc_unit01))
call SaveReal(udg_DotaHashtable,(loc_integer01),(6),((GetLocationX(loc_location01))*1.0))
call SaveReal(udg_DotaHashtable,(loc_integer01),(7),((GetLocationY(loc_location01))*1.0))
call TriggerEvaluate(loc_trigger01)
call RemoveLocation(loc_location01)
set loc_unit01=null
set loc_location01=null
set loc_trigger01=null
set loc_unit02=null
endfunction
function AvalancheSkill takes nothing returns boolean
if GetSpellAbilityId()=='A06E' then
call DebugLog(LVL_DEBUG, "SpellEffect - Avalanche")
call AvalancheEffect()
endif
return false
endfunction
function AvalancheEffectRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(loc_trigger01,Condition(function AvalancheSkill))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "AvalancheEffectRegister")
set loc_trigger01=null
endfunction
function CraggyExteriorEffect takes nothing returns boolean
local unit loc_unit01=GetTriggerUnit()
local unit loc_unit02=GetAttacker()
local integer loc_integer01=GetUnitAbilityLevel(loc_unit01,'A066')
local unit loc_unit03
call DebugLog(LVL_DEBUG, "CraggyExteriorEffect")
if GetRandomInt(1,100)<=loc_integer01*6 and DistanceBetweenUnits(loc_unit01,loc_unit02)<325 then
set loc_unit03=CreateUnit(GetOwningPlayer(loc_unit01),'n00E',GetUnitX(loc_unit02),GetUnitY(loc_unit02),0)
call UnitApplyTimedLifeBJ(1.50, 'BTLF', loc_unit03)
call UnitAddAbility(loc_unit03,'A067')
call SetUnitAbilityLevel(loc_unit03,'A067',loc_integer01)
call IssueTargetOrder(loc_unit03,"thunderbolt",loc_unit02)
set loc_unit03=null
endif
set loc_unit01=null
set loc_unit02=null
return false
endfunction
function CraggyExteriorEffectRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
local unit loc_unit01=GetTriggerUnit()
call TriggerRegisterUnitEvent(loc_trigger01,loc_unit01,EVENT_UNIT_ATTACKED)
call TriggerAddCondition(loc_trigger01,Condition(function CraggyExteriorEffect))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "CraggyExteriorEffectRegister")
set loc_trigger01=null
set loc_unit01=null
endfunction
function CraggyExteriorSkill takes nothing returns boolean
if GetLearnedSkill()=='A066' and GetUnitAbilityLevel(GetTriggerUnit(),'A066')==1 and IsUnitIllusion(GetTriggerUnit())==false then
call DebugLog(LVL_DEBUG, "CraggyExteriorSkill")
call CraggyExteriorEffectRegister()
endif
return false
endfunction
function CraggyExteriorSkillRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(loc_trigger01,Condition(function CraggyExteriorSkill))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "CraggyExteriorSkillRegister")
set loc_trigger01=null
endfunction
function SetAllPlayerGrabTreeAvailable takes nothing returns nothing
local unit loc_unit01=GetTriggerUnit()
call SetAllPlayersAbilityAvailable('A2KK')
endfunction
function GrabTreeCountSuccessfulAttacks takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local integer loc_integer02=(LoadInteger(udg_DotaHashtable,(loc_integer01),(375)))
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(2)))
local integer loc_integer03
if GetTriggerEventId()==EVENT_UNIT_DAMAGED then
if GetEventDamageSource()==loc_unit01 and GetEventDamage()>20 then
set loc_integer03=(LoadInteger(udg_DotaHashtable,(GetHandleId(loc_unit01)),(674))) // Get number of attacks already made
if((LoadInteger(udg_DotaHashtable,(GetHandleId((loc_unit01))),((4297))))==1)==false then
call SaveUnitInCacheWithDelay(loc_unit01,4297,0.1)
call SaveInteger(udg_DotaHashtable,(GetHandleId(loc_unit01)),(674),(loc_integer03+1)) // Save number or attacks made
endif
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DestroyTrigger(loc_trigger01)
endif
else
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DestroyTrigger(loc_trigger01)
endif
set loc_trigger01=null
set loc_unit01=null
return false
endfunction
function GrabTreeAttackEffect takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local trigger loc_trigger02
local integer loc_integer01=GetHandleId(loc_trigger01)
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(2)))
local integer loc_integer02=(LoadInteger(udg_DotaHashtable,(GetHandleId(loc_unit01)),(674)))
call DebugLog(LVL_DEBUG, "GrabTreeAttackEffect")
if GetTriggerEventId()==EVENT_PLAYER_UNIT_ATTACKED and loc_integer02<30 then
// A unit is attacked and the max attack count is not reached yet
if GetAttacker()==loc_unit01 and((LoadInteger(udg_DotaHashtable,(GetHandleId((loc_unit01))),((4297))))==1)==false then
// Attacker is Tiny && SaveUnitInCacheWithDelay is finshed
set loc_trigger02=CreateTrigger()
call TriggerRegisterUnitEvent(loc_trigger02,GetTriggerUnit(),EVENT_UNIT_DAMAGED)
call TriggerRegisterTimerEvent(loc_trigger02,1.00,false)
call TriggerAddCondition(loc_trigger02,Condition(function GrabTreeCountSuccessfulAttacks))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger02, "GrabTreeAttackEffect")
call SaveUnitHandle(udg_DotaHashtable,(GetHandleId(loc_trigger02)),(2),(loc_unit01))
endif
endif
if loc_integer02>29 then
// The max attack count is about to be reached
call SaveInteger(udg_DotaHashtable,(GetHandleId(GetTriggerUnit())),(674),(0))
call UnitRemoveAbility(loc_unit01,'A06M')
if(LoadInteger(udg_DotaHashtable,(loc_integer01),(34)))==1 then
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DestroyTrigger(loc_trigger01)
endif
endif
if GetTriggerEventId()!=EVENT_PLAYER_UNIT_ATTACKED then
// A unit is attacked
call SaveInteger(udg_DotaHashtable,(loc_integer01),(34),(1))
if loc_integer02>29 then
// The max attack count is about to be reached
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DestroyTrigger(loc_trigger01)
endif
call UnitRemoveAbility(loc_unit01,'A06K')
call SetPlayerTechResearched(GetOwningPlayer(loc_unit01),'R002',0)
//if(Func0367((loc_unit01),integers084[integer355])!=null)then
if (GetHeroLevel(loc_unit01)>=20)then
// Unit carries Tiny's aghanim scepter
call UnitAddPermanentAbility(loc_unit01,'A06L')
endif
call SetPlayerAbilityAvailable(GetOwningPlayer(loc_unit01),'A06L',true)
endif
set loc_trigger01=null
set loc_unit01=null
return false
endfunction
//Dissused
function Func2388 takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(2)))
if GetTriggerEvalCount(loc_trigger01)==1 then
call SetUnitTimeScalePercent(loc_unit01,250)
else
call SetUnitTimeScalePercent(loc_unit01,100)
call SetUnitAnimationByIndex(loc_unit01,12)
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DestroyTrigger(loc_trigger01)
endif
set loc_trigger01=null
return false
endfunction
function GrabTreeEffectRegister takes nothing returns boolean
local trigger loc_trigger01
call DebugLog(LVL_DEBUG, "GrabTreeEffectRegister")
if GetSpellAbilityId()=='A06L' then
// Tiny is casting GrabTree - Current version
call SaveUnitInCacheWithDelay(GetTriggerUnit(),4296,29.9)
call SetPlayerAbilityAvailable(GetOwningPlayer(GetTriggerUnit()),'A06L',false) // Remove dummy grap tree ability
call SetPlayerAbilityAvailable(GetOwningPlayer(GetTriggerUnit()),'A06K',true)
call UnitAddPermanentAbility(GetTriggerUnit(),'A06K') // Add the real grab tree ability
call SetPlayerTechResearched(GetOwningPlayer(GetTriggerUnit()),'R002',1)
call SetPlayerAbilityAvailable(GetOwningPlayer(GetTriggerUnit()),'A06M',false) // Disable to hide the spellbook
call UnitAddPermanentAbility(GetTriggerUnit(),'A06M')
call IssueTargetOrder(GetTriggerUnit(),"grabtree",GetSpellTargetDestructable()) // Cast the real grab tree ability
set loc_trigger01=CreateTrigger()
call TriggerRegisterTimerEvent(loc_trigger01,30,false)
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(loc_trigger01,Condition(function GrabTreeAttackEffect))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "GrabTreeEffectRegister")
call SaveUnitHandle(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(2),(GetTriggerUnit()))
call SaveInteger(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(34),(0))
call SaveInteger(udg_DotaHashtable,(GetHandleId(GetTriggerUnit())),(674),(0))
set loc_trigger01=null
elseif GetSpellAbilityId()=='A06C' then
// Tiny is casting GrabTree - Old version
call RemoveDestructable(GetSpellTargetDestructable())
call ShowUnit(GetTriggerUnit(),false)
call ShowUnit(GetTriggerUnit(),true)
call UnitRemoveAbility(GetTriggerUnit(),'Aloc')
call UnitAddAbility(GetTriggerUnit(),'A06D')
call UnitRemoveAbility(GetTriggerUnit(),'A06D')
call UnitAddAbility(GetTriggerUnit(),'A06I')
call UnitRemoveAbility(GetTriggerUnit(),'A06I')
call AddUnitAnimationProperties(GetTriggerUnit(),"upgrade",false)
endif
return false
endfunction
//Dissused
function Func2390 takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(2)))
//if(Func0367((loc_unit01),integers084[integer355])!=null)then
if(GetHeroLevel(loc_unit01)>=20)then
// Unit carries Tiny's aghanim scepter
if((LoadInteger(udg_DotaHashtable,(GetHandleId((loc_unit01))),((4296))))==1)==false then
if GetUnitAbilityLevel(loc_unit01,'A06L')==0 and GetUnitAbilityLevel(loc_unit01,'A06K')==0 then
call SetPlayerAbilityAvailable(GetOwningPlayer(loc_unit01),'A06L',true)
call UnitAddPermanentAbility(loc_unit01,'A06L')
call SetPlayerTechResearched(GetOwningPlayer(loc_unit01),'R002',0)
endif
endif
else
call UnitRemoveAbility(loc_unit01,'A06L')
call UnitRemoveAbility(loc_unit01,'A06K')
call SetPlayerTechResearched(GetOwningPlayer(loc_unit01),'R002',0)
endif
set loc_trigger01=null
return false
endfunction
// New function
function GrapTreeSkillRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(loc_trigger01,Condition(function GrabTreeEffectRegister))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "GrabTreeSkillRegister")
set loc_trigger01=null
endfunction
function GrowSkillLearnConditions takes nothing returns boolean
return GetLearnedSkill()=='A068' and IsUnitIllusion(GetTriggerUnit())==false
endfunction
function GrowUpdateScaleLoop takes nothing returns nothing
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(GetHandleId(GetTriggeringTrigger())),(298)))
local integer loc_integer01=GetUnitAbilityLevel(loc_unit01,'A068')
if GetUnitState(loc_unit01,UNIT_STATE_LIFE)>1 then
call SetUnitScale(loc_unit01,0.5+0.25*loc_integer01,0.5+0.25*loc_integer01,0.5+0.25*loc_integer01)
endif
endfunction
function GrowUpdateScaleEnterRegion takes nothing returns boolean
local integer loc_integer01
if IsUnitIllusion(GetTriggerUnit())and GetUnitTypeId(GetTriggerUnit())=='U00B' then
set loc_integer01=GetUnitAbilityLevel((LoadUnitHandle(udg_DotaHashtable,(GetHandleId(GetTriggeringTrigger())),(298))),'A068')
call SetUnitScale(GetTriggerUnit(),0.5+0.25*loc_integer01,0.5+0.25*loc_integer01,0.5+0.25*loc_integer01)
endif
return false
endfunction
function GrowSkillLearn takes nothing returns nothing
local trigger loc_trigger01
local unit loc_unit01=GetTriggerUnit()
local integer loc_integer01=GetUnitAbilityLevel(loc_unit01,'A068')
local unit loc_unit03=GetTriggerUnit()
local region loc_region01
call DebugLog(LVL_DEBUG, "GrowSkill")
call SetPlayerTechResearched(GetOwningPlayer(loc_unit01),'R001',loc_integer01)
if loc_integer01==1 then
set loc_trigger01=CreateTrigger()
call TriggerAddAction(loc_trigger01,function GrowUpdateScaleLoop)
call TriggerRegisterTimerEvent(loc_trigger01,2.00,true)
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "GrowSkillLearn")
call SaveUnitHandle(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(298),(loc_unit01))
call SetUnitScale(loc_unit01,0.5+0.25*loc_integer01,0.5+0.25*loc_integer01,0.5+0.25*loc_integer01)
set loc_trigger01=CreateTrigger()
call TriggerRegisterEnterRectSimple( loc_trigger01, GetEntireMapRect() )
call TriggerAddCondition(loc_trigger01,Condition(function GrowUpdateScaleEnterRegion))
call SaveUnitHandle(udg_DotaHashtable,(GetHandleId(loc_trigger01)),(298),(loc_unit01))
set loc_trigger01=null
endif
set loc_unit03=null
endfunction
function GrowSkillRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(loc_trigger01,Condition(function GrowSkillLearnConditions))
call TriggerAddAction(loc_trigger01,function GrowSkillLearn)
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "GrowSkillRegister")
//set loc_trigger01=CreateTrigger()
//call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_SPELL_EFFECT)
//call TriggerAddCondition(loc_trigger01,Condition(function GrabTreeEffectRegister))
//call SetAllPlayerGrabTreeAvailable()
set loc_trigger01=null
endfunction
function TossDamageUnit takes nothing returns nothing
if IsUnitType(GetEnumUnit(),UNIT_TYPE_STRUCTURE)==true then
call DamageUnit(udg_TempTossCaster,GetEnumUnit(),1,udg_TempTossDamages/3)
else
call DamageUnit(udg_TempTossCaster,GetEnumUnit(),1,udg_TempTossDamages)
endif
endfunction
function TossAreaDamage takes unit loc_unit01,real loc_real01,real loc_real02,real loc_real03,real loc_real04 returns nothing
local group loc_group01=CreateGroup()
set udg_TempTossProjectedUnit=loc_unit01
call GroupEnumUnitsInRange(loc_group01,loc_real01,loc_real02,loc_real03,Condition(function TargetFilterNoAncients))
set udg_TempTossCaster=loc_unit01
set udg_TempTossDamages=loc_real04
call ForGroup(loc_group01,function TossDamageUnit)
call DestroyGroup(loc_group01)
set loc_group01=null
endfunction
function TossFilterProjectableUnits takes nothing returns boolean
if((GetUnitAbilityLevel(GetFilterUnit(),'A069')==0 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and GetUnitDefaultMoveSpeed(GetFilterUnit())>0.00 and IsUnitUnknownOrDead(GetFilterUnit())==false)and IsUnitVisible(GetFilterUnit(),GetOwningPlayer(GetTriggerUnit())))and IsCourrierType(GetFilterUnit())==false and(IsUnitType(GetFilterUnit(),UNIT_TYPE_ANCIENT)==false or IsInvalidTargetType(GetFilterUnit()))then
return true
endif
return false
endfunction
function TossSelectProjectUnit takes unit loc_unit01 returns unit
local unit loc_unit02=null
local group loc_group01=CreateGroup()
call GroupEnumUnitsInRange(loc_group01,GetUnitX(loc_unit01),GetUnitY(loc_unit01),275,Condition(function TossFilterProjectableUnits))
call GroupRemoveUnit(loc_group01,loc_unit01)
set loc_unit02=GroupPickRandomUnit(loc_group01)
call DestroyGroup(loc_group01)
set udg_TempTossProjectedUnit=loc_unit02
set loc_unit02=null
set loc_group01=null
return udg_TempTossProjectedUnit
endfunction
function TossProjectedUnitFlightPeriodic takes nothing returns boolean
local trigger loc_trigger01=GetTriggeringTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
local integer loc_integer02=GetTriggerEvalCount(loc_trigger01)
local unit loc_unit01=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(14))) // Caster unit
local unit loc_unit02=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(2))) // Projected unit
//local integer loc_integer03=(LoadInteger(udg_DotaHashtable,(loc_integer01),(30)))
//local unit loc_unit03=Func0022(loc_integer03)
local unit loc_unit03=(LoadUnitHandle(udg_DotaHashtable,(loc_integer01),(30))) // Target unit
local real loc_real01=(LoadReal(udg_DotaHashtable,(loc_integer01),(282))) // Target X
local real loc_real02=(LoadReal(udg_DotaHashtable,(loc_integer01),(283))) // Target Y
local real loc_real03=GetUnitX(loc_unit02)
local real loc_real04=GetUnitY(loc_unit02)
local real loc_real05=GetUnitX(loc_unit03)
local real loc_real06=GetUnitY(loc_unit03)
local real loc_real07
local real loc_real08
local real loc_real09
local real loc_real10
local real loc_real11
local real loc_real12
local location loc_location01
call DebugLog(LVL_DEBUG, "TossProjectedUnitFlightPeriodic")
if DistanceBetweenPointsByCoord(loc_real01,loc_real02,loc_real05,loc_real06)>1000 then
set loc_real05=loc_real01
set loc_real06=loc_real02
endif
set loc_real07=MathsAtan2(loc_real03,loc_real04,loc_real05,loc_real06)
set loc_real08=DistanceBetweenPointsByCoord(loc_real03,loc_real04,loc_real05,loc_real06)
set loc_real09=loc_real08/IMaxBJ((51-loc_integer02),1)
set loc_real10=(loc_integer02-25)*(loc_integer02-25)
set loc_real11=loc_real03+loc_real09*Cos(loc_real07*bj_DEGTORAD)
set loc_real12=loc_real04+loc_real09*Sin(loc_real07*bj_DEGTORAD)
if loc_integer02<51 then
if IsUnitFlying(loc_unit02)==false then
call SetUnitFlyHeight(loc_unit02,775-loc_real10,0)
endif
call SetUnitPosition(loc_unit02,loc_real11,loc_real12)
else
if IsUnitFlying(loc_unit02)==false then
call SetUnitFlyHeight(loc_unit02,GetUnitDefaultFlyHeight(loc_unit02),0)
endif
call PauseUnit(loc_unit02,false)
call SetUnitPathing(loc_unit02,true)
call SetUnitPosition(loc_unit02,loc_real05,loc_real06)
call SaveInteger(udg_DotaHashtable,(GetHandleId((loc_unit02))),((4268)),(2))
set loc_location01=Location(loc_real05,loc_real06)
call TerrainDeformationRippleBJ(0.2,true,loc_location01,1.00,300.00,96.00,1,64.00)
call RemoveLocation(loc_location01)
call DestroyEffect((LoadEffectHandle(udg_DotaHashtable,(loc_integer01),(32)))) // Projection effect handle
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(loc_unit02),GetUnitY(loc_unit02)))
if IsUnitAlly(loc_unit02,GetOwningPlayer(loc_unit01))then
else
//if(Func0367((loc_unit01),integers084[integer355])!=null)then
if(GetHeroLevel(loc_unit01)>=20)then
// Unit carries Aghanim scepter
call DamageUnit(loc_unit01,loc_unit02,1,(0.2+0.15*GetUnitAbilityLevel(loc_unit01,'A068')+1)*2000*GetUnitAbilityLevel(loc_unit01,'A06G'))
else
call DamageUnit(loc_unit01,loc_unit02,1,(0.2+0.15*GetUnitAbilityLevel(loc_unit01,'A068'))*2000*GetUnitAbilityLevel(loc_unit01,'A06G'))
endif
endif
call DestroyTreeDestructablesInRegion(loc_real05,loc_real06,300)
call TossAreaDamage(loc_unit01,loc_real05,loc_real06,300,550*GetUnitAbilityLevel(loc_unit01,'A06G'))
//call Func0021(loc_integer03)
call FlushChildHashtable(udg_DotaHashtable,(loc_integer01))
call DisableTrigger(loc_trigger01)
endif
set loc_trigger01=null
set loc_unit01=null
set loc_unit02=null
set loc_unit03=null
set loc_location01=null
return false
endfunction
function TossSourceEffect takes nothing returns nothing
local unit loc_unit01=GetTriggerUnit()
local unit loc_unit02=TossSelectProjectUnit(loc_unit01)
local unit loc_unit03=GetSpellTargetUnit()
local trigger loc_trigger01=CreateTrigger()
local integer loc_integer01=GetHandleId(loc_trigger01)
call DebugLog(LVL_DEBUG, "TossSourceEffect")
//call SetUnitAnimationByIndex(loc_unit01,4)
call SetUnitAnimation(loc_unit01, "spell")
call PauseUnit(loc_unit02,true)
call SetUnitPathing(loc_unit02,false)
if IsUnitFlying(loc_unit02)==false then
call UnitAddAbility(loc_unit02,'Amrf')
call UnitRemoveAbility(loc_unit02,'Amrf')
endif
call SaveInteger(udg_DotaHashtable,(GetHandleId((loc_unit02))),((4268)),(1)) // Is unit projected
call SaveUnitHandle(udg_DotaHashtable,(loc_integer01),(14),(loc_unit01)) // Caster unit
call SaveUnitHandle(udg_DotaHashtable,(loc_integer01),(2),(loc_unit02)) // Projected unit
//call SaveInteger(udg_DotaHashtable,(loc_integer01),(30),(Func0024(loc_unit03))) // Target handle
call SaveUnitHandle(udg_DotaHashtable,(loc_integer01),(30),loc_unit03) // Target unit
call SaveEffectHandle(udg_DotaHashtable,(loc_integer01),(32),(AddSpecialEffectTarget("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl",loc_unit02,"origin"))) // Projection effect handle
call SaveReal(udg_DotaHashtable,(loc_integer01),(282),((GetUnitX(loc_unit03))*1.0)) // Target X
call SaveReal(udg_DotaHashtable,(loc_integer01),(283),((GetUnitY(loc_unit03))*1.0)) // Target Y
call TriggerRegisterTimerEvent(loc_trigger01,0.02,true)
call TriggerAddCondition(loc_trigger01,Condition(function TossProjectedUnitFlightPeriodic))
//call TriggerDebugAutomation_TriggerIsReady(loc_trigger01, "TossSourceEffect")
set loc_unit01=null
set loc_unit02=null
set loc_unit03=null
set loc_trigger01=null
endfunction
function TossSourceCast takes nothing returns nothing
local unit loc_unit01=GetTriggerUnit()
local unit loc_unit02=TossSelectProjectUnit(loc_unit01)
local unit loc_unit03=GetSpellTargetUnit()
call DebugLog(LVL_DEBUG, "TossSourceCast")
if loc_unit02==null then
call StopUnitSilent(loc_unit01)
call DisplayError(GetOwningPlayer(loc_unit01),"No valid unit to Toss")
elseif GetOwningPlayer(loc_unit03)==GetOwningPlayer(loc_unit01)then
call StopUnitSilent(loc_unit01)
call DisplayError(GetOwningPlayer(loc_unit01),"Cannot Toss to your own units")
endif
set loc_unit01=null
set loc_unit02=null
set loc_unit03=null
endfunction
function TossEffect takes nothing returns boolean
if GetSpellAbilityId()=='A06G' then
call DebugLog(LVL_DEBUG, "TossEffect")
if GetTriggerEventId()==EVENT_PLAYER_UNIT_SPELL_CAST then
call TossSourceCast()
else
call TossSourceEffect()
endif
endif
return false
endfunction
function TossEffectRegister takes nothing returns nothing
local trigger loc_trigger01=CreateTrigger()
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerRegisterAllPlayersUnitEvent(loc_trigger01,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(loc_trigger01,Condition(function TossEffect))
set loc_trigger01=null
endfunction
library GameStatus uses optional PlayerUtils
/***************************************************************
*
* v1.0.0 by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Simple API for detecting if the game is online, offline, or a replay.
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it (requires JassHelper *or* JNGP)
* _________________________________________________________________________
* 2. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* This library provides one function
*
* function GetGameStatus takes nothing returns integer
*
* It returns one of the following constants
*
* - GAME_STATUS_OFFLINE
* - GAME_STATUS_ONLINE
* - GAME_STATUS_REPLAY
*
***************************************************************/
// Configuration:
globals
// The dummy unit is only created once, and removed directly after.
private constant integer DUMMY_UNIT_ID = 'hfoo'
endglobals
// (end)
globals
constant integer GAME_STATUS_OFFLINE = 0
constant integer GAME_STATUS_ONLINE = 1
constant integer GAME_STATUS_REPLAY = 2
private integer status = 0
endglobals
function GetGameStatus takes nothing returns integer
return status
endfunction
private module GameStatusInit
private static method onInit takes nothing returns nothing
local player firstPlayer
local unit u
local boolean selected
// find an actual player
static if not (LIBRARY_PlayerUtils) then
set firstPlayer = Player(0)
loop
exitwhen (GetPlayerController(firstPlayer) == MAP_CONTROL_USER and GetPlayerSlotState(firstPlayer) == PLAYER_SLOT_STATE_PLAYING)
set firstPlayer = Player(GetPlayerId(firstPlayer)+1)
endloop
else
set firstPlayer = User.fromPlaying(0).toPlayer()
endif
// force the player to select a dummy unit
set u = CreateUnit(firstPlayer, DUMMY_UNIT_ID, 0, 0, 0)
call SelectUnit(u, true)
set selected = IsUnitSelected(u, firstPlayer)
call RemoveUnit(u)
set u = null
if (selected) then
// detect if replay or offline game
if (ReloadGameCachesFromDisk()) then
set status = GAME_STATUS_OFFLINE
else
set status = GAME_STATUS_REPLAY
endif
else
// if the unit wasn't selected instantly, the game is online
set status = GAME_STATUS_ONLINE
endif
endmethod
endmodule
private struct GameStatus
implement GameStatusInit
endstruct
endlibrary
library Maths
function Floor takes real r returns integer
local integer i = R2I(r)
if r == i then
return i
endif
if r > 0 then
return i
else // if r < 0 then
return i - 1
endif
endfunction
function Ceil takes real r returns integer
local integer i = R2I(r)
if r == i then
return i
endif
if r > 0 then
return i + 1
else // if r < 0 then
return i
endif
endfunction
function Round takes real r returns integer
if r > 0 then
return R2I(r + 0.5)
else // if r < 0 then
return R2I(r - 0.5)
endif
endfunction
endlibrary
library Logarithm
globals
private constant integer ITERATIONS=20
endglobals
function Log takes real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(bj_E,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
function Logarithm takes real base, real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(base,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
endlibrary
/*
Armor lib v1.0.1 (28/11/2019) by Ricola3D
API:
### General ###
function ArmorToDamageFactor takes real whichArmor returns real
> Converts armor amount to damage factor.
function DamageFactorToArmor takes real whichDamageFactor returns real
> Converts damage factor to armor amount.
### Unit ###
function ModifyArmor takes unit whichUnit, real armorDiff returns nothing
> Adds/removes the given difference to unit's code armor.
function AdjustArmorToWhite takes unit whichUnit, real desiredWhiteArmor returns nothing
> Modifies unit's code armor to obtain the desired amount of white armor.
function AdjustArmorToWhitePercent takes unit whichUnit, real desiredWhiteArmorPercent returns nothing
> Modifies unit's code armor to obtain the desired percent of current white armor.
function AdjustArmorToTotal takes unit whichUnit, real desiredTotalArmor returns nothing
> Modifies unit's code armor to obtain the desired amount of total armor.
function AdjustArmorToTotalPercent takes unit whichUnit, real desiredTotalArmorPercent returns nothing
> Modifies unit's code armor to obtain the desired percent of current total armor.
function SetCodeArmor takes unit whichUnit, real desiredCodeArmor returns nothing
> Sets unit's code armor to the given value.
function GetWhiteArmor takes unit whichUnit returns real
> Gets white (base + agi + code) armor of the unit.
function GetGreenArmor takes unit whichUnit returns real
> Gets green armor of the unit.
function GetTotalArmor takes unit whichUnit returns real
> Gets total (white + green) armor of the unit.
function GetDamageFactor takes unit whichUnit returns real
> Gets the damage factor corresponding to the total armor of the unit.
function GetAgiArmor takes unit whichUnit, boolean includeBonuses returns real
> Gets agility armor of the unit.
function GetCodeArmor takes unit whichUnit returns real
> Gets code armor of the unit (0 by default, modified by setters).
function GetBaseArmor takes unit whichUnit returns real
> Worthless. Gets base (value from Object Editor) armor of the unit.
*/
native UnitAlive takes unit id returns boolean
library Armor requires Logarithm /*, TriggerDebugAutomation*/
globals
// ----------------------------------------------------------------------------
// BASE SETTINGS
// ----------------------------------------------------------------------------
// Values shall be taken from gameplay constants
constant real AGI_DEFENSE_BASE = 5.00 // "Hero Attributes - Defense Base Value (before Agility Bonus)"
constant real AGI_DEFENSE_BONUS = 0.1 // "Hero Attributes - Defense Bonus per Agility Point"
constant real DEFENSE_ARMOR = 0.06 // "Combat - Armor Damage Reduction Multiplier"
// An ability derivated from Devotion Aura that nullifies what Blizzard considers "base" armor.
private constant integer NULLIFY_BASE_ARMOR_ABILITY = 'A05K'
private constant integer NULLIFY_BASE_ARMOR_BUFF = 'B01J'
// System cleaning - Ability to detect unit removal from game
// If you already have a Unit Event system (GUI Unit Event by Bribe, Unit Event by Nestharus, or AutoEvents by grim001) you can reuse the same ability.
private constant integer DETECT_REMOVE_ABILITY = 'A06D'
// ----------------------------------------------------------------------------
// ADVANCED SETTINGS (you may leave them default)
// ----------------------------------------------------------------------------
// Set to true if you want the getter/setters to work for hidden units.
// Notes:
// - Works fine except in one case: during "[ANef] Storm, Earth, And Fire" ability cast.
constant boolean ENABLE_UNHIDE = true
// Set to true to enable last ressort action (if nothing else worked to compute armor values).
// Notes:
// - No known case for the moment, it's just a safe fallback measure.
// - Will temporary remove items, and remove all buffs (only aura/passive buffs will be re-activate after, not active ones)
constant boolean ENABLE_BONUS_REMOVAL = true
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Internal storage for code armor value
private hashtable unitData
endglobals
// ----------------------------------------------------------------------------
// SaveCode.
// Notes: since there is no native to access internal "code armor" value from Blizzard. This function stores a copy of it.
// ----------------------------------------------------------------------------
private function SaveCode takes unit whichUnit, real codeArmor returns nothing
if ( null != whichUnit ) then
// In case there is no Unit Event system, add the remove detect ability manually.
if ( 0 == GetUnitAbilityLevel(whichUnit, DETECT_REMOVE_ABILITY) ) then
call UnitAddAbility(whichUnit, DETECT_REMOVE_ABILITY)
call UnitMakeAbilityPermanent(whichUnit, true, DETECT_REMOVE_ABILITY)
endif
call SaveReal( unitData, GetHandleId(whichUnit), StringHash("code_armor"), codeArmor )
endif
endfunction
// ----------------------------------------------------------------------------
// ArmorToDamageFactor: get damage modifier corresponding to a armor value.
// Notes:
// - "0.02" means damages are reduced by 98%.
// - "1.25" means damages are amplified by 25%.
// - For the moment Blizzard displays -71% as min reduction
// ----------------------------------------------------------------------------
function ArmorToDamageFactor takes real whichArmor returns real
local real factor = 0.0
if (whichArmor >= 0) then
// Damage reduction - factor is inferior or equal to 1
set factor = 1 - ( whichArmor * DEFENSE_ARMOR ) / ( 1 + whichArmor * DEFENSE_ARMOR )
else
// DamageAmplification - factor is superior to 1
set factor = 2 - Pow( 1 - DEFENSE_ARMOR , -1 * whichArmor )
endif
return factor
endfunction
// ----------------------------------------------------------------------------
// DamageFactorToArmor: computes the armor necessary to reach this damage factor.
// Notes:
// - Does not work for 0 walue (= dodge, nullify damage).
// - Does not work for negative values (=heal).
// ----------------------------------------------------------------------------
function DamageFactorToArmor takes real whichDamageFactor returns real
local real armor = 0.0
if (whichDamageFactor <= 0.0) then
// Negative factor does not work - infinite armor or healing
elseif (whichDamageFactor <= 1.0) then
// Damage reduction - armor is positive or null
set armor = ( 1 - whichDamageFactor ) / ( whichDamageFactor * DEFENSE_ARMOR )
else
// Damage amplification - armor is negative
set armor = -1.0 * Logarithm( 1.0 - DEFENSE_ARMOR, 2.0 - whichDamageFactor )
endif
return armor
endfunction
// ----------------------------------------------------------------------------
// GetAgiArmor: get armor bonus from agility. Returns 0 for non-hero units.
// ----------------------------------------------------------------------------
function GetAgiArmor takes unit whichUnit, boolean includeBonuses returns real
local real agiArmor = 0.0
local integer agi = 0
local boolean isHero = false
if ( null != whichUnit ) then
set isHero = IsUnitIdType(GetUnitTypeId(whichUnit), UNIT_TYPE_HERO)
if (isHero) then
// Unit is hero, illusion of hero, ...
set agi = GetHeroAgi(whichUnit, includeBonuses)
set agiArmor = AGI_DEFENSE_BASE + AGI_DEFENSE_BONUS * I2R(agi)
endif
endif
return agiArmor
endfunction
// ----------------------------------------------------------------------------
// GetCodeArmor: get code armor. This is the only armor you can modify directly (with BlzSetUnitArmor primitive).
// ----------------------------------------------------------------------------
function GetCodeArmor takes unit whichUnit returns real
local real codeArmor = 0.0
if ( null != whichUnit ) then
set codeArmor = LoadReal( unitData, GetHandleId(whichUnit), StringHash("code_armor") )
endif
return codeArmor
endfunction
// ----------------------------------------------------------------------------
// GetBaseArmor: get what Blizzard considers "base" armor.
// If no upgrades, equal to the number in World Editor > Object Editor > Unit > "[def] Combat - Defense base".
// Otherwise also includes upgrades count x "[defUp] Defense Upgrade Bonus"
// Notes:
// - Meaningless in 99% of cases. Equal to white armor ONLY for non-hero units whose armor have not been modified by code...)
// - This is the value taken as base by Devotion Aura with "[DataB1] Data - Percent Bonus" set to true.
// ----------------------------------------------------------------------------
function GetBaseArmor takes unit whichUnit returns real
local real totalArmorBefore = 0.0
local real totalArmorAfter = 0.0
local real baseArmor = 0.0
static if ENABLE_BONUS_REMOVAL then
local integer inventorySize = 0
local integer tempInventorySlot = 0
local item array unitItems
endif
local boolean abilityAdded = false
local boolean buffAdded = false
local boolean isDead = false
static if ENABLE_UNHIDE then
local boolean isHidden = false
endif
if ( null != whichUnit ) then
static if ENABLE_UNHIDE then
set isHidden = IsUnitHidden(whichUnit)
if (isHidden) then
call ShowUnit(whichUnit, true)
endif
endif
// Try to compute base armor using the test ability (that nullifies base armor).
set totalArmorBefore = BlzGetUnitArmor(whichUnit)
call UnitAddAbility(whichUnit, NULLIFY_BASE_ARMOR_ABILITY)
set abilityAdded = ( GetUnitAbilityLevel(whichUnit, NULLIFY_BASE_ARMOR_ABILITY) > 0 )
set buffAdded = ( GetUnitAbilityLevel(whichUnit, NULLIFY_BASE_ARMOR_BUFF) > 0 )
if (abilityAdded and buffAdded) then
// Test worked, base armor has been nullified properly.
set totalArmorAfter = BlzGetUnitArmor(whichUnit)
set baseArmor = totalArmorBefore - totalArmorAfter
else
// Test failed
set isDead = ( not UnitAlive(whichUnit) )
if (isDead) then
// Case A: unit is dead. Thus its green armor is 0, and base = total - agi - code
set baseArmor = BlzGetUnitArmor(whichUnit) - GetAgiArmor(whichUnit, false) - GetCodeArmor(whichUnit)
static if ENABLE_BONUS_REMOVAL then
else
// Case Z: last resort is to remove all armor bonuses
// Temporary remove all items
set inventorySize = UnitInventorySizeBJ(whichUnit)
set tempInventorySlot = 0
loop
set tempInventorySlot = tempInventorySlot + 1
exitwhen tempInventorySlot > inventorySize
set unitItems[tempInventorySlot] = UnitItemInSlotBJ(whichUnit, tempInventorySlot)
if ( null != unitItems[tempInventorySlot] ) then
call UnitRemoveItemFromSlot(whichUnit, tempInventorySlot)
endif
endlop
// Remove all buffs (unfortunately there is no way to restore the active buffs)
call UnitRemoveBuffsEx(whichUnit, true, true, true, true, false, true, true) // Remove all buffs but timed life
set armor = BlzGetUnitArmor(whichUnit) - GetAgiArmor(whichUnit, false) - GetCodeArmor(whichUnit)
// Restore all items
set tempInventorySlot = 0
loop
set tempInventorySlot = tempInventorySlot + 1
exitwhen tempInventorySlot > inventorySize
if ( null != unitItems[tempInventorySlot] ) then
call UnitDropItemSlotBJ( whichUnit, unitItems[tempInventorySlot], tempInventorySlot )
endif
endlop
endif
endif
endif
if (abilityAdded) then
call UnitRemoveAbility(whichUnit, NULLIFY_BASE_ARMOR_ABILITY)
endif
if (buffAdded) then
call UnitRemoveBuffBJ(NULLIFY_BASE_ARMOR_BUFF, whichUnit)
endif
static if ENABLE_UNHIDE then
if (isHidden) then
call ShowUnit(whichUnit, false)
endif
endif
endif
return baseArmor
endfunction
// ----------------------------------------------------------------------------
// GetWhiteArmor: get armor before bonus (= number displayed in white in unit status).
// ----------------------------------------------------------------------------
function GetWhiteArmor takes unit whichUnit returns real
local real whiteArmor = 0.0
local integer baseAgi = 0
if ( null != whichUnit ) then
set whiteArmor = GetBaseArmor(whichUnit) + GetAgiArmor(whichUnit, false) + GetCodeArmor(whichUnit)
endif
return whiteArmor
endfunction
// ----------------------------------------------------------------------------
// GetTotal: get total armor. Same as BlzGetUnitArmor.
// ----------------------------------------------------------------------------
function GetTotalArmor takes unit whichUnit returns real
local real armor = 0.0
if ( null != whichUnit ) then
set armor = BlzGetUnitArmor(whichUnit)
endif
return armor
endfunction
// ----------------------------------------------------------------------------
// GetGreenArmor: get current armor bonus (= number displayed in green in unit status.
// ----------------------------------------------------------------------------
function GetGreenArmor takes unit whichUnit returns real
return ( GetTotalArmor(whichUnit) - GetWhiteArmor(whichUnit) )
endfunction
// ----------------------------------------------------------------------------
// GetDamageFactor: get current damage factor taking into account total armor. Does not consider attack type, damage type and armor type!
// Notes:
// - If factor is <1, then damage reduction
// - If factor >1, then damage amplification
// - If factor ==1, damages unchanged, null armor.
// - If factor ==0, then error.
// ----------------------------------------------------------------------------
function GetDamageFactor takes unit whichUnit returns real
local real damageFactor = 0.0
local real totalArmor = 0.0
if ( null != whichUnit ) then
set totalArmor = GetTotalArmor(whichUnit)
set damageFactor = DamageFactorToArmor(totalArmor)
endif
return damageFactor
endfunction
// ----------------------------------------------------------------------------
// ModifyArmor: apply difference to unit code armor (and thus to white armor). Difference can be positive or negative.
// Also modifies white armor and total armor of the same difference.
// ----------------------------------------------------------------------------
function ModifyArmor takes unit whichUnit, real armorDiff returns nothing
local real currentTotalArmor = 0.0
if ( null != whichUnit ) then
set currentTotalArmor = BlzGetUnitArmor(whichUnit)
call BlzSetUnitArmor(whichUnit, currentTotalArmor + armorDiff )
endif
endfunction
// ----------------------------------------------------------------------------
// SetCode: set unit code armor to desired value.
// ----------------------------------------------------------------------------
function SetCodeArmor takes unit whichUnit, real desiredCodeArmor returns nothing
local real currentCodeArmor = 0.0
local real armorDiff = 0.0
if ( null != whichUnit ) then
set currentCodeArmor = GetCodeArmor(whichUnit)
set armorDiff = desiredCodeArmor - currentCodeArmor
call ModifyArmor(whichUnit, armorDiff)
endif
endfunction
// ----------------------------------------------------------------------------
// AdjustArmorToWhite: set unit base armor such as white armor reaches the desired amount.
// ----------------------------------------------------------------------------
function AdjustArmorToWhite takes unit whichUnit, real desiredWhiteArmor returns nothing
local real currentWhiteArmor = 0.0
local real armorDiff = 0.0
if ( null != whichUnit ) then
set currentWhiteArmor = GetWhiteArmor(whichUnit)
set armorDiff = desiredWhiteArmor - currentWhiteArmor
call ModifyArmor(whichUnit, armorDiff)
endif
endfunction
// ----------------------------------------------------------------------------
// AdjustArmorToWhitePercent: set unit base armor such as white armor changes of the desirated percent.
// Ex: 1.50 will increase white armor of 50%
// ----------------------------------------------------------------------------
function AdjustArmorToWhitePercent takes unit whichUnit, real desiredWhiteArmorPercent returns nothing
local real currentWhiteArmor = 0.0
local real armorDiff = 0.0
if ( null != whichUnit ) then
set currentWhiteArmor = GetWhiteArmor(whichUnit)
set armorDiff = currentWhiteArmor * (desiredWhiteArmorPercent - 1.0)
call ModifyArmor(whichUnit, armorDiff)
endif
endfunction
// ----------------------------------------------------------------------------
// AdjustArmorToTotal: set unit base armor such as total reaches the desired amount.
// Same as BlzSetUnitArmor.
// ----------------------------------------------------------------------------
function AdjustArmorToTotal takes unit whichUnit, real desiredTotalArmor returns nothing
if ( null != whichUnit ) then
call BlzSetUnitArmor(whichUnit, desiredTotalArmor)
endif
endfunction
// ----------------------------------------------------------------------------
// AdjustArmorToTotalPercent: set unit base armor such as total armor changes of the desirated percent.
// Ex: 1.50 will increase total armor of 50%
// ----------------------------------------------------------------------------
function AdjustArmorToTotalPercent takes unit whichUnit, real desiredTotalArmorPercent returns nothing
local real currentTotalArmor = 0.0
if ( null != whichUnit ) then
set currentTotalArmor = BlzGetUnitArmor(whichUnit)
call BlzSetUnitArmor( whichUnit, currentTotalArmor * desiredTotalArmorPercent )
endif
endfunction
// ----------------------------------------------------------------------------
// onBlzSetUnitArmor: called just before everytime code sets unit armor with "BlzSetUnitArmor" native.
// Notes: since there is no native to access internal "code armor" value from Blizzard. This function stores a copy of it.
// ----------------------------------------------------------------------------
private function onBlzSetUnitArmor takes unit whichUnit, real armorAmount returns nothing
local real previousCodeArmor = 0.0
local real nextCodeArmor = 0.0
local real previousArmorAmount = 0.0
local real armorDiff = 0.0
if ( null != whichUnit ) then
// Detect armor difference
set previousArmorAmount = BlzGetUnitArmor(whichUnit)
set armorDiff = armorAmount - previousArmorAmount
// Get previous code armor (0 if not existing), update it, and save-it back
set previousCodeArmor = GetCodeArmor(whichUnit)
set nextCodeArmor = previousCodeArmor + armorDiff
call SaveCode(whichUnit, nextCodeArmor)
endif
endfunction
hook BlzSetUnitArmor onBlzSetUnitArmor
// ----------------------------------------------------------------------------
// onBlzSetUnitRealField: called just before everytime code sets unit armor with "BlzSetUnitRealField" native for UNIT_RF_DEFENSE field.
// Notes: intenally just calls onBlzSetUnitArmor function.
// ----------------------------------------------------------------------------
private function onBlzSetUnitRealField takes unit whichUnit, unitrealfield whichField, real value returns nothing
if ( UNIT_RF_DEFENSE == whichField ) then
call onBlzSetUnitArmor(whichUnit, value)
endif
endfunction
hook BlzSetUnitRealField onBlzSetUnitRealField
// ----------------------------------------------------------------------------
// onUnitRemoved: called just before a unit is removed from the game. Cleans internal storage.
// ----------------------------------------------------------------------------
private function onUnitRemoved takes nothing returns nothing
local unit whichUnit = GetTriggerUnit()
local boolean unitBeingRemoved
// Because unit has DETECT_REMOVE_ABILITY, it will fire a "undefend" event just before being removed from game.
if ( OrderId2StringBJ(GetIssuedOrderIdBJ()) == "undefend" ) then
set unitBeingRemoved = ( 0 == GetUnitAbilityLevel(whichUnit, DETECT_REMOVE_ABILITY) )
if (unitBeingRemoved) then
call FlushChildHashtable( unitData, GetHandleId(whichUnit) )
endif
endif
endfunction
// ----------------------------------------------------------------------------
// onInit: system initializer
// ----------------------------------------------------------------------------
private module M
private static method onInit takes nothing returns nothing
local trigger cleanTrigger = CreateTrigger() // trigger to detect unit removal (and clean hashtable)
call TriggerRegisterAnyUnitEventBJ( cleanTrigger, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddAction( cleanTrigger, function onUnitRemoved )
//call TriggerDebugAutomation_TriggerIsReady(cleanTrigger, "cleanTrigger")
set unitData = InitHashtable() // Init hashtable (avoid adding dependency to an indexer)
endmethod
endmodule
private struct S extends array
implement M
endstruct
endlibrary
library TimeUtils
globals
private constant string FIELDS_DELIMITER = ":"
endglobals
function FormatTime takes real seconds returns string
// Compute seconds, minutes and hours
local real s = ModuloReal( seconds, 60.0 )
local integer m = R2I(ModuloReal( seconds, 3600 ) / 60.0)
local integer h = R2I(seconds / 3600.0)
local string ss
local string ms
local string hs
local string formatedTime
// Format seconds as real with 3 decimals string
set ss = R2SW(s, 2, 3)
// Format minutes as a 2-character number string (3 => 03)
set ms = I2S(m)
if ( 1 == StringLength(ms) ) then
set ms = "0" + ms
endif
// Format hours as a 2-character number string (3 => 03)
set hs = I2S(h)
if ( 1 == StringLength(hs) ) then
set hs = "0" + hs
endif
// Contatenate to obtenate a time under the form: HH:MM:SS.sss
set formatedTime = hs + FIELDS_DELIMITER + ms + FIELDS_DELIMITER + ss
return formatedTime
endfunction
endlibrary
//===========================================================================
function UnitEventInAction takes nothing returns nothing
if (not udg_UnitInAction[udg_UDex]) then
set udg_UnitInAction[udg_UDex] = true
set udg_UnitInActionEvent = 0.00
set udg_UnitInActionEvent = 1.00
set udg_UnitInActionEvent = 0.00
endif
endfunction
function UnitEventInaction takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS
local unit u = udg_UDexUnits[udg_UDex]
local player p
local player p2
local boolean b
if udg_IsUnitAlive[udg_UDex] and udg_CargoTransportUnit[udg_UDex] != null then
set p2 = GetOwningPlayer(udg_CargoTransportUnit[udg_UDex])
endif
if (udg_UnitInAction[udg_UDex]) then
set udg_UnitInAction[udg_UDex] = false
set udg_UnitInActionEvent = 0.00
set udg_UnitInActionEvent = 2.00
set udg_UnitInActionEvent = 0.00
endif
// Check if selected by some players
loop
set i = i - 1
set p = Player(i)
if IsUnitInGroup(u, udg_PlayerSelection[i]) then
call GroupRemoveUnit(udg_PlayerSelection[i], u)
set udg_PDex = i + 1
set udg_PlayerSelectionEvent = 0.00
set udg_PlayerSelectionEvent = 2.00
set udg_PlayerSelectionEvent = 0.00
// Check if selected unit is loaded in a controlable transporter
set b = (p == p2) or GetPlayerAlliance(p2, p, ALLIANCE_SHARED_CONTROL) or GetPlayerAlliance(p2, p, ALLIANCE_SHARED_ADVANCED_CONTROL)
if (b) then
call GroupAddUnit(udg_PlayerSelection[i], udg_CargoTransportUnit[udg_UDex])
set udg_UDex = GetUnitUserData(udg_CargoTransportUnit[udg_UDex])
set udg_PDex = i + 1
set udg_PlayerSelectionEvent = 0.00
set udg_PlayerSelectionEvent = 1.00
set udg_PlayerSelectionEvent = 0.00
endif
endif
exitwhen i == 0
endloop
endfunction
function UnitEventOnSelect takes nothing returns boolean
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer i = GetPlayerId(p)
local boolean b = IsUnitInGroup(u, udg_PlayerSelection[i])
if (not b) then
call GroupAddUnit(udg_PlayerSelection[i], u)
set udg_UDex = GetUnitUserData(u)
set udg_PDex = i + 1
set udg_PlayerSelectionEvent = 0.00
set udg_PlayerSelectionEvent = 1.00
set udg_PlayerSelectionEvent = 0.00
endif
return false
endfunction
function UnitEventOnDeselect takes nothing returns boolean
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer i = GetPlayerId(p)
local boolean b = IsUnitInGroup(u, udg_PlayerSelection[i])
if (b) then
call GroupRemoveUnit(udg_PlayerSelection[i], u)
set udg_UDex = GetUnitUserData(u)
set udg_PDex = i + 1
set udg_PlayerSelectionEvent = 0.00
set udg_PlayerSelectionEvent = 2.00
set udg_PlayerSelectionEvent = 0.00
endif
return false
endfunction
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer id = 0
local unit u
loop
set id = udg_CheckDeathList[id]
exitwhen id == 0
set udg_UDex = id
set u = udg_UDexUnits[id]
if udg_IsUnitNew[id] then
//The unit was just created.
set udg_IsUnitNew[id] = false
set udg_UnitIndexEvent = 1.50 //New event requested by SpellBound to detect when unit fully enters scope.
set udg_UnitIndexEvent = 0.00
elseif udg_IsUnitTransforming[id] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[id] = GetUnitTypeId(u) //Set this afterward as otherwise the user won't know what the previous unittype was.
set udg_IsUnitTransforming[id] = false
call UnitAddAbility(u, udg_DetectTransformAbility)
elseif udg_IsUnitAlive[id] then
//The unit has started reincarnating (=is a tombstone).
set udg_IsUnitReincarnating[id] = true
set udg_IsUnitAlive[id] = false
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
call UnitEventInaction()
elseif GetUnitTypeId(u) != 0 and not IsUnitType(u, UNIT_TYPE_DEAD) then //with vJass, could just use UnitAlive instead of both of these values.
//Moved this code to fire after a 0 second timer instead.
set udg_IsUnitAlive[id] = true
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
call UnitEventInAction()
set udg_IsUnitReincarnating[id] = false
endif
set udg_CheckDeathInList[id] = false
endloop
set u = null
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
call UnitEventInAction()
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
call UnitEventInaction()
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
// Fire an inaction event for UDex
call UnitEventInaction()
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventCheckAfterProxy(i) //modified 22 Oct 2022 to ensure the unit is fully revived before firing the event.
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
call UnitEventInaction()
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
call UnitEventInAction()
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
call UnitEventInaction()
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
set udg_CheckDeathInList[i] = false
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
// Fire a in action event
call UnitEventInAction()
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local trigger select = CreateTrigger()
local trigger deselect = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_CheckDeathList[0] = 0
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
call TriggerAddCondition(select, Filter(function UnitEventOnSelect))
call TriggerAddCondition(deselect, Filter(function UnitEventOnDeselect))
loop
set i = i - 1
set p = Player(i)
set udg_PlayerSelection[i] = CreateGroup()
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call TriggerRegisterPlayerUnitEvent( select, p, EVENT_PLAYER_UNIT_SELECTED, null)
call TriggerRegisterPlayerUnitEvent( deselect, p, EVENT_PLAYER_UNIT_DESELECTED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
// TODO: just in case, a 2nd loop for units already selected by the init struct of another library ?
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
/*
vJass Damage Engine 5.A.0.0
This update enables compatibility with AttackIndexer.
*/
/*
JASS API:
struct Damage extends array
readonly static unit source // udg_DamageEventSource in real-time
readonly static unit target // udg_DamageEventTarget in real-time
static real amount // udg_DamageEventAmount in real-time
readonly unit sourceUnit // udg_DamageEventSource by index
readonly unit targetUnit // udg_DamageEventTarget by index
real damage // udg_DamageEventAmount by index
readonly real prevAmt // udg_DamageEventPrevAmt by index
attacktype attackType // udg_DamageEventAttackT by index
damagetype damageType // udg_DamageEventDamageT by index
weapontype weaponType // udg_DamageEventWeaponT by index
integer userType // udg_DamageEventType by index
readonly boolean isAttack // udg_IsDamageAttack by index
readonly boolean isCode // udg_IsDamageCode by index
readonly boolean isMelee // udg_IsDamageMelee by index
readonly boolean isRanged // udg_IsDamageRanged by index
readonly boolean isSpell // udg_IsDamageSpell by index
real armorPierced // udg_DamageEventArmorPierced by index
integer armorType // udg_DamageEventArmorT by index
integer defenseType // udg_DamageEventDefenseT by index
readonly integer eFilter
Set to false to disable the damage event triggers or to true to reverse that:
static boolean operator enabled
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 apply takes
unit source,
unit target,
real amount,
boolean isAttack,
boolean isRanged,
attacktype at,
damagetype dt,
weapontype wt
returns Damage
A simplified version of the above function that autofills each boolean, attacktype and weapontype.
static method applySpell takes
unit src,
unit tgt,
real amt,
damagetype dt
returns Damage
A different variation of the above which autofills the "isAttack" boolean
and populates damagetype as DAMAGE_TYPE_NORMAL.
static method applyAttack takes
unit src,
unit tgt,
real amt,
boolean ranged,
attacktype at,
weapontype wt
returns Damage
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:
- integer DamageEngine_FILTER_ATTACK
- integer DamageEngine_FILTER_MELEE
- integer DamageEngine_FILTER_OTHER
- integer DamageEngine_FILTER_RANGED
- integer DamageEngine_FILTER_SPELL
- integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
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
method configure takes nothing returns nothing
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 registerTrigger takes
trigger whichTrig,
string var,
real value
returns nothing
static method unregister takes
trigger whichTrig,
string eventName,
real value,
boolean reset
returns boolean
static method getIndex takes
trigger fromTrigger,
string eventName,
real value
returns integer
If you already have the index of the trigger you want to unregister:
method unregisterByIndex takes
boolean reset
returns boolean
Converts a code argument to a trigger, while checking if the same code had already been registered before.
Use it via DamageTrigger[function MyCallbackFunction]
static method operator [] takes
code callback
returns trigger
The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister:
function TriggerRegisterDamageEngineEx takes
trigger whichTrig,
string eventName,
real value,
integer opId
returns nothing
function TriggerRegisterDamageEngine takes
trigger whichTrig,
string eventName,
real value
returns nothing
function RegisterDamageEngineEx takes
code callback,
string eventName,
real value,
integer opId
returns nothing
function RegisterDamageEngine takes
code callback,
string eventName,
real value
returns nothing
*/
//===========================================================================
library DamageEngine requires optional AttackIndexer /*, TriggerDebugAutomation*/
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 SourceDamageEvent, 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
/*
When manually-enabled recursion is enabled via DamageEngine_inception,
the engine will never go deeper than MAX_RECURSIVE_TOLERANCE:
*/
private constant integer MAX_RECURSIVE_TOLERANCE = 16
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 M$ ever changes this, it'll be a quick fix here.
private timer async = null
private boolean timerStarted = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean isNotNativeRecursiveDamage = true
private boolean waitingForDamageEventToRun = false
private boolean array attacksImmune
private boolean array damagesImmune
//Primary triggers used to handle all damage events.
private trigger damagingTrigger = null
private trigger damagedTrigger = null
private trigger recursiveTrigger = null //Catches, stores recursive events
/*
These variables coincide with Blizzard's "limitop" type definitions
so as to enable GUI users with some performance perks - however,
these optimizations need to be tested
*/
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
/*
When true, it allows your trigger to go recursively up to
MAX_RECURSIVE_TOLERANCE (if needed). It must be set before dealing damage.
*/
public boolean inception = false
private boolean callbacksInProgress = false
private integer recursiveCallbackDepth = 0
private group recursionSources = null
private group recursionTargets = null
private boolean recursiveCallbaksInProgress = false
private boolean nativeEventsCompleted = false
private boolean atLeastOneLethalDamageEventRegistered = false
// Struct members made private to this library.
private keyword run
private keyword trigFrozen
private keyword ownRecursiveDepth
private keyword manualRecursionRequested
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 "checkConfig" 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
//Added in 5.8:
boolean udg_RemoveDamageEvent //Allow GUI users to more fully unregister a damage event trigger. Can only be used from within a damage event (of any kind).
integer udg_DamageFilterSourceA
integer udg_DamageFilterTargetA //Check if a source or target have a specific ability (will overwrite any source or target buff check, I need to use this because GUI differentiates ability ID and buff ID)
integer udg_DamageFilterSourceI
integer udg_DamageFilterTargetI //Check if a source or target have a specific type of item
integer udg_DamageFilterSourceC
integer udg_DamageFilterTargetC //Classification of source/target (e.g. hero, treant, ward)
//Added in 5.9
real udg_SourceDamageEvent //Like AOEDamageEvent, fires each time the source unit has finished dealing damage, but doesn't care if the damage hit multiple units.
real udg_PreDamageEvent //Like DamageModifierEvent 3.99 or less, except can be any real value.
real udg_ArmorDamageEvent //Like DamageModifierEvent 4.00 or more, except can be any real value.
real udg_OnDamageEvent //Like DamageEvent equal to 1.00 or some non-zero/non-2 value, except can be any real value.
real udg_ZeroDamageEvent //Like DamageEvent equal to 0.00 or 2.00, except can be any real value.
*/
struct DamageTrigger extends array
static method checkItem takes unit u, integer id returns boolean
local integer i
if IsUnitType(u, UNIT_TYPE_HERO) then
set i = UnitInventorySize(u)
loop
exitwhen i <= 0
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == id then
return true
endif
endloop
endif
return false
endmethod
/*
Map makers should probably not use these filters,
unless someone tests performance to see
if such an ugly hack is even worth it.
*/
method checkConfig takes nothing returns boolean
//call BJDebugMsg("Checking configuration")
if 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 this.failChance > 0.00 and GetRandomReal(0.00, 1.00) <= this.failChance then
elseif 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.sourceItem != 0 and not .checkItem(udg_DamageEventSource, this.sourceItem) then
elseif this.targetItem != 0 and not .checkItem(udg_DamageEventTarget, this.targetItem) then
elseif this.sourceClass >= 0 and not IsUnitType(udg_DamageEventSource, ConvertUnitType(this.sourceClass)) then
elseif this.targetClass >= 0 and not IsUnitType(udg_DamageEventTarget, ConvertUnitType(this.targetClass)) then
elseif udg_DamageEventAmount >= this.damageMin then
//call BJDebugMsg("Configuration passed")
return true
endif
//call BJDebugMsg("Checking failed")
return false
endmethod
//The below variables are to be treated as 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 usingGUI
private thistype next
private trigger rootTrig
//The below variables are to be treated as private
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer ownRecursiveDepth //How deep the user recursion currently is.
boolean manualRecursionRequested //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent triggers.
//configuration variables:
boolean configured
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
integer sourceItem
integer targetItem
integer sourceClass
integer targetClass
real damageMin
real failChance
integer attackType
integer damageType
integer userType
// getter:
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
// setter:
method operator runChance= takes real chance returns nothing
set this.failChance = 1.00 - chance
endmethod
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.sourceItem = udg_DamageFilterSourceI
set this.targetItem = udg_DamageFilterTargetI
set this.sourceClass = udg_DamageFilterSourceC
set this.targetClass = udg_DamageFilterTargetC
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set this.failChance = 1.00 - (udg_DamageFilterRunChance - udg_DamageFilterFailChance)
if udg_DamageFilterSourceA > 0 then
set this.sourceBuff = udg_DamageFilterSourceA
set udg_DamageFilterSourceA = 0
else
set this.sourceBuff = udg_DamageFilterSourceB
endif
if udg_DamageFilterTargetA > 0 then
set this.targetBuff = udg_DamageFilterTargetA
set udg_DamageFilterTargetA = 0
else
set this.targetBuff = udg_DamageFilterTargetB
endif
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
//These handles can have a valid value of 0, so we need to distinguish them.
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterSourceI = 0
set udg_DamageFilterTargetI = 0
set udg_DamageFilterMinAmount = 0.00
set udg_DamageFilterFailChance = 0.00
set udg_DamageFilterRunChance = 1.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
//! runtextmacro optional ATTACK_INDEXER_GUI_VARS()
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" and root < 4) or var == "udg_PreDamageEvent" then
set root = MOD
elseif var == "udg_DamageModifierEvent" or var == "udg_ArmorDamageEvent" then
set root = SHIELD
elseif (var == "udg_DamageEvent" and root == 2 or root == 0) or var == "udg_ZeroDamageEvent" then
set root = ZERO
elseif var == "udg_DamageEvent" or var == "udg_OnDamageEvent" then
set root = DAMAGE
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" or var == "udg_SourceDamageEvent" 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 opId returns nothing
set this = this * FILTER_MAX
if opId == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if opId == 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 + opId] = 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
//allows GUI to register multiple different types of Damage filters to the same trigger
set filters[lastRegistered*FILTER_MAX + filt] = true
return 0
endif
set atLeastOneLethalDamageEventRegistered = /*
*/ atLeastOneLethalDamageEventRegistered or index == LETHAL
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
//they will probably bug out with class types as well, so I should add them, just in case:
set id.sourceClass = -1
set id.targetClass = -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
method unregisterByIndex takes boolean reset returns boolean
if this == 0 then
return false
endif
set prev.next = this.next
set trigIndexStack[this] = trigIndexStack[0]
set trigIndexStack[0] = this
if reset then
call this.configure()
set this.configured = false
call thistype(this*FILTER_MAX).toggleAllFilters(false)
endif
return true
endmethod
static method unregister takes /*
*/ trigger t, /*
*/ string eventName, /*
*/ real lbs, /*
*/ boolean reset /*
*/ returns boolean
return getIndex(t, eventName, lbs).unregisterByIndex(reset)
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 callbacksInProgress then
return
endif
set callbacksInProgress = true
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
call EnableTrigger(recursiveTrigger)
//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.checkConfig())) and /*
*/ (cat != AOE or udg_DamageEventAOE > 1 or this.eventStr == "udg_SourceDamageEvent") /*
*/ 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
if udg_RemoveDamageEvent then
set udg_RemoveDamageEvent = false
call this.unregisterByIndex(true)
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(recursiveTrigger)
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set callbacksInProgress = false
endmethod
/*
Used by RegisterDamageEngineEx to create triggers behind-the-scenes,
allowing the user to simply pass the function they want to execute.
*/
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code callback returns trigger
local integer i = 0
local boolexpr b = Filter(callback)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
//call TriggerDebugAutomation_TriggerIsReady(autoTriggers[i], "autoTriggers_" + I2S(i))
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
readonly unit targetUnit
real damage
readonly real prevAmt
attacktype attackType
damagetype damageType
weapontype weaponType
integer userType
readonly boolean isAttack
readonly boolean isCode
readonly boolean isSpell
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 not (pierce == 0.00) then //Changed from != to not == due to bug reported by BLOKKADE
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
call DamageTrigger.AOE.run()
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif
private static method afterDamage takes nothing returns nothing
if udg_DamageEventDamageT != 0 and not (udg_DamageEventPrevAmt == 0.00) then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method runDamagingEvents 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(recursionSources, udg_DamageEventSource)
call GroupAddUnit(recursionTargets, 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()
// Using not == instead of !=; the idea is to eliminate floating point bugs when two numbers are very close to 0,
// because JASS uses a less-strict comparison for checking if a number is equal than when it is unequal.
if not (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 //return value is based on whether the event is a 0 damage event (true) or not (false).
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.ownRecursiveDepth = 0
endloop
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set recursiveCallbaksInProgress = false
set damageStack = 0
set prepped = 0
set callbacksInProgress = false
set recursiveCallbackDepth = 0
call GroupClear(recursionSources)
call GroupClear(recursionTargets)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method runAfterDamageEvents takes nothing returns nothing
local Damage i = 0
local integer exit
if nativeEventsCompleted then
set nativeEventsCompleted = false
call afterDamage()
endif
if isNotNativeRecursiveDamage and not recursiveCallbaksInProgress then
if damageStack != 0 then
set recursiveCallbaksInProgress = true
loop
/*
Use two loops. The outer loop handles all normal event
execution, while the inner loop intelligently handles
recursive execution (when it's used).
*/
set recursiveCallbackDepth = recursiveCallbackDepth + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then
// We don't need to trigger `damagingTrigger` itself, so just call its handler directly.
call prepped.runDamagingEvents(false)
if prepped.damage > 0.00 then
call DisableTrigger(damagingTrigger) // Disallow `damagingTrigger` because we only want `damageTrigger` to run.
call EnableTrigger(damagedTrigger) // Re-enable `damagedTrigger` in case the user forgot to do so.
set waitingForDamageEventToRun = true
call UnitDamageTarget( /*
*/ prepped.sourceUnit, /*
*/ prepped.targetUnit, /*
*/ prepped.damage, /*
*/ prepped.isAttack, /*
*/ prepped.isRanged, /*
*/ prepped.attackType, /*
*/ prepped.damageType, /*
*/ prepped.weaponType /*
*/ )
else
if udg_DamageEventDamageT != 0 then
//No native events run at all in this case
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
/*
No need for BlzSetEventDamage/UnitDamageTarget here,
because we can safely adjust the unit's life instead.
*/
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 isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
set waitingForDamageEventToRun = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set nativeEventsCompleted = true
endif
call runAfterDamageEvents()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if callbacksInProgress then
call EnableTrigger(recursiveTrigger)
else
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
endif
else
if callbacksInProgress then
call DisableTrigger(recursiveTrigger)
else
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(damagingTrigger)
endmethod
private static boolean threadCompleted = false
private static method asyncCallbackSafeCallback takes nothing returns nothing
if waitingForDamageEventToRun then
/*
This means that WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
*/
call failsafeClear()
else
set isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
call runAfterDamageEvents()
endif
static if USE_EXTRA then
call onAOEEnd()
endif
set threadCompleted = true
endmethod
private static method asyncCallback takes nothing returns nothing
set callbacksInProgress = false
set Damage.enabled = true
/*
Open a new thread in case of a thread crash during callback.
*/
call ForForce(bj_FORCE_PLAYER[0], function thistype.asyncCallbackSafeCallback)
if not threadCompleted then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set threadCompleted = false
endif
set Damage.count = 0
set Damage.index = 0
set timerStarted = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
local DamageTrigger currentIndex
if not (this.damage == 0.00) then
set currentIndex = DamageTrigger.eventIndex
set this.recursiveTrig = currentIndex
if not this.isCode then
/*
If the recursive damage trigger is executed, this can only
mean that the user has manually dealt damage from a trigger.
Hence flag the damage as being 'code' if they didn't already
manually do this.
*/
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or /*
*/ currentIndex.manualRecursionRequested
if recursiveCallbaksInProgress and /*
*/ IsUnitInGroup(this.sourceUnit, recursionSources) and /*
*/ IsUnitInGroup(this.targetUnit, recursionTargets) /*
*/ then
if not inception then
set currentIndex.trigFrozen = true
elseif not currentIndex.trigFrozen then
set currentIndex.manualRecursionRequested = true
if currentIndex.ownRecursiveDepth < recursiveCallbackDepth then
set currentIndex.ownRecursiveDepth = /*
*/ currentIndex.ownRecursiveDepth + 1
if currentIndex.ownRecursiveDepth >= MAX_RECURSIVE_TOLERANCE then
set currentIndex.trigFrozen = true
endif
endif
endif
endif
// push the reference to the top of the damage stack.
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " ownRecursiveDepth: " + I2S(currentIndex.ownRecursiveDepth) + " recursiveCallbackDepth: " + I2S(recursiveCallbackDepth))
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 isAttack, /*
*/ 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.damageType = dt
set d.attackType = at
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or isAttack
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = thistype.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.damageType == DAMAGE_TYPE_UNKNOWN and not (d.damage == 0.00))
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
// Added in version 5.A in order to allow an optional external
// Attack Indexer system to reset the event weapon type to normal.
//! runtextmacro optional ATTACK_INDEXER_ADJUSTMENTS()
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
// Melee units always play a sound when damaging in WC3,
// so this is an easy check.
set d.isMelee = d.weaponType != null
// In the case where a unit is both ranged and melee,
// the ranged attack plays no sound.
set d.isRanged = not d.isMelee
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
// Spells are neither melee nor ranged.
set d.isMelee = false
set d.isRanged = false
endif
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursiveDamageCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamagingCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if timerStarted then
if waitingForDamageEventToRun 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 waitingForDamageEventToRun = false
set lastInstance = Damage.index
set isNotNativeRecursiveDamage = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call runAfterDamageEvents() //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
set udg_EnhancedDamageTarget = d.targetUnit
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(async, 0.00, false, function Damage.asyncCallback)
set timerStarted = 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.runDamagingEvents(true) then
call DamageTrigger.ZERO.run()
set isNotNativeRecursiveDamage = true
call runAfterDamageEvents()
endif
set waitingForDamageEventToRun = 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 onDamagedCallback 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 callbacksInProgress or d.prevAmt == 0.00 then
return false
elseif waitingForDamageEventToRun then
set waitingForDamageEventToRun = false
else
/*
This should only happen for native recursive WarCraft 3 damage
such as Spirit Link, Thorns Aura, or Spiked Carapace / Barricades.
*/
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
/*
Since the native recursive damage has now wrapped up, we can resume
handling events as normal at this point. This means that the original
target that the DAMAGING event was triggered for is now finally getting
its DAMAGED event.
*/
set isNotNativeRecursiveDamage = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then
call d.setArmor(true)
endif
static if USE_SCALING then
if not (udg_DamageEventAmount == 0.00) and not (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 atLeastOneLethalDamageEventRegistered or udg_DamageEventType < 0 then
set udg_LethalDamageHP = /*
*/ GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if atLeastOneLethalDamageEventRegistered 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 nativeEventsCompleted = true
if udg_DamageEventAmount == 0.00 then
call runAfterDamageEvents()
endif
// This return statement was needed years ago to avoid potential crashes on Mac.
// I am not sure if that's still a thing.
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 callbacksInProgress 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 runAfterDamageEvents()
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
/*
This part is the most critical to get things kicked off. All the code we've seen up until now
is related to event handling, trigger assignment, edge cases, etc. But it's the following that
is really quite esesntial for any damage engine - not just this one.
*/
private static method onInit takes nothing returns nothing
set async = CreateTimer()
set recursionSources = CreateGroup()
set recursionTargets = CreateGroup()
set damagingTrigger = CreateTrigger()
set damagedTrigger = CreateTrigger()
set recursiveTrigger = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(damagingTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(damagingTrigger, Filter(function Damage.onDamagingCallback))
//call TriggerDebugAutomation_TriggerIsReady(damagingTrigger, "damagingTrigger")
call TriggerRegisterAnyUnitEventBJ(damagedTrigger, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(damagedTrigger, Filter(function Damage.onDamagedCallback))
//call TriggerDebugAutomation_TriggerIsReady(damagedTrigger, "damagedTrigger")
//For recursion
call TriggerRegisterAnyUnitEventBJ(recursiveTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(recursiveTrigger, Filter(function Damage.onRecursiveDamageCallback))
call DisableTrigger(recursiveTrigger) //starts disabled. Will be enabled during recursive event handling.
//call TriggerDebugAutomation_TriggerIsReady(recursiveTrigger, "recursiveTrigger")
/*
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
// Called from the GUI configuration trigger once the assignments are in place.
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"
// Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
/*
In-game World Editor doesn't allow Attack Type and Damage Type comparisons.
Therefore, I need to code them as integers into GUI
*/
set udg_ATTACK_TYPE_SPELLS = 0
set udg_ATTACK_TYPE_NORMAL = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
// -
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
/*
The below variables don't affect damage amount, but do affect the sound played
They also give important information about the type of attack used.
They can differentiate between ranged and melee for units who are both
*/
set udg_WEAPON_TYPE_NONE = 0
// Metal Light/Medium/Heavy
set udg_WEAPON_TYPE_ML_CHOP = 1
set udg_WEAPON_TYPE_MM_CHOP = 2
set udg_WEAPON_TYPE_MH_CHOP = 3
set udg_WEAPON_TYPE_ML_SLICE = 4
set udg_WEAPON_TYPE_MM_SLICE = 5
set udg_WEAPON_TYPE_MH_SLICE = 6
set udg_WEAPON_TYPE_MM_BASH = 7
set udg_WEAPON_TYPE_MH_BASH = 8
set udg_WEAPON_TYPE_MM_STAB = 9
set udg_WEAPON_TYPE_MH_STAB = 10
// Wood Light/Medium/Heavy
set udg_WEAPON_TYPE_WL_SLICE = 11
set udg_WEAPON_TYPE_WM_SLICE = 12
set udg_WEAPON_TYPE_WH_SLICE = 13
set udg_WEAPON_TYPE_WL_BASH = 14
set udg_WEAPON_TYPE_WM_BASH = 15
set udg_WEAPON_TYPE_WH_BASH = 16
set udg_WEAPON_TYPE_WL_STAB = 17
set udg_WEAPON_TYPE_WM_STAB = 18
// Claw Light/Medium/Heavy
set udg_WEAPON_TYPE_CL_SLICE = 19
set udg_WEAPON_TYPE_CM_SLICE = 20
set udg_WEAPON_TYPE_CH_SLICE = 21
// Axe Medium
set udg_WEAPON_TYPE_AM_CHOP = 22
// Rock Heavy
set udg_WEAPON_TYPE_RH_BASH = 23
/*
Since GUI still doesn't provide Defense Type and Armor Types,
I needed to include the below:
*/
set udg_ARMOR_TYPE_NONE = 0
set udg_ARMOR_TYPE_FLESH = 1
set udg_ARMOR_TYPE_METAL = 2
set udg_ARMOR_TYPE_WOOD = 3
set udg_ARMOR_TYPE_ETHEREAL = 4
set udg_ARMOR_TYPE_STONE = 5
set udg_DEFENSE_TYPE_LIGHT = 0
set udg_DEFENSE_TYPE_MEDIUM = 1
set udg_DEFENSE_TYPE_HEAVY = 2
set udg_DEFENSE_TYPE_FORTIFIED = 3
set udg_DEFENSE_TYPE_NORMAL = 4
set udg_DEFENSE_TYPE_HERO = 5
set udg_DEFENSE_TYPE_DIVINE = 6
set udg_DEFENSE_TYPE_UNARMORED = 7
/*
The remaining stuff is an ugly 'optimization' that I did a long
time ago, thinking that it would improve performance for GUI users
by not having so many different triggerconditions evaluating per
damage event. I am not sure if it even worked; in Lua it might
perform worse, but in vJass it remains to be tested.
*/
set udg_UNIT_CLASS_HERO = 0
set udg_UNIT_CLASS_DEAD = 1
set udg_UNIT_CLASS_STRUCTURE = 2
set udg_UNIT_CLASS_FLYING = 3
set udg_UNIT_CLASS_GROUND = 4
set udg_UNIT_CLASS_ATTACKS_FLYING = 5
set udg_UNIT_CLASS_ATTACKS_GROUND = 6
set udg_UNIT_CLASS_MELEE = 7
set udg_UNIT_CLASS_RANGED = 8
set udg_UNIT_CLASS_GIANT = 9
set udg_UNIT_CLASS_SUMMONED = 10
set udg_UNIT_CLASS_STUNNED = 11
set udg_UNIT_CLASS_PLAGUED = 12
set udg_UNIT_CLASS_SNARED = 13
set udg_UNIT_CLASS_UNDEAD = 14
set udg_UNIT_CLASS_MECHANICAL = 15
set udg_UNIT_CLASS_PEON = 16
set udg_UNIT_CLASS_SAPPER = 17
set udg_UNIT_CLASS_TOWNHALL = 18
set udg_UNIT_CLASS_ANCIENT = 19
set udg_UNIT_CLASS_TAUREN = 20
set udg_UNIT_CLASS_POISONED = 21
set udg_UNIT_CLASS_POLYMORPHED = 22
set udg_UNIT_CLASS_SLEEPING = 23
set udg_UNIT_CLASS_RESISTANT = 24
set udg_UNIT_CLASS_ETHEREAL = 25
set udg_UNIT_CLASS_MAGIC_IMMUNE = 26
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterRunChance = 1.00
endfunction
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 opId /*
*/ returns DamageTrigger
return DamageTrigger.registerVerbose( /*
*/ whichTrig, /*
*/ DamageTrigger.getVerboseStr(eventName), /*
*/ value, /*
*/ false, /*
*/ opId /*
*/ )
endfunction
function TriggerRegisterDamageEngine takes /*
*/ trigger whichTrig, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value, /*
*/ integer opId /*
*/ returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[callback], eventName, value, opId)
endfunction
//Similar to TriggerRegisterDamageEvent, but takes code instead of trigger as the first argument.
function RegisterDamageEngine takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return RegisterDamageEngineEx(callback, eventName, value, FILTER_OTHER)
endfunction
/*
The below macros are 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()
endif
if not DamageTrigger.eventIndex.checkConfig() then
return
endif
//! endtextmacro
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//=====================================================================================
// Easy Item Stack 'n Split v2.7.4
// by Dangerb0y
//=====================================================================================
library EasyItemStacknSplit initializer onInit /*requires TriggerDebugAutomation*/
//=====================================================================================
//
// This system adds some much needed item stacking, item splitting, and full inventory
// functionality to Warcraft III.
//
// A couple of useful functions are also included...
//
// - UnitInventoryFull( unit )
// Returns true if all of a unit's inventory slots are occupied, else false.
//
// - UnitStackItem( unit, item )
// Works like UnitAddItem(), but will try to stack items even if inventory is full.
// If excess items from an item stack are dropped, returns the item, else null.
//
//=====================================================================================
// SYSTEM PARAMETERS
//=====================================================================================
globals
// Allow item splitting with double right-click?
private boolean SPLIT = true
// Amount to split from stack... (0 = half)
private integer SPLIT_SIZE = 1
// Allow consecutively split items to stack together?
private boolean SPLIT_STACK = true
private real SPLIT_STACK_DELAY = 2.00
// Allow split items to be dropped if no inventory slots are open?
private boolean SPLIT_DROP = true
// Use item levels to determine stack limit? (false = unlimited stacks)
private boolean USE_ITEM_LEVEL = true
// Full inventory error sound filename... (null = disabled)
private string ERROR_SOUND = "Sound\\Interface\\Error.wav"
private string ERROR_MESSAGE = "Inventory is full."
private integer array DUMMY_ITEM_TYPES
private integer array REAL_ITEM_TYPES
endglobals
function InitDummyItemPairs takes nothing returns nothing
// Since BlzSetItemBooleanField does not work, to allow buying items with full inventory we are forced to do this
// For each item with charges, we created a tome-like dummy copy with "use automatically on acquired" = true.
// Such dummy items can be clicked-bought even with full inventory, contrary to other items.
set DUMMY_ITEM_TYPES[0] = 'I00P' // 1st dummy item bought from shop
set REAL_ITEM_TYPES[0] = 'wild' // 1st real item heroes can use
set DUMMY_ITEM_TYPES[1] = 'I00Q'
set REAL_ITEM_TYPES[1] = 'ankh'
set DUMMY_ITEM_TYPES[2] = 'I00O'
set REAL_ITEM_TYPES[2] = 'pams'
set DUMMY_ITEM_TYPES[3] = 'I00W'
set REAL_ITEM_TYPES[3] = 'I002'
set DUMMY_ITEM_TYPES[4] = 'I00S'
set REAL_ITEM_TYPES[4] = 'whwd'
set DUMMY_ITEM_TYPES[5] = 'I00T'
set REAL_ITEM_TYPES[5] = 'pghe'
set DUMMY_ITEM_TYPES[6] = 'I00U'
set REAL_ITEM_TYPES[6] = 'pgma'
set DUMMY_ITEM_TYPES[7] = 'I00V'
set REAL_ITEM_TYPES[7] = 'pnvu'
set DUMMY_ITEM_TYPES[8] = 'I00X'
set REAL_ITEM_TYPES[8] = 'stwp'
endfunction
//=====================================================================================
// DO NOT EDIT BELOW THIS LINE
//=====================================================================================
globals
private unit array goPickButFullUnits
private unit array splitStackUnits
private item array goPickButFullItems
private item array splitStackItem1s
private item array splitStackItem2s
private real array splitStackDelays
private integer goPickButFullCount = 0
private integer splitStackCount = 0
private timer t = CreateTimer()
endglobals
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// PUBLIC FUNCTION : UnitInventoryFull( unit )
// Checks if all the inventory slots of a unit are occupied.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function UnitInventoryFull takes unit u returns boolean
local integer inventorySize = UnitInventorySize( u )
local integer slot = 0
loop
exitwhen slot >= inventorySize
if UnitItemInSlot(u, slot) == null then
return false
endif
set slot = slot + 1
endloop
return true
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// PUBLIC FUNCTION : FireStackChangedEvent( unit, item )
// Fire an event to signal that the stack size on an item carriet has changed.
// The solution decided for the moment is to trigger a "Unit - is issued an order targeting item" to move it in-place event.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function FireStackChangedEvent takes unit u, item i returns nothing
local integer inventorySize = UnitInventorySize(u)
local integer slot = 0
// Retrieve the item's slot
loop
if ( UnitItemInSlot(u, slot) == i ) then
exitwhen true // item's slot found
endif
set slot = slot + 1
exitwhen slot >= inventorySize
endloop
if ( slot < inventorySize ) then
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitDropItemSlot( u, i, slot )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
endif
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// PUBLIC FUNCTION : UnitStackItem( unit, item )
// Works like UnitAddItem() with full inventory functionality.
// Returns true if excess items are dropped. Otherwise false.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function UnitStackItem takes unit u, item item1 returns boolean
local integer item1Charges = GetItemCharges( item1 )
local integer inventorySize
local integer item1Level
local integer item1TypeId
local item item2
local integer item2Charges
local integer item2Level
local integer slot
local real posX
local real posY
local real unitAngle
// Make sure the item has charges
if item1Charges <= 0 then
// If not we just give it to the unit
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, item1 )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
else
// Item has charges
set inventorySize = UnitInventorySize( u )
set item1Level = GetItemLevel( item1 )
set item1TypeId = GetItemTypeId( item1 )
// We can remove the item, we have all the data we need from it
call RemoveItem( item1 )
// Look for items of the same type and try stack onto them
set slot = 0
loop
set item2 = UnitItemInSlot( u, slot )
set item2Charges = GetItemCharges( item2 )
set item2Level = GetItemLevel( item2 )
if item2 != null and (not USE_ITEM_LEVEL or item2Level == 0 or item2Charges < item2Level) and GetItemTypeId(item2) == item1TypeId then
// Found an item with same type and room for some charges
if USE_ITEM_LEVEL and item2Level > 0 and item2Charges + item1Charges > item2Level then
// Not all charges can be stacked onto this item, stack as many as possible and keep the rest
call SetItemCharges( item2, item2Level )
call FireStackChangedEvent(u,item2)
set item1Charges = item2Charges + item1Charges - item2Level
else
// All charges can be stacked onto this item
call SetItemCharges( item2, item2Charges + item1Charges )
call FireStackChangedEvent(u,item2)
set item1Charges = 0
endif
endif
set slot = slot + 1
exitwhen item1Charges <= 0 or slot >= inventorySize
endloop
// If there are any charges left over, look for open slots
if item1Charges > 0 then
// There are charges left
set posX = GetUnitX( u )
set posY = GetUnitY( u )
set slot = 0
loop
// Create as many items as necessary and possible in the unit inventory
set item2 = UnitItemInSlot( u, slot )
if item2 == null then
// There is a free slot: create a new item there for the remaining charges
set item2 = CreateItem( item1TypeId, posX, posY )
if USE_ITEM_LEVEL and item1Level > 0 and item1Charges > item1Level then
// Not all charges can fit in a single item, just put as many as possible
call SetItemCharges( item2, item1Level )
set item1Charges = item1Charges - item1Level
else
// All charges fit in this new item
call SetItemCharges( item2, item1Charges )
set item1Charges = 0
endif
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, item2 )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
endif
set slot = slot + 1
exitwhen item1Charges <= 0 or slot >= inventorySize
endloop
// If there are still charges left over, drop them on the ground
if item1Charges > 0 then
// There are some charges left that cannot be carried
set unitAngle = GetUnitFacing( u )
set posX = GetUnitX( u ) + 100 * Cos( unitAngle * bj_DEGTORAD )
set posY = GetUnitY( u ) + 100 * Sin( unitAngle * bj_DEGTORAD )
loop
// Create a many items as necessary on the floor
if item1Charges > item1Level then
// Not all charges can find in a single
set item2Charges = item1Level
set item1Charges = item1Charges - item1Level
else
// All charges can fit in a single item
set item2Charges = item1Charges
set item1Charges = 0
endif
set item2 = CreateItem( item1TypeId, posX, posY )
call SetItemCharges( item2, item2Charges )
exitwhen item1Charges <= 0
endloop
return true
endif
endif
endif
// Nothing dropped
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// TEXTMACRO : EasyItemStacknSplit_PLAYITEMSOUND( soundname, unitvar )
// Plays item sound for player if the triggering unit is nearby.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! textmacro EasyItemStacknSplit_PLAYITEMSOUND takes FILENAME
set str = "Sound\\Interface\\$FILENAME$.wav"
set snd = CreateSound( str, false, true, false, 12700, 12700, "" )
call AttachSoundToUnit( snd, u )
call SetSoundVolume( snd, 75 )
call SetSoundDistances( snd, 600.0, 1024.0 )
call SetSoundDistanceCutoff( snd, 1536.0 )
if GetLocalPlayer() != p then
call StartSound( snd )
endif
call KillSoundWhenDone( snd )
//! endtextmacro
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : TimerController
// EVENTS : Global Timer (t) expires (periodically, 0.05)
// Runs through full-stack and split-stack queues, and works its magic.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function TimerController takes nothing returns nothing
local unit u
local item item1
local item item2
local integer index
local integer orderId
local real deltax
local real deltay
local real delay
local player p
local string str
local sound snd
// Run through the go-pick-but-full actions stack queue
if goPickButFullCount > 0 then
set index = 0
loop
set u = goPickButFullUnits[index]
set item1 = goPickButFullItems[index]
if u != null and item1 != null and not IsItemOwned(item1) and GetWidgetLife(item1) > 0 and GetWidgetLife(u) > 0 then
// Unit and items are still untouched
set orderId = GetUnitCurrentOrder( u )
set deltax = GetItemX( item1 ) - GetUnitX( u )
set deltay = GetItemY( item1 ) - GetUnitY( u )
if deltax * deltax + deltay * deltay <= 22500 or orderId != 851986 then
// Unit has reached the item, or unit is not currently moving
if orderId == 851986 then
// Unit is moving - get the item and try to stack it
set p = GetOwningPlayer( u )
// Play the "Item Get" sound
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "PickUpItem" )
call IssueImmediateOrder( u, "stop" )
call SetUnitFacing( u, bj_RADTODEG * Atan2(GetItemY(item1) - GetUnitY(u), GetItemX(item1) - GetUnitX(u)) )
if UnitStackItem(u, item1) then
// Couldn't stack all the charges, somes have been left on the floor, play the "Item Drop" sound
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "HeroDropItem1" )
endif
endif
set goPickButFullCount = goPickButFullCount - 1
if goPickButFullCount > 0 then
// To fill the hole in the queue, move-in the last action
set goPickButFullUnits[index] = goPickButFullUnits[goPickButFullCount]
set goPickButFullItems[index] = goPickButFullItems[goPickButFullCount]
set index = index - 1
endif
endif
elseif u != null or item1 != null then
// The item has been destroyed or picked by someone else
call IssueImmediateOrder( u, "stop" )
set goPickButFullCount = goPickButFullCount - 1
if goPickButFullCount > 0 then
// To fill the hole in the queue, move-in the last action
set goPickButFullUnits[index] = goPickButFullUnits[goPickButFullCount]
set goPickButFullItems[index] = goPickButFullItems[goPickButFullCount]
set index = index - 1
endif
endif
set index = index + 1
exitwhen index >= goPickButFullCount
endloop
endif
// Run through split-stack actions queue
if SPLIT_STACK and splitStackCount > 0 then
set index = 0
loop
set u = splitStackUnits[index]
set item1 = splitStackItem1s[index]
set item2 = splitStackItem2s[index]
set delay = splitStackDelays[index]
if u != null and item1 != null and item2 != null and delay > 0 and UnitHasItem(u, item1) and UnitHasItem(u, item2) then
// Unit still carries both items - split&stack may have not been resolved yet
set splitStackDelays[index] = delay - 0.05
else
// Split-stack has been finished somehow
set splitStackCount = splitStackCount - 1
if splitStackCount > 0 then
// To fill the hole in the queue, move-in the last action
set splitStackUnits[index] = splitStackUnits[splitStackCount]
set splitStackItem1s[index] = splitStackItem1s[splitStackCount]
set splitStackItem2s[index] = splitStackItem2s[splitStackCount]
set splitStackDelays[index] = splitStackDelays[splitStackCount]
set index = index - 1
endif
endif
set index = index + 1
exitwhen index >= splitStackCount
endloop
endif
// Pause timer if not needed
if goPickButFullCount <= 0 and (not SPLIT_STACK or splitStackCount <= 0) then
// If all timed events have been resolved, pause the timer
call PauseTimer( t )
endif
set u = null
set item1 = null
set p = null
set snd = null
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : CancelController
// EVENTS : Unit Targets Point
// Flushes trigger-unit and target-item from timer queue.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function CancelController takes nothing returns boolean
local integer index = 0
if goPickButFullCount > 0 then
loop
if goPickButFullUnits[index] == GetTriggerUnit() and (GetOrderPointX() != GetItemX(goPickButFullItems[index]) or GetOrderPointY() != GetItemY(goPickButFullItems[index])) then
set goPickButFullCount = goPickButFullCount - 1
if goPickButFullCount > 0 then
set goPickButFullUnits[index] = goPickButFullUnits[goPickButFullCount]
set goPickButFullItems[index] = goPickButFullItems[goPickButFullCount]
set index = index - 1
elseif not SPLIT_STACK or splitStackCount <= 0 then
call PauseTimer( t )
endif
endif
set index = index + 1
exitwhen index >= goPickButFullCount
endloop
endif
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : ActionController
// EVENTS : Unit Acquires Item, Unit Targets Object
// Main system controller. Determines unit order and runs actions accordingly.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function ActionController takes nothing returns boolean
local eventid eventId = GetTriggerEventId()
local unit u = GetTriggerUnit()
local integer inventorySize = UnitInventorySize(u)
local player p
local integer orderId
local item item1 // Item being manipulated
local integer item1TypeId
local integer item1Charges
local integer item1Level
local item item2 // Either target or newly created item
local integer item2Charges
local integer item2Level
local integer item2Slot
local integer index
local integer splitChargeCount
local location pos
local boolean full
local real unitAngle
local string str
local sound snd
// Only units with not-null inventory are relevant
if (inventorySize == 0) then
return false
endif
// Detect if triggering event is "unit acquires an item" or "unit is issued an order targeting item"
if (eventId == EVENT_PLAYER_UNIT_PICKUP_ITEM) then
// Unit acquired an item
set item1 = GetManipulatedItem()
if (item1 != null) then
// Could it be a dummy item (allow buying items with full inventory)
if ( BlzGetItemBooleanField(item1, ITEM_BF_USE_AUTOMATICALLY_WHEN_ACQUIRED) == true) then
// Compare to the dummy item list
set index = 0
loop
exitwhen (DUMMY_ITEM_TYPES[index] == null or REAL_ITEM_TYPES[index] == null)
if (GetItemTypeId(item1) == DUMMY_ITEM_TYPES[index] ) then
// Dummy item found > replace with the real one
call RemoveItem(item1)
set pos = GetUnitLoc(u)
set item1 = CreateItemLoc( REAL_ITEM_TYPES[index], pos )
call RemoveLocation(pos)
exitwhen true
endif
set index = index + 1
endloop
endif
if ( BlzGetItemBooleanField(item1, ITEM_BF_USE_AUTOMATICALLY_WHEN_ACQUIRED) == true and GetItemCharges(item1) == 1 ) then
// Nothing to add in inventory, all charges will be used on acquisition
else
// The item is being acquired so we stack it
if UnitStackItem(u, item1) then
// Couldnot stack all charges in inventory, some remain on the floor. Play the "Item Drop" sound
set p = GetOwningPlayer( u )
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "HeroDropItem1.wav" )
endif
endif
endif
elseif (eventId == EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER) then
// Unit is issued an order targeting an object: attack, attack once, move to, right click, moveslot<1-6>
set item1 = GetOrderTargetItem()
if (item1 != null) then
if ( BlzGetItemBooleanField(item1, ITEM_BF_USE_AUTOMATICALLY_WHEN_ACQUIRED) == true and GetItemCharges(item1) == 1 ) then
// Nothing to add in inventory, all charges will be used on acquisition
else
set orderId = GetIssuedOrderId()
if (orderId == 851971) then
// The item is on the floor and left clicked (going to pick it)
if UnitInventoryFull(u) then
// The item is being targeted with a full inventory so we add it to the timer queue
set item1Charges = GetItemCharges( item1 )
set index = 0
if ( item1Charges > 0 ) then
// Item with charges, look up if there is an item available to receive those charges in unit inventory
set item1Level = GetItemLevel( item1 )
set item1TypeId = GetItemTypeId( item1 )
set index = 0
loop
set item2 = UnitItemInSlot( u, index )
set item2Level = GetItemLevel( item2 )
if item2 != item1 and GetItemTypeId(item2) == item1TypeId and (not USE_ITEM_LEVEL or item2Level == 0 or GetItemCharges(item2) < item2Level) then
// Found item with same type
set index = inventorySize + 1
else
set index = index + 1
endif
exitwhen index >= inventorySize
endloop
endif
// Is it possible to pick some charges or not ?
if index > inventorySize then
// Inventory has room to receive the charges
set index = 0
if goPickButFullCount > 0 then
// Check if unit is already moving to pick other charges
loop
if goPickButFullUnits[index] == u then
set goPickButFullItems[index] = item1 // Update the parameters
set index = -1
else
set index = index + 1
endif
exitwhen index >= goPickButFullCount or index == -1
endloop
endif
if index >= 0 then
// No previous go-pick-but-full action, just check if the timer should be started and append this action
if goPickButFullCount == 0 then
call TimerStart( t, 0.05, true, function TimerController )
endif
set goPickButFullUnits[goPickButFullCount] = u
set goPickButFullItems[goPickButFullCount] = item1
set goPickButFullCount = goPickButFullCount + 1
endif
// Order the unit to move to the item position
call IssuePointOrder( u, "move", GetItemX(item1), GetItemY(item1) )
else
// Full inventory error
call IssueImmediateOrder( u, "stop" )
set p = GetOwningPlayer( u )
// Play error sound
if ERROR_SOUND != null and ERROR_SOUND != "" then
set str = ERROR_SOUND
set snd = CreateSound( str, false, false, false, 12700, 12700, "" )
call SetSoundVolume( snd, 127 )
if GetLocalPlayer() != p then
call StartSound( snd )
endif
call KillSoundWhenDone( snd )
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetOwningPlayer(udg_EasyItem_unit),0.50,-1.00,2.00,"|cffffcc00"+ERROR_MESSAGE+"|r")
endif
endif
else
// The item will be picked normally when the unit reaches it (a unit acquire item event will be fired by W3)
endif
elseif (orderId > 852001 and orderId < 852008) then
// The unit is issued a moveslot<1-6> order: an item is being moved to another inventory slot
if UnitHasItem(u, item1) then
// Safety check: item comes from the unit inventory
set item1Charges = GetItemCharges( item1 )
if (item1Charges > 0) then
// The moved item has charges
set item2Slot = orderId - 852002 // target slot index (0 to 5)
set item2 = UnitItemInSlot( u, item2Slot )
if GetItemTypeId(item2) == GetItemTypeId(item1) then
// The moved item and target item have the same type or are identical
if item2 == item1 then
// The item is moved on itself - split charges
if SPLIT then
// Split by double right-click is enabled in settings
set full = UnitInventoryFull( u )
if item1Charges > 1 and (SPLIT_DROP or not full) then
// Split is possible (there is room in inventory or drop is enabled in settings)
if SPLIT_SIZE > 0 then
// Split is set to a fixed size in settings
if SPLIT_SIZE >= item1Charges then
// Not enough charges: splitting total quantity minus 1
set splitChargeCount = item1Charges - 1
else
// Enough charges for full-split
set splitChargeCount = SPLIT_SIZE
endif
else
// Splits in half (bottom-rounded)
set splitChargeCount = item1Charges / 2
endif
call SetItemCharges( item1, item1Charges - splitChargeCount )
call FireStackChangedEvent(u, item1)
if SPLIT_STACK then
// Splitted charged stacked on other items is enabled in settings
set item2 = null
if splitStackCount > 0 then
// Cancel timer is on
set index = 0
loop
if u == splitStackUnits[index] then
// This unit already is in the splitstack/cancel timer input
set item2 = splitStackItem2s[index]
set item2Charges = GetItemCharges( item2 )
set item1Charges = GetItemLevel( item2 )
exitwhen true
endif
set index = index + 1
exitwhen index >= splitStackCount
endloop
endif
endif
if SPLIT_STACK and item2 != null and item2 != item1 and splitStackItem1s[index] == item1 and (not USE_ITEM_LEVEL or item1Charges == 0 or item2Charges < item1Charges) and UnitHasItem(u, item2) and GetItemTypeId(item2) == GetItemTypeId(item1) then
// Merge this split-stack with the other entry in the splitstack/cancel timer input
call SetItemCharges( item2, item2Charges + splitChargeCount )
call FireStackChangedEvent(u, item2)
set splitStackDelays[index] = SPLIT_STACK_DELAY
else
// Create a new item with the splitted charges
set unitAngle = GetUnitFacing( u )
set item2 = CreateItem( GetItemTypeId(item1), GetUnitX(u) + 100 * Cos(unitAngle * bj_DEGTORAD), GetUnitY(u) + 100 * Sin(unitAngle * bj_DEGTORAD) )
call SetItemCharges( item2, splitChargeCount )
if not full then
// There is room, give the new item to the unit
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, item2 )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
if SPLIT_STACK then
// Splitted charged stacked on other items is enabled in settings
set index = 0
if splitStackCount > 0 then
// Cancel timer is on
loop
if splitStackUnits[index] == u then
// This unit already is in the splitstack/cancel timer input - update the previous parameters
set splitStackItem1s[index] = item1
set splitStackItem2s[index] = item2
set splitStackDelays[index] = SPLIT_STACK_DELAY
set index = -1
else
set index = index + 1
endif
exitwhen index >= splitStackCount or index == -1
endloop
endif
if index >= 0 then
// This unit is not already in the cancel timer input
if splitStackCount == 0 then
// If not started, start the timer
call TimerStart( t, 0.05, true, function TimerController )
endif
// Push back this unit to the splitstack/cancel timer input
set splitStackUnits[splitStackCount] = u
set splitStackItem1s[splitStackCount] = item1
set splitStackItem2s[splitStackCount] = item2
set splitStackDelays[splitStackCount] = SPLIT_STACK_DELAY
set splitStackCount = splitStackCount + 1
endif
endif
else
// There is no room for the new item, leave it on the floor and play the "Item Drop" sound
set p = GetOwningPlayer( u )
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "HeroDropItem1" )
endif
endif
endif
endif
else
// The item is moved on another item of same type - stack them
set item1Level = GetItemLevel( item1 )
set item2Charges = GetItemCharges( item2 )
if USE_ITEM_LEVEL and item1Level > 0 and item2Charges + item1Charges > item1Level then
// Total charges of destination item is limited and that limit is exceeded
if item1Charges < GetItemLevel(item2) and item2Charges < GetItemLevel(item2) then
// Safety check: both items had less than max charge. Stack a max of charges in the destination item, leave the rest in the source item
call SetItemCharges( item2, item2Charges + item1Charges - item1Level )
call FireStackChangedEvent(u, item2)
call SetItemCharges( item1, item1Level )
call FireStackChangedEvent(u, item1)
endif
else
// All the charges can be stacked, source item disapears
call SetItemCharges( item2, item2Charges + item1Charges )
call FireStackChangedEvent(u, item2)
call RemoveItem( item1 )
endif
endif
endif
endif
endif
else
// Other irrelevant orders targeting an item (attack, ...)
endif
endif
endif
else
// OTHER TYPE OF TRIGGERING EVENT - SHOULD NEVER HAPPEN
endif
set u = null
set p = null
set item1 = null
set item2 = null
set snd = null
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : PreloadController
// EVENTS : Game Time Elapsed = 0.00
// Preloads sound files so that they play the first time around.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function PreloadController takes nothing returns boolean
local string array str
local sound snd
local integer x = 0
set str[0] = "Sound\\Interface\\PickUpItem.wav"
set str[1] = "Sound\\Interface\\HeroDropItem1.wav"
if ERROR_SOUND != null and ERROR_SOUND != "" then
set str[2] = ERROR_SOUND
endif
loop
exitwhen str[x] == null
set snd = CreateSound( str[x], false, false, false, 12700, 12700, "" )
call SetSoundVolume( snd, 0 )
call StartSound( snd )
call KillSoundWhenDone( snd )
set x = x + 1
endloop
set snd = null
call DestroyTrigger( GetTriggeringTrigger() )
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// TRIGGER INITIALIZER
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function onInit takes nothing returns nothing
local trigger CancelTrigger = CreateTrigger()
local trigger PreloadTrigger = CreateTrigger()
local integer index = 0
call InitDummyItemPairs()
set gg_trg_EasyItemStacknSplit = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent( gg_trg_EasyItemStacknSplit, Player(index), EVENT_PLAYER_UNIT_PICKUP_ITEM, null )
call TriggerRegisterPlayerUnitEvent( gg_trg_EasyItemStacknSplit, Player(index), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null )
call TriggerRegisterPlayerUnitEvent( CancelTrigger, Player(index), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null )
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerRegisterTimerEvent( PreloadTrigger, 0.00, false )
call TriggerAddCondition( gg_trg_EasyItemStacknSplit, function ActionController )
call TriggerAddCondition( CancelTrigger, function CancelController )
call TriggerAddCondition( PreloadTrigger, function PreloadController )
//call TriggerDebugAutomation_TriggerIsReady(CancelTrigger, "CancelTrigger")
//call TriggerDebugAutomation_TriggerIsReady(PreloadTrigger, "PreloadTrigger")
endfunction
endlibrary
function RegisterBossUnit takes unit bossUnit returns nothing
call GroupAddUnit(udg_BossUnits, bossUnit)
call EnableTrigger(gg_trg_BossUnregister)
call EnableTrigger(gg_trg_BossRearFlankAttack)
endfunction
function GetAttackAngle takes unit attackerUnit, unit targetUnit returns real
local location attackerLocation = GetUnitLoc(attackerUnit)
local location targetLocation = GetUnitLoc(targetUnit)
local real targetToAttackerAngle = AngleBetweenPoints(targetLocation, attackerLocation)
local real targetFacingAngle = GetUnitFacing(targetUnit)
call RemoveLocation(attackerLocation)
call RemoveLocation(targetLocation)
return (targetFacingAngle - targetToAttackerAngle)
endfunction
function IsFrontAttacking takes unit attackerUnit, unit targetUnit returns boolean
local real attackAngle = GetAttackAngle(attackerUnit, targetUnit)
if ( CosBJ(attackAngle) >= CosBJ(45.0) ) then
return true
endif
return false
endfunction
function IsRearAttacking takes unit attackerUnit, unit targetUnit returns boolean
local real attackAngle = GetAttackAngle(attackerUnit, targetUnit)
if ( CosBJ(attackAngle) <= -CosBJ(45.0) ) then
return true
endif
return false
endfunction
function IsFlankAttacking takes unit attackerUnit, unit targetUnit returns boolean
local real attackAngle = GetAttackAngle(attackerUnit, targetUnit)
// Right
if ( SinBJ(attackAngle) < -SinBJ(45.0) ) then
return true
endif
// Left
if ( SinBJ(attackAngle) > SinBJ(45.0) ) then
return true
endif
return false
endfunction
:+++++++`
..........ymmmmmmm-...............
.NNNNNNNNNN:```````mNNNNNNNNNNNNNNh
+dddddddddh----------` .--------------/ddddddd+
oooooooooooooooooooo+ .oooooooooooooooooooo:
.--hddddddddd/ /ddddddddddddo--`
sNN`````````` ````````````+NN.
sMM` +MM.
-++ss/ sso++`
NMy -:- -:- `MMs
NMy hMm`` ``mMh `MMs
NMy hMMmm+ +mmMMh `MMs
NMy hMMMM+ +MMMMh `MMs
NMy hMMMMy// //yMMMMh `MMs
NMy hMMMMMMM` `MMMMMMMh `MMs
NMy hMMMMMMM` `MMMMMMMh `MMs
NMy hMMMMMMM` `MMMMMMMh `MMs
NMy hMMMMMMM+/: `MMMMMMMh -//yy/
NMy ymmMMMMMMMy .......................` `MMMMMMMh yMN
NMy ``-MMMMMMMy mNNNNNNNNNNNNNNNNNNNNNNo `MMMMMMMh yMN
-:+hh- .MMMMMMMNhhhhhhhhhhMMMMMMMMMMMMMMMMMMMMMMMmhhhhhhhhhdMMMMMMMh yMN
/MM: .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMys+ yMN
/MM: .ddNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNdd. yMN
/MM: ``sMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMs`` yMN
/MM: .----oMMMMMMMs----+MMMMMMMMMMMMMMM+----sMMMMMMMMMN--. yMN
.oooo+ .oooosMMo .oomMMMMMMMMMmoo. oMMsooooooo .ooooo
hMm .MMs-- hMMMMMMMMMh --sMM. :MM/
hNd`` .NNNMM.`` hMMMMMMMMMh ``.MMNNN. ``:NN/
.-:dd/ --yMMmds hMMMMMMMMMh sdmMMy-- hdy--`
.MM+ -++++ossmMMMMMMMMMmssmMN++- mMh
.MM+ :MMMMMMMMMMMMMMMmhh .::yhs
.NNo`` :MMMMMMMMMMMMMMM: ``oNN.
..omm` :MMMMMMMMMMMMMMM: `mmo..
sMM` .//dMMMMMMMMMMMM: `MMs
/hh/:- hMMhhhhhMMMMM: -:/hh/
mmy.. hMN NMMMM: ..ymm
`./mm- hMN NMMMM: -mm/.`
.//sys hMN NMd//` :MM/
hMm hMN/////NMh //+yy-
ymd..... ymNMMMMMNmy `..dmy
``.NNNNN` ``.MMMMM.`` +NN.``
:::::hho ::::: ohhhho::
oso++++/ .++ossss:
:mmmmd......./mm:
`NNNNNNNy
-------.
`-------` `----. `-- `--` ----- --` `-------` .---------` `----- `-------`
/MMMNMMM+ ``/NNMMm sMM``/MM: .MMMNN` `.MMo`` :MMMNMMMo mMMMMMMMMMs `:NNMMN +MMMNMMM/
/MM/.:MM+ dms..dMm sMMmmmMM: .MMs.. smmMMNmm` :MM+.-MMo mMMMMMMMMMs hmy..hMN +MM:./MM/
/MMysyMM+ NMy hMm sMMMMMMM: .MMdss` hMN++hMM` :MMhssMMo mMMMMMMMMMs mMh yMN +MMysyMM/
/MMdhdMM+ NMy hMm sMMMMMMM: .MMmhh` hMN::yMM` :MMmhdMMo mMNhhNMMMMs mMh yMN +MMdhdMM/
/MM- -MM+ NMy dMm sMMMMMMM: .MMo hMMMMMMM` :MM: `MMo mMh yMMMMs mMd yMN +MM. -MM/
/MMNNNMM+ NMMNNMMm sMM.`/MM: .MMNNN` hMN``sMM` :MM: `MMo mMh yMMMMs mMMNNMMN +MM. -MM/
.///////. //////// -// .//` `///// :// -//` .//. //- //: :////- //////// .//` `//.
Import Bone Armor in your map!
Step 1 - Allow creation of unknown variables - (Understand that this is absolutely nessesary)
1A - Under Preferences, make sure you have "Automatically create unknown variables while pasting trigger data" checked
Step 2 - Install Bribe's Damage Engine into your map:
2A - Copy Pasta Bribe's Damage Engine Folder into your trigger editor
Step 3 - Install Bone Armor
4A Copy Pasta the Bone Armor folder into your trigger editor
4B Copy the Bone Armor Ability from Object Editor, and set it to the variable BAmr_SPELL
4C Copy the Bone Armor Buff from Object Editor, and set it to the variable BArmr_BUFF
function castBoneArmorOnAllies takes nothing returns nothing
local unit sourceUnit = GetTriggerUnit()
local unit targetUnit = GetEnumUnit()
local unit dummyUnit
local player sourcePlayer = GetOwningPlayer(sourceUnit)
local location targetLocation
if ( IsUnitAlly(targetUnit, sourcePlayer) == true ) then
set targetLocation = GetUnitLoc(targetUnit)
call CreateNUnitsAtLoc(1, 'n012', sourcePlayer, targetLocation, bj_UNIT_FACING)
set dummyUnit = GetLastCreatedUnit()
call ModifyHeroStat( bj_HEROSTAT_STR, dummyUnit, bj_MODIFYMETHOD_SET, GetHeroStatBJ(bj_HEROSTAT_STR, sourceUnit, true) )
call ModifyHeroStat( bj_HEROSTAT_AGI, dummyUnit, bj_MODIFYMETHOD_SET, GetHeroStatBJ(bj_HEROSTAT_AGI, sourceUnit, true) )
call ModifyHeroStat( bj_HEROSTAT_INT, dummyUnit, bj_MODIFYMETHOD_SET, GetHeroStatBJ(bj_HEROSTAT_INT, sourceUnit, true) )
call UnitAddAbilityBJ( 'A04Z', dummyUnit )
call IssueTargetOrderBJ( dummyUnit, "innerfire", targetUnit )
call RemoveUnit(dummyUnit)
call RemoveLocation(targetLocation)
endif
endfunction
function Trig_BoneArmorAOE_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A00B' ) ) then
return false
endif
return true
endfunction
function Trig_BoneArmorAOE_Actions takes nothing returns nothing
local unit sourceUnit = GetTriggerUnit()
local location sourceLocation = GetUnitLoc(sourceUnit)
local group unitsInRange = GetUnitsInRangeOfLocAll(500.00, sourceLocation)
call ForGroupBJ( unitsInRange, function castBoneArmorOnAllies )
call DestroyGroup(unitsInRange)
endfunction
//===========================================================================
function InitTrig_BoneArmorAOE_JASS takes nothing returns nothing
set gg_trg_BoneArmorAOE_JASS = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_BoneArmorAOE_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_BoneArmorAOE_JASS, Condition( function Trig_BoneArmorAOE_Conditions ) )
call TriggerAddAction( gg_trg_BoneArmorAOE_JASS, function Trig_BoneArmorAOE_Actions )
endfunction
function onBlzEndUnitAbilityCooldown takes unit whichUnit, integer abilCode returns nothing
local integer playerIndex = GetConvertedPlayerId(GetOwningPlayer(whichUnit))
local integer loopIndex = 0
if ( (IsTriggerEnabled(gg_trg_DualHeroChange) == true) and (playerIndex <=8) and (whichUnit == udg_LightHeroes[playerIndex] ) and (udg_LightHeroes[playerIndex+8] != null) ) then
// Only reset cooldown of ability for 2nd hero if it is an item ability
loop
if ( abilCode == udg_ItemAbilities[loopIndex] ) then
call BlzEndUnitAbilityCooldown(udg_LightHeroes[playerIndex+8], abilCode)
exitwhen true
endif
exitwhen loopIndex > udg_ItemAbilityCount
endloop
endif
endfunction
hook BlzEndUnitAbilityCooldown onBlzEndUnitAbilityCooldown
function onBlzSetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level, real cooldown returns nothing
local integer playerIndex = GetConvertedPlayerId(GetOwningPlayer(whichUnit))
local integer loopIndex = 0
if ( (IsTriggerEnabled(gg_trg_DualHeroChange) == true) and (playerIndex <=8) and (whichUnit == udg_LightHeroes[playerIndex] ) and (udg_LightHeroes[playerIndex+8] != null) ) then
// Only modify cooldown of ability for 2nd hero if it is an item ability
loop
if ( abilId == udg_ItemAbilities[loopIndex] ) then
call BlzSetUnitAbilityCooldown(udg_LightHeroes[playerIndex+8], abilId, level, cooldown)
exitwhen true
endif
exitwhen loopIndex > udg_ItemAbilityCount
endloop
endif
endfunction
hook BlzSetUnitAbilityCooldown onBlzSetUnitAbilityCooldown
function onUnitResetCooldown takes unit whichUnit returns nothing
local integer playerIndex = GetConvertedPlayerId(GetOwningPlayer(whichUnit))
if ( (IsTriggerEnabled(gg_trg_DualHeroChange) == true) and (playerIndex <=8) and (whichUnit == udg_LightHeroes[playerIndex] ) and (udg_LightHeroes[playerIndex+8] != null) ) then
// Also reset all cooldowns of 2nd hero
call UnitResetCooldown(udg_LightHeroes[playerIndex+8])
endif
endfunction
hook UnitResetCooldown onUnitResetCooldown
function Trig_FanOfKnives_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AEfk' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AEfk', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Ewar' ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
return true
endfunction
function Trig_FanOfKnives_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
call TriggerSleepAction( 1.00 )
call SetPlayerAbilityAvailableBJ( false, 'AEfk', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A075', casterPlayer )
call IssueImmediateOrderBJ( casterUnit, "fanofknives" )
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A075', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AEfk', casterPlayer )
endfunction
//===========================================================================
function InitTrig_FanOfKnives_JASS takes nothing returns nothing
set gg_trg_FanOfKnives_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_FanOfKnives_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_FanOfKnives_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_FanOfKnives_JASS, Condition( function Trig_FanOfKnives_Conditions ) )
call TriggerAddAction( gg_trg_FanOfKnives_JASS, function Trig_FanOfKnives_Actions )
endfunction
function Trig_Hex_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A03F' ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Oshd' ) ) then
return false
endif
if ( not ( GetHeroLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
if ( not ( IsUnitPausedBJ(GetSpellTargetUnit()) == false ) ) then
return false
endif
return true
endfunction
function Trig_Hex_Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
local location targetLoc = GetUnitLoc(target)
local location tempLoc
local player sourcePlayer = GetOwningPlayer(GetTriggerUnit())
local integer index = 1
loop
exitwhen index > 6
call TriggerSleepAction( 0.10 )
set tempLoc = PolarProjectionBJ(targetLoc, 200.00, ( 60.00 * I2R(index) ))
call CreateNUnitsAtLocFacingLocBJ( 1, 'o000', sourcePlayer, tempLoc, targetLoc )
call RemoveLocation(tempLoc)
call UnitApplyTimedLifeBJ( 8.00, 'Bhwd', GetLastCreatedUnit() )
set index = index + 1
endloop
call RemoveLocation(targetLoc)
set sourcePlayer = null
set tempLoc = null
set targetLoc = null
set target = null
endfunction
//===========================================================================
function InitTrig_Hex_JASS takes nothing returns nothing
set gg_trg_Hex_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_Hex_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Hex_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Hex_JASS, Condition( function Trig_Hex_Conditions ) )
call TriggerAddAction( gg_trg_Hex_JASS, function Trig_Hex_Actions )
endfunction
function Trig_Polymorph_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A023' ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Ewar' ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
return true
endfunction
function Trig_Polymorph_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
local unit targetUnit = GetSpellTargetUnit()
local location targetLoc = GetUnitLoc(targetUnit)
local location tempLoc
local integer index = 1
local integer indexEnd = 6
call TriggerSleepAction( 0.10 )
call PauseUnitBJ( true, targetUnit )
call DisableTrigger( GetTriggeringTrigger() )
call DisableTrigger( gg_trg_ShadowStrike_JASS )
loop
exitwhen index > indexEnd
call AddSpellEffectTargetById('AEbl', EFFECT_TYPE_AREA_EFFECT, casterUnit, "origin")
set tempLoc = PolarProjectionBJ(targetLoc, 350.00, ( 60.00 * I2R(index) ))
call SetUnitPositionLocFacingLocBJ( casterUnit, tempLoc, targetLoc )
call RemoveLocation(tempLoc)
call SetPlayerAbilityAvailableBJ( false, 'AEsh', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A078', casterPlayer )
call IssueTargetOrderBJ( casterUnit, "shadowstrike", targetUnit )
call TriggerSleepAction( 1.0 )
call SetPlayerAbilityAvailableBJ( false, 'A078', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AEsh', casterPlayer )
set index = index + 1
endloop
call RemoveLocation(targetLoc)
call EnableTrigger( gg_trg_ShadowStrike_JASS )
call EnableTrigger( GetTriggeringTrigger() )
call PauseUnitBJ( false, targetUnit )
set tempLoc = null
set targetLoc = null
set targetUnit = null
set casterPlayer = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_Polymorph_JASS takes nothing returns nothing
set gg_trg_Polymorph_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_Polymorph_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Polymorph_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Polymorph_JASS, Condition( function Trig_Polymorph_Conditions ) )
call TriggerAddAction( gg_trg_Polymorph_JASS, function Trig_Polymorph_Actions )
endfunction
function ConvertPolarCoordToLocation takes location tL,real TL,real uL returns location
return Location(GetLocationX(tL)+TL*Cos(uL*bj_DEGTORAD),GetLocationY(tL)+TL*Sin(uL*bj_DEGTORAD))
endfunction
function RealmOfSoulPeriodic_Actions takes nothing returns nothing
local trigger realmOfSoulPeriodicTrigger = GetTriggeringTrigger()
local unit dummyUnit = LoadUnitHandle(udg_RosHashtable,GetHandleId(realmOfSoulPeriodicTrigger),StringHashBJ("DummyUnit"))
local location dummyUnitLocation = GetUnitLoc(dummyUnit)
local location targetLocation = ConvertPolarCoordToLocation(dummyUnitLocation,100.,GetRandomReal(0,360))
call DebugLog(LVL_DEBUG, "RealmOfSoulPeriodic_Actions")
call IssuePointOrderLocBJ( dummyUnit, "carrionswarm", targetLocation )
call RemoveLocation(dummyUnitLocation)
call RemoveLocation(targetLocation)
set targetLocation = null
set dummyUnitLocation = null
set dummyUnit = null
set realmOfSoulPeriodicTrigger = null
endfunction
function Trig_RealmOfSoul_Conditions takes nothing returns boolean
return( GetSpellAbilityId()=='A04X' )
endfunction
function Trig_RealmOfSoul_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local real spellDuration = (5.+(I2R(GetUnitAbilityLevelSwapped('A04X', casterUnit))*5.))
local unit dummyUnit
local integer dummyUnitId
local location casterUnitLocation = GetUnitLoc(casterUnit)
local trigger realmOfSoulPeriodicTrigger = CreateTrigger()
call DebugLog(LVL_DEBUG, "RealOfSoul_Actions")
// Create a dummy unit
call CreateNUnitsAtLoc( 1, 'n010', GetOwningPlayer(casterUnit), casterUnitLocation, bj_UNIT_FACING )
set dummyUnit = bj_lastCreatedUnit
set dummyUnitId = GetHandleId(dummyUnit)
call SetUnitAbilityLevelSwapped( 'A04Y', dummyUnit, GetUnitAbilityLevelSwapped('A04X', casterUnit) )
// Save the data required for the periodic and end triggers
call SaveUnitHandle(udg_RosHashtable,GetHandleId(dummyUnit),StringHashBJ("CasterUnit"),casterUnit) // Caster unit
call SaveUnitHandle(udg_RosHashtable,GetHandleId(realmOfSoulPeriodicTrigger),StringHashBJ("DummyUnit"),dummyUnit) // Dummy unit
// Execute the periodic trigger
call TriggerRegisterTimerEvent(realmOfSoulPeriodicTrigger,0.2,true)
call TriggerAddCondition(realmOfSoulPeriodicTrigger,Condition(function RealmOfSoulPeriodic_Actions))
//call TriggerDebugAutomation_TriggerIsReady(realmOfSoulPeriodicTrigger, "realmOfSoulPeriodicTrigger")
call TriggerEvaluate(realmOfSoulPeriodicTrigger)
// Wait for its end then clean variables
call TriggerSleepAction(spellDuration)
call DisableTrigger(realmOfSoulPeriodicTrigger)
call RemoveSavedHandle(udg_RosHashtable,GetHandleId(dummyUnit),StringHashBJ("CasterUnit"))
call RemoveSavedHandle(udg_RosHashtable,GetHandleId(realmOfSoulPeriodicTrigger),StringHashBJ("DummyUnit"))
call RemoveUnit(dummyUnit)
call DestroyTrigger(realmOfSoulPeriodicTrigger)
call RemoveLocation(casterUnitLocation)
set realmOfSoulPeriodicTrigger = null
set casterUnitLocation = null
set dummyUnit = null
set casterUnit = null
endfunction
function Trig_RealmOfSoulDummyCastFinished_Conditions takes nothing returns boolean
return( GetSpellAbilityId()=='A04Y' )
endfunction
function Trig_RealmOfSoulDummyCastFinished_Actions takes nothing returns nothing
local unit dummyUnit = GetSpellAbilityUnit()
local unit casterUnit = LoadUnitHandle(udg_RosHashtable,GetHandleId(dummyUnit),StringHashBJ("CasterUnit"))
local location casterUnitLocation = GetUnitLoc(casterUnit)
call DebugLog(LVL_DEBUG, "Trig_RealmOfSoulDummyCastFinished_Actions")
call SetUnitPositionLoc(dummyUnit,casterUnitLocation)
call RemoveLocation(casterUnitLocation)
set casterUnitLocation = null
set casterUnit = null
set dummyUnit = null
endfunction
//===========================================================================
function InitTrig_RealmOfSoul takes nothing returns nothing
local trigger Trig_RealmOfSoulDummyCastFinished = CreateTrigger()
set gg_trg_RealmOfSoul = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( gg_trg_RealmOfSoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_RealmOfSoul, Condition(function Trig_RealmOfSoul_Conditions) )
call TriggerAddAction( gg_trg_RealmOfSoul, function Trig_RealmOfSoul_Actions )
call TriggerRegisterAnyUnitEventBJ( Trig_RealmOfSoulDummyCastFinished ,EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( Trig_RealmOfSoulDummyCastFinished, Condition(function Trig_RealmOfSoulDummyCastFinished_Conditions))
call TriggerAddAction( Trig_RealmOfSoulDummyCastFinished, function Trig_RealmOfSoulDummyCastFinished_Actions )
//call TriggerDebugAutomation_TriggerIsReady(Trig_RealmOfSoulDummyCastFinished, "Trig_RealmOfSoulDummyCastFinished")
endfunction
function Trig_ShadowStrike_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AEsh' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AEsh', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Ewar' ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
return true
endfunction
function Trig_ShadowStrike_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local unit targetUnit = GetSpellTargetUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'AEsh', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A078', casterPlayer )
call IssueTargetOrderBJ( casterUnit, "shadowstrike", targetUnit )
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A078', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AEsh', casterPlayer )
set casterPlayer = null
set targetUnit = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_ShadowStrike_JASS takes nothing returns nothing
set gg_trg_ShadowStrike_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_ShadowStrike_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ShadowStrike_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_ShadowStrike_JASS, Condition( function Trig_ShadowStrike_Conditions ) )
call TriggerAddAction( gg_trg_ShadowStrike_JASS, function Trig_ShadowStrike_Actions )
endfunction
function Trig_ShockWave_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AOsh' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AOsh', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not ( (GetUnitTypeId(GetTriggerUnit()) == 'Otch') or (GetUnitTypeId(GetTriggerUnit()) == 'O008') ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
if ( not ( UnitHasBuffBJ(GetTriggerUnit(), 'B00N') == true ) ) then
return false
endif
return true
endfunction
function Trig_ShockWave_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
local unit targetUnit = GetSpellTargetUnit()
local location targetLocation = GetSpellTargetLoc()
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'AOsh', GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerAbilityAvailableBJ( true, 'A04Q', GetOwningPlayer(GetTriggerUnit()) )
if ( targetUnit != null ) then
call IssueTargetOrderBJ( casterUnit, "carrionswarm", targetUnit)
elseif ( targetLocation != null ) then
call IssuePointOrderLocBJ( casterUnit, "carrionswarm", targetLocation)
endif
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A04Q', GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerAbilityAvailableBJ( true, 'AOsh', GetOwningPlayer(GetTriggerUnit()) )
set targetLocation = null
set targetUnit = null
set casterPlayer = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_ShockWave_JASS takes nothing returns nothing
set gg_trg_ShockWave_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_ShockWave_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ShockWave_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_ShockWave_JASS, Condition( function Trig_ShockWave_Conditions ) )
call TriggerAddAction( gg_trg_ShockWave_JASS, function Trig_ShockWave_Actions )
endfunction
function Trig_StormBolt_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AHtb' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AHtb', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Hmkg' ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
return true
endfunction
function Trig_StormBolt_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local unit targetUnit = GetSpellTargetUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'AHtb', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A02V', casterPlayer )
call IssueTargetOrderBJ( casterUnit, "creepthunderbolt", targetUnit )
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A02V', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AHtb', casterPlayer )
set casterPlayer = null
set targetUnit = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_StormBolt_JASS takes nothing returns nothing
set gg_trg_StormBolt_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_StormBolt_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_StormBolt_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_StormBolt_JASS, Condition( function Trig_StormBolt_Conditions ) )
call TriggerAddAction( gg_trg_StormBolt_JASS, function Trig_StormBolt_Actions )
endfunction
function Trig_ThunderClap_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AHtc' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AHtc', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Hmkg' ) ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
return true
endfunction
function Trig_ThunderClap_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'AHtc', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A04P', casterPlayer )
call IssueImmediateOrderBJ( casterUnit, "creepthunderclap" )
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A04P', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AHtc', casterPlayer )
set casterPlayer = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_ThunderClap_JASS takes nothing returns nothing
set gg_trg_ThunderClap_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_ThunderClap_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ThunderClap_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_ThunderClap_JASS, Condition( function Trig_ThunderClap_Conditions ) )
call TriggerAddAction( gg_trg_ThunderClap_JASS, function Trig_ThunderClap_Actions )
endfunction
function Trig_WarStomp_Func009C takes nothing returns boolean
if ( ( GetUnitTypeId(GetTriggerUnit()) == 'Otch' ) ) then
return true
endif
if ( ( GetUnitTypeId(GetTriggerUnit()) == 'O008' ) ) then
return true
endif
return false
endfunction
function Trig_WarStomp_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'AOws' ) ) then
return false
endif
if ( not ( GetUnitAbilityLevelSwapped('AOws', GetTriggerUnit()) == 4 ) ) then
return false
endif
if ( not Trig_WarStomp_Func009C() ) then
return false
endif
if ( not ( GetUnitLevel(GetTriggerUnit()) >= 20 ) ) then
return false
endif
if ( not ( UnitHasBuffBJ(GetTriggerUnit(), 'B00N') == true ) ) then
return false
endif
return true
endfunction
function Trig_WarStomp_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local player casterPlayer = GetOwningPlayer(casterUnit)
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'AOws', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'A01O', casterPlayer )
call IssueImmediateOrderBJ( casterUnit, "creepthunderclap" )
call TriggerSleepAction( 0.10 )
call SetPlayerAbilityAvailableBJ( false, 'A01O', casterPlayer )
call SetPlayerAbilityAvailableBJ( true, 'AOws', casterPlayer )
set casterPlayer = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_WarStomp_JASS takes nothing returns nothing
set gg_trg_WarStomp_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_WarStomp_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_WarStomp_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_WarStomp_JASS, Condition( function Trig_WarStomp_Conditions ) )
call TriggerAddAction( gg_trg_WarStomp_JASS, function Trig_WarStomp_Actions )
endfunction
function Trig_MuradinClap_Conditions takes nothing returns boolean
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Hmbr' ) ) then
return false
endif
if ( not ( GetSpellAbilityId() == 'AHtc' ) ) then
return false
endif
return true
endfunction
function Trig_MuradinClap_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
call PlaySoundOnUnitBJ( gg_snd_MuradinDoubleClap, 100, casterUnit )
call TriggerSleepAction( 0.10 )
call UnitAddAbilityBJ( 'A04P', casterUnit )
call IssueImmediateOrder(casterUnit,"creepthunderclap")
call TriggerSleepAction( 0.50 )
call UnitRemoveAbilityBJ( 'A04P', casterUnit )
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_MuradinClap_JASS takes nothing returns nothing
set gg_trg_MuradinClap_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_MuradinClap_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_MuradinClap_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_MuradinClap_JASS, Condition( function Trig_MuradinClap_Conditions ) )
call TriggerAddAction( gg_trg_MuradinClap_JASS, function Trig_MuradinClap_Actions )
endfunction
function Trig_MuradinBolt_Conditions takes nothing returns boolean
if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'Hmbr' ) ) then
return false
endif
if ( not ( GetSpellAbilityId() == 'AHtb' ) ) then
return false
endif
return true
endfunction
function Trig_MuradinBolt_Actions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local unit targetUnit = GetSpellTargetUnit()
call PlaySoundOnUnitBJ( gg_snd_MuradinDoubleBolt, 100, casterUnit )
call TriggerSleepAction( 0.10 )
call UnitAddAbilityBJ( 'A058', casterUnit )
call IssueTargetOrderBJ(casterUnit,"creepthunderbolt",targetUnit)
call TriggerSleepAction( 0.50 )
call UnitRemoveAbilityBJ( 'A058', casterUnit )
set targetUnit = null
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_MuradinBolt_JASS takes nothing returns nothing
set gg_trg_MuradinBolt_JASS = CreateTrigger( )
call DisableTrigger( gg_trg_MuradinBolt_JASS )
call TriggerRegisterAnyUnitEventBJ( gg_trg_MuradinBolt_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_MuradinBolt_JASS, Condition( function Trig_MuradinBolt_Conditions ) )
call TriggerAddAction( gg_trg_MuradinBolt_JASS, function Trig_MuradinBolt_Actions )
endfunction