Name | Type | is_array | initial_value |
A_ArmorBreakCount | real | Yes | |
A_ArmorBreakDummies | group | Yes | |
A_ArmorBreakGroup | group | Yes | |
A_ArmorBreakMaster | unit | Yes | |
A_ArmorGroupCount | integer | No | |
A_ArmorGroupEnum | unit | No | |
A_AssNightDamaged | group | Yes | |
A_AssNightDummies | group | Yes | |
A_AssNightFX | effect | Yes | |
A_AssNightGroup | group | Yes | |
A_AssNightLoop | integer | Yes | |
A_AssNightToRemove | group | Yes | |
A_AssNightX | real | Yes | |
A_AssNightY | real | Yes | |
A_BattleAuraDummy | unit | Yes | |
A_BerserkFX1 | effect | Yes | |
A_BerserkFX2 | effect | Yes | |
A_BerserkOn | boolean | Yes | |
A_BerserkOverLife | integer | Yes | |
A_BerserkResist | real | Yes | |
A_BerserkResistTaken | real | Yes | |
A_BerserkSteal | real | Yes | |
A_BigShotDummy | unit | Yes | |
A_BigShotFX | effect | Yes | |
A_BigShotGroup | group | Yes | |
A_BigShotMaster | unit | Yes | |
A_ChemRageAngle | real | Yes | |
A_ChemRageBonus | integer | Yes | |
A_ChemRageCount | integer | Yes | |
A_ChemRageFX | effect | Yes | |
A_ChemRageGroup | group | No | |
A_ChemRageRate | real | Yes | |
A_ChemRageTimer | timer | Yes | |
A_CopyCaster | unit | Yes | |
A_CrystalDuration | real | Yes | |
A_CrystalFX | effect | Yes | |
A_CrystalString | string | Yes | |
A_DaggerLevel | integer | Yes | |
A_DaggerMaster | unit | Yes | |
A_DaggerTarget | unit | Yes | |
A_DaTroll | group | No | |
A_DaTrollCount | integer | No | |
A_DaTrollEnum | unit | No | |
A_DemonChargeAngle | real | Yes | |
A_DemonChargeCount | integer | Yes | |
A_DemonChargeCountMax | integer | Yes | |
A_DemonChargeGroup | group | Yes | |
A_DemonChargeX | real | Yes | |
A_DemonChargeY | real | Yes | |
A_DemonQuakeCount | integer | Yes | |
A_DoomSoonFactor | real | Yes | |
A_DrainLning | lightning | Yes | |
A_DrainSourceFX | effect | Yes | |
A_DrainTargetFX | effect | Yes | |
A_DruidTrapCount | integer | No | |
A_DruidTrapDone | boolean | Yes | |
A_DruidTrapDummyGroup | group | Yes | |
A_DruidTrapEnum | unit | No | |
A_DruidTrapFX | effect | Yes | |
A_DruidTrapRadius | real | Yes | |
A_DruidTrapX | real | Yes | |
A_DruidTrapY | real | Yes | |
A_DruidZealArmor | real | Yes | |
A_DruidZealDamage | integer | No | |
A_EarthAngle | real | Yes | |
A_EarthAoe | real | Yes | |
A_EarthSize | real | Yes | |
A_EarthX | real | Yes | |
A_EarthY | real | Yes | |
A_ElemDummy | unit | Yes | |
A_ElemIndex | integer | No | |
A_EnchantBonus | real | Yes | |
A_EnchantCount | integer | No | |
A_EnchantEnum | unit | No | |
A_EnchantFX | effect | Yes | |
A_EnchantGroup | group | No | |
A_EnchantString | string | Yes | |
A_EnchantTimer | timer | Yes | |
A_EnchantToRemove | group | No | |
A_Felhound | group | No | |
A_FelhoundCount | integer | No | |
A_FelhoundEnum | unit | No | |
A_FrostArmorFactor | integer | Yes | |
A_FrostArmorOwner | player | Yes | |
A_FuryEnemyCount | integer | No | |
A_FuryEnemyEnum | unit | No | |
A_FuryEnemyGroup | group | Yes | |
A_FuryX | real | Yes | |
A_FuryY | real | Yes | |
A_GhostyDummy | unit | Yes | |
A_GlaveStackCount | integer | Yes | |
A_GlaveStackDummy | unit | Yes | |
A_GlaveStackGroup | group | No | |
A_GlaveStackTimer | timer | Yes | |
A_GoblinArmorMaster | unit | Yes | |
A_GrowMaster | unit | Yes | |
A_GrowSize | real | Yes | |
A_GrowTrigger | trigger | No | |
A_HolyAlly | group | Yes | |
A_HolyEnemy | group | Yes | |
A_HolyGroupCount | integer | No | |
A_HolyGroupEnum | unit | No | |
A_HolyPowa | real | Yes | |
A_IceBallDummy | unit | Yes | |
A_IceBallGroup | group | Yes | |
A_IceBallTarget | unit | Yes | |
A_IceBallX | real | Yes | |
A_IceBallY | real | Yes | |
A_ImpaleAngle | real | Yes | |
A_ImpaleCount | integer | Yes | |
A_ImpaleFX | effect | Yes | |
A_ImpaleGroup | group | Yes | |
A_ImpaleSize | real | Yes | |
A_ImpaleX | real | Yes | |
A_ImpaleY | real | Yes | |
A_InfernalBoltCount | integer | Yes | |
A_InfernalBoltLevel | integer | Yes | |
A_KnockShotGroup_1 | group | Yes | |
A_KnockShotGroup_2 | group | Yes | |
A_KnockShotGroup_3 | group | Yes | |
A_KnockShotGroup_4 | group | Yes | |
A_KnockShotLevel | real | Yes | |
A_KnockShotMaster | unit | Yes | |
A_KnockShotX | real | Yes | |
A_KnockShotY | real | Yes | |
A_LanceAngle | real | Yes | |
A_LanceCaster | unit | Yes | |
A_LanceCount | integer | Yes | |
A_LanceIsDamaged | group | Yes | |
A_LashCount | integer | Yes | |
A_LashUnit | unit | No | |
A_MageCurseCastOn | boolean | Yes | |
A_MageCurseDoubleOn | boolean | Yes | |
A_MageCurseFX | effect | Yes | |
A_MercTauntBonus | real | No | |
A_MercTauntCount | integer | Yes | |
A_MercTauntString | string | No | |
A_MeteorLevel | integer | Yes | |
A_MeteorMaster | unit | Yes | |
A_MinoJumpAngle | real | Yes | |
A_MinoJumpCount | integer | Yes | |
A_MinoJumpFX | effect | Yes | |
A_MinoJumpRate | real | Yes | |
A_NagaDummy | unit | Yes | |
A_NagaIndex | integer | No | |
A_PietyBonus | integer | Yes | |
A_PsiBlastFX | effect | Yes | |
A_PsiSlamCount | integer | Yes | |
A_PsiSlamX | real | Yes | |
A_PsiSlamY | real | Yes | |
A_PullCount | integer | No | |
A_PullEnum | unit | No | |
A_PullGroup | group | Yes | |
A_PullMaster | unit | Yes | |
A_PullMasterX | real | Yes | |
A_PullMasterY | real | Yes | |
A_PullSpeed | real | Yes | |
A_RuneSilenceFX | effect | Yes | |
A_SacrificeAllies | group | Yes | |
A_SacrificeLife | real | Yes | |
A_SacrificeMaster | unit | Yes | |
A_SatyrHero | unit | No | |
A_SatyrInvisGroup | group | No | |
A_SatyrInvisTimer | timer | Yes | |
A_SeaBeastAngle | real | Yes | |
A_SeaBeastFX | effect | Yes | |
A_SeaBeastGroup | group | Yes | |
A_SeaBeastLife | real | Yes | |
A_SeaBeastX | real | Yes | |
A_SeaBeastY | real | Yes | |
A_SearFrostCount | integer | Yes | |
A_SearFrostDummies | group | Yes | |
A_SearFrostLevel | integer | Yes | |
A_SearingBladeCount | integer | Yes | |
A_Skeletons | group | No | |
A_SlumberCount | integer | Yes | |
A_SlumberUnit | unit | Yes | |
A_SlumberX | real | Yes | |
A_SlumberY | real | Yes | |
A_SmiteAngle | real | Yes | |
A_SmiteEnd | boolean | Yes | |
A_SnareDummy | unit | Yes | |
A_SnareFX | effect | Yes | |
A_SomersaultAngle | real | Yes | |
A_SomersaultCount | integer | Yes | |
A_SomersaultGroup | group | Yes | |
A_SomersaultTargetFacing | real | Yes | |
A_SomersaultX | real | Yes | |
A_SomersaultY | real | Yes | |
A_SpikyCount | integer | No | |
A_SpikyEnum | unit | No | |
A_SpikyGroup | group | Yes | |
A_SpikyLoop | integer | Yes | |
A_SpiritWaveDummy | unit | Yes | |
A_SpiritWaveFX | effect | Yes | |
A_SpiritWaveGroup | group | Yes | |
A_SpiritWaveInt | real | Yes | |
A_SpiritWaveSize | real | Yes | |
A_StrangleDummy | unit | Yes | |
A_TempEnum | unit | No | |
A_TempSize | integer | No | |
A_ThickFX | effect | Yes | |
A_TotemFX | effect | Yes | |
A_TotemGroup | group | Yes | |
A_TotemTarget | unit | Yes | |
A_UltishotAngle | real | Yes | |
A_UltishotCount | integer | Yes | |
A_UltishotLevel | integer | Yes | |
A_UltishotX | real | Yes | |
A_UltishotY | real | Yes | |
A_UnholyGroundX | real | Yes | |
A_UnholyGroundY | real | Yes | |
A_VampBlinkGroup | group | No | |
A_VampBlinkSteal | real | Yes | |
A_VampBlinkTarget | unit | Yes | |
A_VampBlinkTimer | timer | Yes | |
A_VampStunGroup | group | Yes | |
A_VampStunGroupCount | integer | No | |
A_VampStunGroupEnum | unit | No | |
A_VampVomit | boolean | Yes | |
A_VoidShadeCount | integer | Yes | |
A_VoidShadeFX | effect | Yes | |
A_VoidShadeMaster | unit | Yes | |
A_VortexCastTarget | unit | Yes | |
A_VortexCount | integer | No | |
A_VortexDummyCount | integer | No | |
A_VortexDummyEnum | unit | No | |
A_VortexDummyGroup | group | Yes | |
A_VortexDummyTarget | unit | Yes | |
A_VortexEnum | unit | No | |
A_VortexFX | effect | Yes | |
A_VortexGroup | group | Yes | |
A_WingCasterGroup | group | No | |
A_WingCasterGroupCount | integer | No | |
A_WingCasterGroupEnum | unit | No | |
A_WingCasterTimer | timer | Yes | |
A_WingGroup | group | Yes | |
A_WingGroupCount | integer | No | |
A_WingGroupEnum | unit | No | |
A_WingHeal | real | Yes | |
A_WingLevel | real | Yes | |
A_ZapShieldFX | effect | Yes | |
A_ZapShieldOn | boolean | Yes | |
A_ZapShieldPowa | real | Yes | |
AfterDamageEvent | real | 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 | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
CapturePoint_DeRegister | trigger | No | |
CapturePoint_Register | trigger | No | |
CapturePoint_Register_Influ | integer | No | |
CapturePoint_Register_Range | real | No | |
CapturePoint_Register_Style | integer | No | |
CapturePoint_Register_Unit | unit | No | |
CapturePoint_TempGroup | group | No | |
CapturePointAutoDeregister | trigger | No | |
CapturePointBarType | modelfile | No | |
CapturePointDefaultFilter | boolexpr | No | |
CapturePointEvent | real | No | |
CapturePointEventMovedUnit | unit | No | |
CapturePointEventPlayer | player | No | |
CapturePointEventUnit | unit | No | |
CapturePointHash | hashtable | No | |
CapturePoints | group | No | |
CapturePointTeamLeader | player | Yes | |
CapturePointTimer | timer | Yes | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
CItemDisassemble | boolean | No | |
CItemDisassembleSlot | integer | No | |
CItemType | itemcode | Yes | |
CItemUnit | unit | No | |
CleanedItem | item | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CP_TempPoint | unit | No | |
CP_Tower | unit | Yes | |
CP_TowerGroup | group | 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 | |
DamageEventToAdd | real | No | |
DamageEventToSub | real | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterMinAmount | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceB | integer | No | |
DamageFilterSourceT | integer | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetB | integer | No | |
DamageFilterTargetT | integer | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeDHVoid | integer | No | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypeItemBTShield | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DamageTypeSADrain | integer | No | |
DeathEvent | real | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
E_SpeechLine1 | string | Yes | |
E_SpeechLine2 | string | Yes | |
E_SpeechLine3 | string | Yes | |
E_SpeechLine4 | string | Yes | |
E_SpeechLineX | string | Yes | |
E_SpeechWin | string | Yes | |
EnhancedDamageTarget | unit | No | |
FC_FastWin | boolean | No | |
FC_RandomHeroType | unitcode | Yes | |
FC_TowerGold | boolean | No | |
H_AllHeroes | group | No | |
H_AllHeroesCount | integer | No | |
H_AllHeroesEnum | unit | No | |
H_AssistGold | integer | No | |
H_KillForce | force | Yes | |
H_KillGold | integer | No | |
H_KillGoldText | string | No | |
H_KillGroup | group | Yes | |
H_KillGroupCount | integer | No | |
H_KillGroupEnum | unit | No | |
H_RezTimer | timer | Yes | |
H_RezTimerWindow | timerdialog | Yes | |
H_RezX | real | Yes | |
H_RezY | real | Yes | |
H_TeamGold | integer | No | |
H_TeamTag | string | No | |
I_CoinNorth | item | No | |
I_CoinSouth | item | No | |
IA_DragonEyeCount | integer | No | |
IA_DragonEyeEnum | unit | No | |
IA_DragonEyeGroup | group | No | |
IA_FortCount | integer | No | |
IA_FortEnum | unit | No | |
IA_FortGroupNorth | group | No | |
IA_FortGroupSouth | group | No | |
IA_FortLevelNorth | integer | No | |
IA_FortLevelSouth | integer | No | |
IA_GoldSpearFX | effect | Yes | |
IA_TownCasterFX | effect | Yes | |
IA_TownFX | effect | Yes | |
IA_VampireRageOn | boolean | Yes | |
InitTempGroup | group | No | |
InitTempLoc | location | No | |
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 | |
ItemsToClean | integer | No | |
KillerOfUnit | unit | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NPC_CreepFacing | real | Yes | |
NPC_CreepTimer | timer | Yes | |
NPC_CreepTimerLength | real | No | |
NPC_CreepToSpawn | group | No | |
NPC_CreepX | real | Yes | |
NPC_CreepY | real | Yes | |
NPC_Towers | group | No | |
NPC_TowersCount | integer | No | |
NPC_TowersEnum | unit | No | |
P_ColorString | string | Yes | |
P_COP | unit | Yes | |
P_Courier | unit | Yes | |
P_Hero | unit | Yes | |
P_IntroString | string | No | |
P_Kills | integer | Yes | |
P_Multiboard | multiboard | No | |
P_MultiboardIndexForPlayer | integer | Yes | |
P_MultiboardPlayer | player | Yes | |
P_MultiboardRowNorthBegin | integer | No | |
P_MultiboardRowNorthEnd | integer | No | |
P_MultiboardRowNumber | integer | No | |
P_MultiboardRowSouthBegin | integer | No | |
P_MultiboardRowSouthEnd | integer | No | |
P_QuestString | string | No | |
P_Remainers | force | No | |
P_ShopNorth | location | No | |
P_ShopSouth | location | No | |
PhysDamageTypeBASweep | integer | No | |
PhysDamageTypeDHSlash | integer | No | |
PhysDamageTypeGARage | integer | No | |
PhysDamageTypeMTSmite | integer | No | |
PhysDamageTypeNWBall | integer | No | |
PhysDamageTypeNWFork | integer | No | |
PhysDamageTypeSGSpike | integer | No | |
PhysDamageTypeTYShot | integer | No | |
PhysDamageTypeVBAura | integer | No | |
PhysDamageTypeWDDagger | integer | No | |
Preload_Dummy | unit | No | |
Spell__Ability | abilcode | No | |
Spell__AutoAddTargets | boolean | No | |
Spell__BuffAbility | abilcode | No | |
Spell__BuffOrder | ordercode | No | |
Spell__Caster | unit | No | |
Spell__CasterOwner | player | No | |
Spell__CastPoint | location | No | |
Spell__Channeling | boolean | No | |
Spell__Completed | boolean | No | |
Spell__DummyOwner | player | No | |
Spell__DummyType | unitcode | No | |
Spell__Duration | real | No | |
Spell__DurationPerLevel | real | No | |
Spell__Expired | boolean | No | |
Spell__Filter_AllowAlly | boolean | No | |
Spell__Filter_AllowDead | boolean | No | |
Spell__Filter_AllowEnemy | boolean | No | |
Spell__Filter_AllowFlying | boolean | No | |
Spell__Filter_AllowHero | boolean | No | |
Spell__Filter_AllowLiving | boolean | No | |
Spell__Filter_AllowMagicImmune | boolean | No | |
Spell__Filter_AllowMechanical | boolean | No | |
Spell__Filter_AllowNonHero | boolean | No | |
Spell__Filter_AllowStructure | boolean | No | |
Spell__Hash | hashtable | No | |
Spell__Index | integer | No | |
Spell__InRange | real | No | |
Spell__InRangeCount | integer | No | |
Spell__InRangeGroup | group | No | |
Spell__InRangeMax | integer | No | |
Spell__InRangePoint | location | No | |
Spell__InRangeUnit | unit | No | |
Spell__InRangeUnits | unit | Yes | |
Spell__Interval | real | No | |
Spell__Level | integer | No | |
Spell__LevelMultiplier | real | No | |
Spell__Running | boolean | No | |
Spell__StartDuration | boolean | No | |
Spell__Target | unit | No | |
Spell__TargetGroup | group | No | |
Spell__TargetPoint | location | No | |
Spell__Time | real | No | |
Spell__Trigger_InRangeFilter | trigger | No | |
Spell__Trigger_OnCast | trigger | No | |
Spell__Trigger_OnChannel | trigger | No | |
Spell__Trigger_OnEffect | trigger | No | |
Spell__Trigger_OnFinish | trigger | No | |
Spell__Trigger_OnLoop | trigger | No | |
Spell__UseTargetGroup | boolean | No | |
Spell__WakeTargets | boolean | No | |
Spell_i_Abil | abilcode | Yes | |
Spell_i_AllowAlly | boolean | Yes | |
Spell_i_AllowDead | boolean | Yes | |
Spell_i_AllowEnemy | boolean | Yes | |
Spell_i_AllowFlying | boolean | Yes | |
Spell_i_AllowHero | boolean | Yes | |
Spell_i_AllowLiving | boolean | Yes | |
Spell_i_AllowMagicImmune | boolean | Yes | |
Spell_i_AllowMechanical | boolean | Yes | |
Spell_i_AllowNonHero | boolean | Yes | |
Spell_i_AllowStructure | boolean | Yes | |
Spell_i_AutoAddTargets | boolean | Yes | |
Spell_i_BuffAbil | abilcode | Yes | |
Spell_i_BuffOrder | ordercode | Yes | |
Spell_i_Caster | unit | Yes | |
Spell_i_Channeling | boolean | Yes | |
Spell_i_Completed | boolean | Yes | |
Spell_i_Duration | real | Yes | |
Spell_i_EventType | integer | Yes | |
Spell_i_GroupN | integer | No | |
Spell_i_GroupStack | group | Yes | |
Spell_i_Head | integer | Yes | |
Spell_i_InRangeFilter | trigger | Yes | |
Spell_i_Instances | integer | No | |
Spell_i_LastTime | real | Yes | |
Spell_i_Level | integer | Yes | |
Spell_i_Linked | boolean | Yes | |
Spell_i_OnCastStack | trigger | Yes | |
Spell_i_OnChannelStack | trigger | Yes | |
Spell_i_OnEffectStack | trigger | Yes | |
Spell_i_OnFinishStack | trigger | Yes | |
Spell_i_OnLoopStack | trigger | Yes | |
Spell_i_PreloadDummy | unit | No | |
Spell_i_Recycle | integer | No | |
Spell_i_RecycleList | integer | Yes | |
Spell_i_Stack | integer | Yes | |
Spell_i_StackN | integer | No | |
Spell_i_StackRef | integer | Yes | |
Spell_i_Target | unit | Yes | |
Spell_i_TargetGroup | group | Yes | |
Spell_i_TargetX | real | Yes | |
Spell_i_TargetY | real | Yes | |
Spell_i_Time | real | Yes | |
Spell_i_Timer | timer | No | |
Spell_i_UseTG | boolean | Yes | |
SummonerOfUnit | unit | Yes | |
UDex | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexUnits | unit | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
VFX_FountainNorth | effect | No | |
VFX_FountainSouth | effect | No | |
W_NorthCinTimer | timer | No | |
W_NorthControl | integer | No | |
W_NorthFastOn | boolean | No | |
W_NorthFastTimer | timer | No | |
W_NorthFastTimerWindow | timerdialog | No | |
W_NorthTickets | real | No | 0.00 |
W_NorthTicketsMax | real | No | 1000.00 |
W_NorthWinTimer | timer | No | |
W_SouthCinTimer | timer | No | |
W_SouthControl | integer | No | |
W_SouthFastOn | boolean | No | |
W_SouthFastTimer | timer | No | |
W_SouthFastTimerWindow | timerdialog | No | |
W_SouthTickets | real | No | 0.00 |
W_SouthTicketsMax | real | No | 1000.00 |
W_SouthWinTimer | timer | No | |
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 | |
WithinRange__DeRegister | trigger | No | |
WithinRangeEnteringUnit | unit | No | |
WithinRangeEvent | real | No | |
WithinRangeHash | hashtable | No | |
WithinRangeRange | real | No | |
WithinRangeUnit | unit | No | |
WithinRangeUsers | group | No | |
WithinRangeWanted_Event | real | No | |
WithinRangeWanted_Filter | boolexpr | No | |
WithinRangeWanted_Keep | boolean | No | |
WithinRangeWanted_Trigger | trigger | No | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
WP_Group | group | No | |
WP_GroupCount | integer | No | |
WP_GroupEnum | unit | No | |
WP_NorthA | location | No | |
WP_NorthA1 | location | No | |
WP_NorthA1reached | boolean | Yes | |
WP_NorthA2 | location | No | |
WP_NorthA2reached | boolean | Yes | |
WP_NorthAGroup | group | No | |
WP_NorthAsecondary | location | No | |
WP_NorthB | location | No | |
WP_NorthB1 | location | No | |
WP_NorthB1reached | boolean | Yes | |
WP_NorthB2 | location | No | |
WP_NorthB2reached | boolean | Yes | |
WP_NorthBGroup | group | No | |
WP_NorthBsecondary | location | No | |
WP_NorthC | location | No | |
WP_NorthC1 | location | No | |
WP_NorthC1reached | boolean | Yes | |
WP_NorthC2 | location | No | |
WP_NorthC2reached | boolean | Yes | |
WP_NorthCGroup | group | No | |
WP_NorthCsecondary | location | No | |
WP_NorthFin | location | No | |
WP_NorthRaxA | unit | No | |
WP_NorthRaxB | unit | No | |
WP_NorthRaxC | unit | No | |
WP_SouthA | location | No | |
WP_SouthA1 | location | No | |
WP_SouthA1reached | boolean | Yes | |
WP_SouthA2 | location | No | |
WP_SouthA2reached | boolean | Yes | |
WP_SouthAGroup | group | No | |
WP_SouthAsecondary | location | No | |
WP_SouthB | location | No | |
WP_SouthB1 | location | No | |
WP_SouthB1reached | boolean | Yes | |
WP_SouthB2 | location | No | |
WP_SouthB2reached | boolean | Yes | |
WP_SouthBGroup | group | No | |
WP_SouthBsecondary | location | No | |
WP_SouthC | location | No | |
WP_SouthC1 | location | No | |
WP_SouthC1reached | boolean | Yes | |
WP_SouthC2 | location | No | |
WP_SouthC2reached | boolean | Yes | |
WP_SouthCGroup | group | No | |
WP_SouthCsecondary | location | No | |
WP_SouthFin | location | No | |
WP_SouthRaxA | unit | No | |
WP_SouthRaxB | unit | No | |
WP_SouthRaxC | unit | No | |
WP_TempGroup | group | No | |
WP_TempInt | integer | No | |
WP_TempInt2 | integer | No | |
WP_Timer | timer | No | |
WP_TotalSpawnInstances | integer | No | |
WP_UnitDest | location | Yes | |
WP_UnitDestX | real | Yes | |
WP_UnitDestY | real | Yes | |
WP_UnitHealerCount | integer | No | |
WP_UnitHealerMaxLife | integer | No | |
WP_UnitMeleeCount | integer | No | |
WP_UnitMeleeMaxLife | integer | No | |
WP_UnitMountedCount | integer | No | |
WP_UnitMountedMaxLife | integer | No | |
WP_UnitRangedCount | integer | No | |
WP_UnitRangedMaxLife | integer | No | |
WP_UnitSiegeCount | integer | No |
//===========================================================================
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 i = 0
loop
set i = udg_CheckDeathList[i]
exitwhen i == 0
if udg_IsUnitNew[i] then
//The unit was just created.
set udg_IsUnitNew[i] = false
elseif udg_IsUnitTransforming[i] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UDex = i
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
set udg_IsUnitTransforming[i] = false
call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
elseif udg_IsUnitAlive[i] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[i] = true
set udg_IsUnitAlive[i] = false
set udg_UDex = i
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
endif
set udg_CheckDeathInList[i] = false
endloop
//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
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
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 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
set udg_IsUnitAlive[i] = true
set udg_DeathEvent = 0.00
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[i] = false
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
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
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
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
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 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))
loop
set i = i - 1
set p = Player(i)
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 GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
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
//===========================================================================
//
// Damage Engine 5.7.1.1 - update requires replacing the JASS script.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method getIndex takes trigger t, string eventName, real value returns integer
static method registerTrigger takes trigger whichTrig, string var, real weight returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method operator [] takes code c returns trigger
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = CreateTrigger()
private trigger t2 = CreateTrigger()
private trigger t3 = CreateTrigger() //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfiguration" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
*/
struct DamageTrigger extends array
//Map-makers should comment-out any booleans they will never need to check for.
method checkConfiguration takes nothing returns boolean
if this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif udg_DamageEventAmount > this.damageMin then
return true
endif
return false
endmethod
//The below variables are constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean configured
boolean usingGUI
//The below variables are private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceBuff = udg_DamageFilterSourceB
set this.targetBuff = udg_DamageFilterTargetB
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set udg_DamageFilterAttackT =-1
set udg_DamageFilterDamageT =-1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterMinAmount=0.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if var == "udg_DamageModifierEvent" then
if root >= 4 then
set root= SHIELD //4.00 or higher
else
set root= MOD //Less than 4.00
endif
elseif var == "udg_DamageEvent" then
if root == 2 or root == 0 then
set root= ZERO
else
set root= DAMAGE //Above 0.00 but less than 2.00, generally would just be 1.00
endif
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
local thistype index = getIndex(t, eventName, lbs)
if index == 0 then
return false
endif
set prev.next = index.next
set trigIndexStack[index] = trigIndexStack[0]
set trigIndexStack[0] = index
if reset then
call index.configure()
set index.configured = false
set index = index*FILTER_MAX
call index.toggleAllFilters(false)
endif
return true
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if not this.trigFrozen and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and (not this.configured or this.checkConfiguration()) then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static 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
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if pierce != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call DamageTrigger.AOE.run()
endif
set udg_DamageEventAOE = 0
set udg_DamageEventLevel = 0
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != 0 then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if udg_DamageEventAmount != 0.00 then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call 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 setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if this.damage != 0.00 then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damage != 0.00 and d.damageType == DAMAGE_TYPE_UNKNOWN)
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
if not DamageTrigger.eventIndex.checkConfiguration() then
return
endif
endif
//! endtextmacro
endlibrary
function SpellIndexGetVars takes integer i returns nothing
set udg_Spell__Ability = udg_Spell_i_Abil[udg_Spell_i_Head[i]]
set udg_Spell__Index = i
set udg_Spell__Caster = udg_Spell_i_Caster[i]
set udg_Spell__CasterOwner = GetOwningPlayer(udg_Spell__Caster)
set udg_Spell__Level = udg_Spell_i_Level[i]
set udg_Spell__LevelMultiplier = udg_Spell__Level //Spell__LevelMultiplier is a real variable.
set udg_Spell__Target = udg_Spell_i_Target[i]
//Magic to ensure the locations never leak.
call MoveLocation(udg_Spell__CastPoint, GetUnitX(udg_Spell__Caster), GetUnitY(udg_Spell__Caster))
if udg_Spell__Target == null then
call MoveLocation(udg_Spell__TargetPoint, udg_Spell_i_TargetX[i], udg_Spell_i_TargetY[i])
else
call MoveLocation(udg_Spell__TargetPoint, GetUnitX(udg_Spell__Target), GetUnitY(udg_Spell__Target))
endif
set udg_Spell__TargetGroup = udg_Spell_i_TargetGroup[i]
set udg_Spell__Completed = udg_Spell_i_Completed[i]
set udg_Spell__Channeling = udg_Spell_i_Channeling[i]
endfunction
function SpellSetFilters takes integer i returns nothing
set udg_Spell_i_AllowEnemy[i] = udg_Spell__Filter_AllowEnemy
set udg_Spell_i_AllowAlly[i] = udg_Spell__Filter_AllowAlly
set udg_Spell_i_AllowDead[i] = udg_Spell__Filter_AllowDead
set udg_Spell_i_AllowLiving[i] = udg_Spell__Filter_AllowLiving
set udg_Spell_i_AllowMagicImmune[i] = udg_Spell__Filter_AllowMagicImmune
set udg_Spell_i_AllowMechanical[i] = udg_Spell__Filter_AllowMechanical
set udg_Spell_i_AllowStructure[i] = udg_Spell__Filter_AllowStructure
set udg_Spell_i_AllowFlying[i] = udg_Spell__Filter_AllowFlying
set udg_Spell_i_AllowHero[i] = udg_Spell__Filter_AllowHero
set udg_Spell_i_AllowNonHero[i] = udg_Spell__Filter_AllowNonHero
endfunction
function SpellIndexDestroy takes integer i returns nothing
local integer indexOf
local integer index
if udg_Spell_i_RecycleList[i] >= 0 then
return
endif
//If the caster is still channeling on the spell, don't destroy until it's finished:
if not udg_Spell_i_Channeling[i] then
set index = udg_Spell_i_Head[i]
set udg_Spell_i_RecycleList[i] = udg_Spell_i_Recycle
set udg_Spell_i_Recycle = i
//Reset things to defaults:
set udg_Spell_i_Time[i] = 0.00
set udg_Spell_i_LastTime[i] = 0.00
set udg_Spell_i_Duration[i] = 0.00
set udg_Spell_i_Completed[i] = false
set udg_Spell_i_Caster[i] = null
set udg_Spell_i_Target[i] = null
set udg_Spell_i_OnLoopStack[i] = null
//Recycle any applicable target unit group.
if udg_Spell_i_TargetGroup[i] != null then
call GroupClear(udg_Spell_i_TargetGroup[i])
set udg_Spell_i_GroupStack[udg_Spell_i_GroupN] = udg_Spell_i_TargetGroup[i]
set udg_Spell_i_GroupN = udg_Spell_i_GroupN + 1
set udg_Spell_i_TargetGroup[i] = null
endif
//Clear any user-specified data in the hashtable:
call FlushChildHashtable(udg_Spell__Hash, i)
//call BJDebugMsg("Destroying index: " + I2S(i))
endif
set indexOf = udg_Spell_i_StackRef[i]
if indexOf >= 0 then
set index = udg_Spell_i_StackN - 1
set udg_Spell_i_StackN = index
set udg_Spell_i_StackRef[udg_Spell_i_Stack[index]] = indexOf
set udg_Spell_i_Stack[indexOf] = udg_Spell_i_Stack[index]
if index == 0 then
//If no more spells require the timer, pause it.
call PauseTimer(udg_Spell_i_Timer)
endif
set udg_Spell_i_StackRef[i] = -1
endif
endfunction
function SpellTriggerExecute takes integer i, trigger t returns real
local real d = udg_Spell_i_Duration[i]
local boolean b = false
set udg_Spell__Duration = d
set udg_Spell__Time = 0.00
if t != null then
set udg_Spell__Trigger_OnLoop = null
set udg_Spell__Expired = d <= 0.00 //If the duration is <= 0, the spell has expired.
call SpellIndexGetVars(i)
if TriggerEvaluate(t) then
call TriggerExecute(t)
endif
if udg_Spell__Trigger_OnLoop != null then
set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
endif
//The remaining lines in this function process the duration specified by the user.
if udg_Spell__StartDuration then
set udg_Spell__StartDuration = false
set udg_Spell__Duration = udg_Spell_i_Duration[udg_Spell_i_Head[i]] + udg_Spell_i_LastTime[udg_Spell_i_Head[i]]*udg_Spell__LevelMultiplier
elseif (udg_Spell__Expired and d > 0.00) or (udg_Spell__Duration <= 0.00) then
set udg_Spell__Duration = 0.00
return udg_Spell__Time
//The user manually expired the spell or the spell duration ended on its own.
endif
if d != udg_Spell__Duration then
//A new duration has been assigned
set d = udg_Spell__Duration
set b = true
endif
set udg_Spell__Duration = 0.00
if udg_Spell__Time == 0.00 then
if udg_Spell_i_LastTime[i] == 0.00 then
if udg_Spell_i_Time[udg_Spell_i_Head[i]] > 0.00 then
//The user specified a default interval to follow:
set udg_Spell__Time = udg_Spell_i_Time[udg_Spell_i_Head[i]]
else
//Set the spell time to the minimum.
set udg_Spell__Time = udg_Spell__Interval
endif
else
//Otherwise, set it to what it was before.
set udg_Spell__Time = udg_Spell_i_LastTime[i]
endif
//else, the user is specifying a new time for the spell.
endif
set udg_Spell_i_LastTime[i] = udg_Spell__Time //Whatever the case, remember this time for next time.
if b then
//The duration was just assigned
set udg_Spell_i_Duration[i] = d
else
//The duration has been ongoing
set udg_Spell_i_Duration[i] = d - udg_Spell__Time
endif
endif
return udg_Spell__Time
endfunction
//===========================================================================
// Runs every Spell__Interval seconds and handles all of the timed events.
//
function SpellTimerLoop takes nothing returns nothing
local integer i = udg_Spell_i_StackN
local integer node
local real time
set udg_Spell__Running = true
//Run stack top to bottom to avoid skipping slots when destroying.
loop
set i = i - 1
exitwhen i < 0
set node = udg_Spell_i_Stack[i]
set time = udg_Spell_i_Time[node] - udg_Spell__Interval
if time <= 0.00 then
set time = SpellTriggerExecute(node, udg_Spell_i_OnLoopStack[node])
endif
if time <= 0.00 then
call SpellIndexDestroy(node)
else
set udg_Spell_i_Time[node] = time
endif
endloop
set udg_Spell__Running = false
endfunction
//===========================================================================
// This is the meat of the system as it handles the event responses.
//
function RunSpellEvent takes nothing returns boolean
local boolean b
local integer aid = GetSpellAbilityId()
local integer head = LoadInteger(udg_Spell__Hash, 0, aid)
local integer i
local integer id
local trigger t
local playerunitevent eid
if head == 0 then
//Nothing for this ability has been registered. Skip the sequence.
return false
endif
set eid = ConvertPlayerUnitEvent(GetHandleId(GetTriggerEventId()))
set udg_Spell__Caster = GetTriggerUnit()
set id = GetHandleId(udg_Spell__Caster)
set i = LoadInteger(udg_Spell__Hash, aid, id)
if i == 0 then
//This block will almost always happen with the OnChannel event. In the
//case of Charge Gold and Lumber, only an OnEffect event will run.
set i = udg_Spell_i_Recycle
if i == 0 then
//Create a new, unique index
set i = udg_Spell_i_Instances + 1
set udg_Spell_i_Instances = i
else
//Repurpose an existing one
set udg_Spell_i_Recycle = udg_Spell_i_RecycleList[i]
endif
//call BJDebugMsg("Creating index: " + I2S(i))
set udg_Spell_i_RecycleList[i] = -1
set udg_Spell_i_StackRef[i] = -1
set udg_Spell_i_Head[i] = head
if eid == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
set udg_Spell_i_Channeling[i] = true
call SaveInteger(udg_Spell__Hash, aid, id, i)
set t = udg_Spell_i_OnChannelStack[head]
else //eid == EVENT_PLAYER_UNIT_SPELL_EFFECT
set t = udg_Spell_i_OnEffectStack[head]
endif
set udg_Spell_i_Caster[i] = udg_Spell__Caster
set udg_Spell_i_Level[i] = GetUnitAbilityLevel(udg_Spell__Caster, aid)
set udg_Spell_i_Target[i] = GetSpellTargetUnit()
set udg_Spell_i_TargetX[i] = GetSpellTargetX()
set udg_Spell_i_TargetY[i] = GetSpellTargetY()
set udg_Spell_i_OnLoopStack[i] = udg_Spell_i_OnLoopStack[head]
if udg_Spell_i_UseTG[head] then
//Get a recycled unit group or create a new one.
set id = udg_Spell_i_GroupN - 1
if id >= 0 then
set udg_Spell_i_GroupN = id
set udg_Spell_i_TargetGroup[i] = udg_Spell_i_GroupStack[id]
else
set udg_Spell_i_TargetGroup[i] = CreateGroup()
endif
endif
elseif eid == EVENT_PLAYER_UNIT_SPELL_CAST then
set t = udg_Spell_i_OnCastStack[head]
elseif eid == EVENT_PLAYER_UNIT_SPELL_EFFECT then
set t = udg_Spell_i_OnEffectStack[head]
elseif eid == EVENT_PLAYER_UNIT_SPELL_FINISH then
set udg_Spell_i_Completed[i] = true
return true
else //eid == EVENT_PLAYER_UNIT_SPELL_ENDCAST
set udg_Spell_i_Channeling[i] = false
call RemoveSavedInteger(udg_Spell__Hash, aid, id)
set t = udg_Spell_i_OnFinishStack[head]
endif
if SpellTriggerExecute(i, t) > 0.00 then
//Set the spell time to the user-specified one.
set udg_Spell_i_Time[i] = udg_Spell__Time
if udg_Spell_i_StackRef[i] < 0 then
//Allocate the spell index onto the loop stack.
set aid = udg_Spell_i_StackN
set udg_Spell_i_Stack[aid] = i
set udg_Spell_i_StackRef[i] = aid
set udg_Spell_i_StackN = aid + 1
if aid == 0 then
//If this is the first spell index using the timer, start it up:
call TimerStart(udg_Spell_i_Timer, udg_Spell__Interval, true, function SpellTimerLoop)
endif
endif
elseif (not udg_Spell_i_Channeling[i]) and (t != null or udg_Spell_i_Time[i] <= 0.00) then
call SpellIndexDestroy(i)
endif
set t = null
return true
endfunction
//This function is invoked if an event was launched recursively by another event's callback.
function RunPreSpellEvent takes nothing returns nothing
local integer i = udg_Spell__Index
local real time = udg_Spell__Time
local real d = udg_Spell__Duration
local boolean expired = udg_Spell__Expired
if udg_Spell__Trigger_OnLoop != null then
set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
endif
if RunSpellEvent() then
set udg_Spell__Time = time
set udg_Spell__Duration = d
set udg_Spell__Expired = expired
call SpellIndexGetVars(i)
endif
endfunction
//===========================================================================
// Base function of the system: runs when an ability event does something.
//
function SpellSystemEvent takes nothing returns boolean
if udg_Spell__Running then
call RunPreSpellEvent()
else
set udg_Spell__Running = true
call RunSpellEvent()
set udg_Spell__Running = false
endif
return false
endfunction
//===========================================================================
// Set Spell__Ability to your spell's ability
// Set Spell__Trigger_OnChannel/Cast/Effect/Finish/Loop to any trigger(s) you
// want to automatically run.
//
// GUI-friendly: Run Spell System <gen> (ignoring conditions)
//
function SpellSystemRegister takes nothing returns nothing
local integer aid = udg_Spell__Ability
local integer head = udg_Spell_i_Instances + 1
if HaveSavedInteger(udg_Spell__Hash, 0, aid) or aid == 0 then
//The system rejects duplicate or unassigned abilities.
return
endif
set udg_Spell_i_Instances = head
set udg_Spell_i_Abil[head] = aid
//Preload the ability on dummy unit to help prevent first-instance lag
call UnitAddAbility(udg_Spell_i_PreloadDummy, aid)
//Save head index to the spell ability so it be referenced later.
call SaveInteger(udg_Spell__Hash, 0, aid, head)
//Set any applicable event triggers.
set udg_Spell_i_OnChannelStack[head]= udg_Spell__Trigger_OnChannel
set udg_Spell_i_OnCastStack[head] = udg_Spell__Trigger_OnCast
set udg_Spell_i_OnEffectStack[head] = udg_Spell__Trigger_OnEffect
set udg_Spell_i_OnFinishStack[head] = udg_Spell__Trigger_OnFinish
set udg_Spell_i_OnLoopStack[head] = udg_Spell__Trigger_OnLoop
set udg_Spell_i_InRangeFilter[head] = udg_Spell__Trigger_InRangeFilter
//Set any customized filter variables:
call SpellSetFilters(head)
//Tell the system to automatically create target groups, if needed
set udg_Spell_i_AutoAddTargets[head] = udg_Spell__AutoAddTargets
set udg_Spell_i_UseTG[head] = udg_Spell__UseTargetGroup or udg_Spell__AutoAddTargets
//Handle automatic buff assignment
set udg_Spell_i_BuffAbil[head] = udg_Spell__BuffAbility
set udg_Spell_i_BuffOrder[head] = udg_Spell__BuffOrder
//Set the default time sequences if a duration is used:
set udg_Spell_i_Time[head] = udg_Spell__Time
set udg_Spell_i_Duration[head] = udg_Spell__Duration
set udg_Spell_i_LastTime[head] = udg_Spell__DurationPerLevel
//Set variables back to their defaults:
set udg_Spell__Trigger_OnChannel = null
set udg_Spell__Trigger_OnCast = null
set udg_Spell__Trigger_OnEffect = null
set udg_Spell__Trigger_OnFinish = null
set udg_Spell__Trigger_OnLoop = null
set udg_Spell__Trigger_InRangeFilter= null
set udg_Spell__AutoAddTargets = false
set udg_Spell__UseTargetGroup = false
set udg_Spell__Time = 0.00
set udg_Spell__Duration = 0.00
set udg_Spell__DurationPerLevel = 0.00
set udg_Spell__BuffAbility = 0
set udg_Spell__BuffOrder = 0
set udg_Spell__Filter_AllowEnemy = udg_Spell_i_AllowEnemy[0]
set udg_Spell__Filter_AllowAlly = udg_Spell_i_AllowAlly[0]
set udg_Spell__Filter_AllowDead = udg_Spell_i_AllowDead[0]
set udg_Spell__Filter_AllowMagicImmune = udg_Spell_i_AllowMagicImmune[0]
set udg_Spell__Filter_AllowMechanical = udg_Spell_i_AllowMechanical[0]
set udg_Spell__Filter_AllowStructure = udg_Spell_i_AllowStructure[0]
set udg_Spell__Filter_AllowFlying = udg_Spell_i_AllowFlying[0]
set udg_Spell__Filter_AllowHero = udg_Spell_i_AllowHero[0]
set udg_Spell__Filter_AllowNonHero = udg_Spell_i_AllowNonHero[0]
set udg_Spell__Filter_AllowLiving = udg_Spell_i_AllowLiving[0]
endfunction
function SpellFilterCompare takes boolean is, boolean yes, boolean no returns boolean
return (is and yes) or ((not is) and no)
endfunction
//===========================================================================
// Before calling this function, set Spell__InRangePoint to whatever point
// you need, THEN set Spell__InRange to the radius you need. The system will
// enumerate the units matching the configured filter and fill them into
// Spell_InRangeGroup.
//
function SpellGroupUnitsInRange takes nothing returns boolean
local integer i = udg_Spell_i_Head[udg_Spell__Index]
local integer j = 0
local unit u
local real padding = 64.00
if udg_Spell_i_AllowStructure[i] then
//A normal unit can only have up to size 64.00 collision, but if the
//user needs to check for structures we need a padding big enough for
//the "fattest" ones: Tier 3 town halls.
set padding = 197.00
endif
call GroupEnumUnitsInRangeOfLoc(udg_Spell__InRangeGroup, udg_Spell__InRangePoint, udg_Spell__InRange + padding, null)
loop
set u = FirstOfGroup(udg_Spell__InRangeGroup)
exitwhen u == null
call GroupRemoveUnit(udg_Spell__InRangeGroup, u)
loop
exitwhen udg_Spell_i_AutoAddTargets[i] and IsUnitInGroup(u, udg_Spell__TargetGroup)
exitwhen not IsUnitInRangeLoc(u, udg_Spell__InRangePoint, udg_Spell__InRange)
exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_DEAD), udg_Spell_i_AllowDead[i], udg_Spell_i_AllowLiving[i])
exitwhen not SpellFilterCompare(IsUnitAlly(u, udg_Spell__CasterOwner), udg_Spell_i_AllowAlly[i], udg_Spell_i_AllowEnemy[i])
exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_HERO) or IsUnitType(u, UNIT_TYPE_RESISTANT), udg_Spell_i_AllowHero[i], udg_Spell_i_AllowNonHero[i])
exitwhen IsUnitType(u, UNIT_TYPE_STRUCTURE) and not udg_Spell_i_AllowStructure[i]
exitwhen IsUnitType(u, UNIT_TYPE_FLYING) and not udg_Spell_i_AllowFlying[i]
exitwhen IsUnitType(u, UNIT_TYPE_MECHANICAL) and not udg_Spell_i_AllowMechanical[i]
exitwhen IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not udg_Spell_i_AllowMagicImmune[i]
set udg_Spell__InRangeUnit = u
//Run the user's designated filter, if one exists.
exitwhen udg_Spell_i_InRangeFilter[i] != null and not TriggerEvaluate(udg_Spell_i_InRangeFilter[i])
set j = j + 1
set udg_Spell__InRangeUnits[j] = u
exitwhen true
endloop
endloop
if j > udg_Spell__InRangeMax and udg_Spell__InRangeMax > 0 then
//The user has defined a maximum number of units allowed in the group.
//Remove a random unit until the total does not exceed capacity.
loop
set i = GetRandomInt(1, j)
set udg_Spell__InRangeUnits[i] = udg_Spell__InRangeUnits[j]
set j = j - 1
exitwhen j == udg_Spell__InRangeMax
endloop
endif
set udg_Spell__InRangeCount = j
set udg_Spell__InRangeMax = 0
set udg_Spell__InRange = 0.00
set i = udg_Spell_i_Head[udg_Spell__Index]
loop
exitwhen j == 0
set u = udg_Spell__InRangeUnits[j]
call GroupAddUnit(udg_Spell__InRangeGroup, u)
if udg_Spell_i_AutoAddTargets[i] then
call GroupAddUnit(udg_Spell__TargetGroup, u)
endif
if udg_Spell__WakeTargets and UnitIsSleeping(u) then
call UnitWakeUp(u)
endif
if udg_Spell_i_BuffAbil[i] != 0 and udg_Spell_i_BuffOrder[i] != 0 then
//Auto-buff units added to group:
call UnitAddAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
call IssueTargetOrderById(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffOrder[i], u)
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
endif
set j = j - 1
endloop
set u = null
return false
endfunction
function SpellPreloadEnd takes nothing returns nothing
local integer i = udg_Spell_i_Instances
loop
exitwhen i == 0
//Remove preloaded abilities so they don't interfere with orders
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_Abil[udg_Spell_i_Head[i]])
set i = i - 1
endloop
endfunction
//===========================================================================
function InitTrig_Spell_System takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS
local player p
local trigger t
if gg_trg_Spell_System != null then
//A JASS function call already initialized the system.
return
endif
//This runs before map init events so the hashtable is ready before then.
set udg_Spell__Hash = InitHashtable()
//Initialize these two locations which will never get removed
set udg_Spell__CastPoint = Location(0, 0)
set udg_Spell__TargetPoint = Location(0, 0)
//Recycle existing unit groups into the recycle stack to avoid needing to destroy any extras.
set udg_Spell_i_GroupStack[2] = udg_Spell__TargetGroup
set udg_Spell_i_GroupStack[3] = udg_Spell_i_TargetGroup[0]
set udg_Spell_i_GroupStack[4] = udg_Spell_i_TargetGroup[1]
set udg_Spell_i_GroupN = 5 //There are already five valid unit groups thanks to Variable Editor.
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_Spell__InRange", GREATER_THAN, 0.00)
call TriggerAddCondition(t, Filter(function SpellGroupUnitsInRange))
set t = CreateTrigger()
call TriggerAddCondition(t, Filter(function SpellSystemEvent))
loop
set i = i - 1
set p = Player(i)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CAST, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_FINISH, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
exitwhen i == 0
endloop
set p = null
set t = null
//Run the configuration trigger so its variables are ready before the
//map initialization events run.
call TriggerExecute(gg_trg_Spell_System_Config)
call SpellSetFilters(0)
//Create this trigger so it's GUI-friendly.
set gg_trg_Spell_System = CreateTrigger()
call TriggerAddAction(gg_trg_Spell_System, function SpellSystemRegister)
set gg_trg_Spell_System_Config = gg_trg_Spell_System //In case the user accidentally picks this one
//Create a dummy unit for preloading abilities and casting buffs.
set udg_Spell_i_PreloadDummy = CreateUnit(udg_Spell__DummyOwner, udg_Spell__DummyType, 0, 0, 0)
//Start the timer to remove its abilities:
call TimerStart(udg_Spell_i_Timer, 0.00, false, function SpellPreloadEnd)
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, 'Amov') //Force it to never move to cast spells
endfunction
//UnitWithinRange 1.5
// By Tasyen
//Allows to register specific Units to throw events when an unit enters a wanted range.
//Inside this Events you have access to the entered unit, the enteringUnit and the Range this was registered on.
//How UnitWithinRange works?
//UnitWithinRange generateds for any Unit Registered an own Trigger handling Unit comes in Range of x.
//By Connecting Unit/Trigger with Hashtabels under their HandleID
// All units using this are inside the Group udg_WithinRangeUsers.
//=========================================================================================================
// Event
//=========================================================================================================
// udg_WithinRangeEvent tells you what happens
// udg_WithinRangeEvent = 1 Enters
// udg_WithinRangeEvent = -1 AutoClean Cause of Death/Remove/Replaced of the registered Unit
// udg_WithinRangeUnit is the Unit who was Registered
// udg_WithinRangeEnteringUnit is the Unit who came in Range
// udg_WithinRangeRange is the Range under which this was registered (it is not the distance between 2 units, the distance function will bve from the center of each unit while the range detecions includes colisionsizes).
//=========================================================================================================
//Jass API
//=========================================================================================================
// function RegisterUnitWithinRangeEvent takes unit u, real range, code filter, real eventValue returns boolean
// - more simple usage of super: no trigger, destroyFilterWhenDone=true, cleanOnKilled = true
// function RegisterUnitWithinRangeTrigger takes unit u, real range, code filter, trigger execution returns boolean
// - more simple usage of super: no Event Thrown, destroyFilterWhenDone=true, cleanOnKilled = true
// function RegisterUnitWithinRangeSuper takes unit u, real range, boolean cleanOnKilled, boolexpr filter, trigger execution, real eventValue, boolean destroyFilterWhenDone returns boolean
// - inside the filter you can only access the entering Unit with GetTriggerUnit()
// - Start the detection for this Unit with this range
// - can not register twice the same range (main number 800.0 and 800.1 are now allowed) onto 1 unit.
// - cleanOnKilled will generate an trigger which will execute DeRegisterUnitWithinRangeUnit as soon the unit dies.
// - cleanOnKilled creates 1 Trigger for each Unit registered.
// function RegisterUnitWithinRangeEx takes unit u, real range, boolean cleanOnKilled, boolexpr filter returns boolean
// -backwards comptatible, wrapper for super
// function RegisterUnitWithinRange takes unit u, real range, boolean cleanOnKilled returns boolean
// -backwards comptatible, wrapper for super
// function DeRegisterUnitWithinRange takes unit u, real range returns boolean
// Destroys the range detection with this specific Range and Unit.
// function DeRegisterUnitWithinRangeUnit takes unit u returns boolean
// Destroys all Triggers used by the unit from UnitWithinRange.
//=========================================================================================================
//Hashtable Indexes:
//=========================================================================================================
// unitId
// -1 = Auto Clean Trigger
// 0 = amount of range triggers used
// 1+ = Range-Detecion Triggers
// range = index of the trigger controlling that range.
// trigId
// -1 = TriggerAction (For remove usage)
// 0 = Registered Unit
// 0 = Range Detected
// 0 = destroyFilterWhenDone
// 1 = EventValue
// 1 = ExecutionTrigger
// 3 = filter (boolexpr)
//=========================================================================================================
//changes 1.5
//=========================================================================================================
// One can now choose the EventValue thrown.
// One can now choose a trigger beeing executed (including conditions) when a unit enters.
// ^^ included for GUI with Wanted_Event/Wanted_Trigger.
// The Filters are now supported by the GUI usage.
// Implemented Autodestorying of the filters, if the range detection ends .
// RegisterUnitWithinRangeSuper allows you to choose, the others allways destory the filter.
//=========================================================================================================
constant function UnitWithinRangeDefaultEvent takes nothing returns real
return 1.0
endfunction
//helper function destroys a trigger, its action, and clears the used table space.
function DestroyUnitWhithinTrigger takes trigger trig returns nothing
local integer trigId = GetHandleId(trig)
if LoadBoolean(udg_WithinRangeHash, trigId,0) then
call DestroyBoolExpr(LoadBooleanExprHandle(udg_WithinRangeHash,trigId,3))
endif
call TriggerRemoveAction(trig, LoadTriggerActionHandle(udg_WithinRangeHash,trigId,-1))
call FlushChildHashtable(udg_WithinRangeHash, trigId)
call DestroyTrigger(trig)
endfunction
//Destroys all Triggers used by the unit from UnitWithinRange.
function DeRegisterUnitWithinRangeUnit takes unit u returns boolean
local integer unitId = GetHandleId(u)
local integer size = LoadInteger(udg_WithinRangeHash,unitId,0)
local integer LoopA = 1
//is there a cleanOnKilled Trigger?
if LoadTriggerHandle(udg_WithinRangeHash,unitId,-1) != null then
call DestroyUnitWhithinTrigger(LoadTriggerHandle(udg_WithinRangeHash,unitId,-1))
endif
loop
exitwhen LoopA > size
call DestroyUnitWhithinTrigger(LoadTriggerHandle(udg_WithinRangeHash,unitId,LoopA))
set LoopA = LoopA + 1
endloop
call FlushChildHashtable(udg_WithinRangeHash, unitId)
call GroupRemoveUnit(udg_WithinRangeUsers, u)
return true
endfunction
//Destroys the Trigger form this unit having this specific Range.
//Triggers are unique based on Range & Unit.
function DeRegisterUnitWithinRange takes unit u, real range returns boolean
local trigger trig
local integer trigId
local integer unitId = GetHandleId(u)
local integer size = LoadInteger(udg_WithinRangeHash,unitId,0)
local integer rangeAsInt = R2I(range)
local integer index
//Range smaller equal 0 does not make sense, skip it or has nothing registered.
if range <= 0 or size <= 0 or not HaveSavedInteger(udg_WithinRangeHash,unitId,rangeAsInt) then
return false
endif
set index = LoadInteger(udg_WithinRangeHash,unitId,rangeAsInt)
set trig = LoadTriggerHandle(udg_WithinRangeHash,unitId,index)
set trigId = GetHandleId(trig)
//destroy and clean it.
call RemoveSavedInteger(udg_WithinRangeHash, unitId, rangeAsInt)
call RemoveSavedHandle(udg_WithinRangeHash, unitId, index)
call DestroyUnitWhithinTrigger(trig)
//Redindex, when not last?
if index != size then
set trig = LoadTriggerHandle(udg_WithinRangeHash, unitId, size)
set trigId = GetHandleId(trig)
call SaveTriggerHandle(udg_WithinRangeHash,unitId,index, trig )
set rangeAsInt = R2I( LoadReal(udg_WithinRangeHash, trigId, 0) )
call SaveInteger(udg_WithinRangeHash,unitId,rangeAsInt,index)
endif
set trig = null
call SaveInteger(udg_WithinRangeHash,unitId,0,size - 1)
//if the last trigger was removed, remove it from users.
if size == 1 then
//is there a cleanOnKilled Trigger?
if LoadTriggerHandle(udg_WithinRangeHash,unitId,-1) != null then
call RemoveSavedHandle(udg_WithinRangeHash, unitId, -1)
call DestroyUnitWhithinTrigger(LoadTriggerHandle(udg_WithinRangeHash,unitId,-1))
endif
call GroupRemoveUnit(udg_WithinRangeUsers, u)
call FlushChildHashtable(udg_WithinRangeHash, unitId)
endif
set trig = null
return true
endfunction
//This is called when someone comes in Range.
function ActionUnitWithinRange takes nothing returns nothing
local integer trigId = GetHandleId(GetTriggeringTrigger ())
local real eventValue = LoadReal(udg_WithinRangeHash, trigId, 1)
local trigger execution = LoadTriggerHandle(udg_WithinRangeHash, trigId, 1)
set udg_WithinRangeUnit = LoadUnitHandle(udg_WithinRangeHash,trigId,0)
set udg_WithinRangeEnteringUnit = GetTriggerUnit()
set udg_WithinRangeRange = LoadReal(udg_WithinRangeHash, trigId, 0)
if eventValue != 0.0 then
set udg_WithinRangeEvent = eventValue
set udg_WithinRangeEvent = 0.0
endif
if execution != null then
call ConditionalTriggerExecute(execution)
endif
set execution = null
endfunction
//This Action is called on Death/Remove/Replaced, if wanted on creation.
// Will throw an -1 Event after the DeRegistering was done.
function ActionUnitWithinCleanOnKilled takes nothing returns nothing
call DeRegisterUnitWithinRangeUnit (GetTriggerUnit())
set udg_WithinRangeUnit = GetTriggerUnit()
set udg_WithinRangeEvent = -1
set udg_WithinRangeEvent = 0
endfunction
//Registers an Unit comes within Range around Unit event.
//Uses for each Unit a own Trigger.
//Each Range can only be registered one time on each unit
//if cleanOnKilled = true an Trigger will be generated, if not existing which will DeRegister as soon the unit dies.
function RegisterUnitWithinRangeSuper takes unit u, real range, boolean cleanOnKilled, boolexpr filter, trigger execution, real eventValue, boolean destroyFilterWhenDone returns boolean
local trigger trig
local integer trigId
local integer unitId = GetHandleId(u)
local integer size = LoadInteger(udg_WithinRangeHash,unitId,0)
local integer rangeAsInt = R2I(range)
//Range smaller equal 0 does not make sense, skip it.
if range <= 0 then
return false
endif
//is the cleanOnKilled Trigger already existing?
if LoadTriggerHandle(udg_WithinRangeHash,unitId,-1) == null and cleanOnKilled then
set trig = CreateTrigger()
set trigId = GetHandleId(trig)
call SaveTriggerHandle(udg_WithinRangeHash,unitId,-1,trig)
call SaveTriggerActionHandle(udg_WithinRangeHash,trigId,-1, TriggerAddAction(trig, function ActionUnitWithinCleanOnKilled))
// This will trigger if the unit is removed/killed
call TriggerRegisterUnitStateEvent(trig, u, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 0.405)
set trig = null
endif
//Was this Range already Registered?
if HaveSavedInteger(udg_WithinRangeHash, unitId, rangeAsInt) then
return false
endif
//New Unique Range for this unit; create an new Trigger handling this range.
set trig = CreateTrigger()
set trigId = GetHandleId(trig)
set size = size + 1
call SaveTriggerHandle(udg_WithinRangeHash,unitId,size,trig)
call SaveUnitHandle(udg_WithinRangeHash,trigId,0,u)
call SaveReal(udg_WithinRangeHash,trigId,0,range)
call SaveTriggerActionHandle(udg_WithinRangeHash,trigId,-1, TriggerAddAction(trig, function ActionUnitWithinRange))
call SaveInteger(udg_WithinRangeHash,unitId,0,size)
call SaveInteger(udg_WithinRangeHash,unitId,rangeAsInt,size)
call SaveBoolean(udg_WithinRangeHash,trigId,0,destroyFilterWhenDone)
call SaveBooleanExprHandle(udg_WithinRangeHash,trigId,3,filter)
call SaveTriggerHandle(udg_WithinRangeHash,trigId,1,execution)
call SaveReal(udg_WithinRangeHash,trigId,1,eventValue)
call TriggerRegisterUnitInRange(trig, u, range, filter)
set trig = null
call GroupAddUnit(udg_WithinRangeUsers, u)
return true
endfunction
//Backwards compatible to 1.4
function RegisterUnitWithinRangeEx takes unit u, real range, boolexpr filter returns boolean
return RegisterUnitWithinRangeSuper(u,range,true,filter, null, 1.0,true)
endfunction
//added 1.5
function RegisterUnitWithinRangeEvent takes unit u, real range, code filter, real eventValue returns boolean
return RegisterUnitWithinRangeSuper(u,range,true,Condition(filter), null, eventValue, true)
endfunction
//added 1.5
function RegisterUnitWithinRangeTrigger takes unit u, real range, code filter, trigger execution returns boolean
return RegisterUnitWithinRangeSuper(u,range,true, Condition(filter), execution, 0.0, true)
endfunction
//Backwards compatible to below 1.4
function RegisterUnitWithinRange takes unit u, real range, boolean cleanOnKilled returns boolean
return RegisterUnitWithinRangeSuper(u,range,cleanOnKilled,null, null, 1.0,false)
endfunction
function WithinRangeGUIRegister takes nothing returns nothing
call RegisterUnitWithinRangeSuper( udg_WithinRangeUnit, udg_WithinRangeRange, true, udg_WithinRangeWanted_Filter, udg_WithinRangeWanted_Trigger, udg_WithinRangeWanted_Event, true)
if not udg_WithinRangeWanted_Keep then
set udg_WithinRangeWanted_Trigger = null
set udg_WithinRangeWanted_Event = UnitWithinRangeDefaultEvent()
set udg_WithinRangeWanted_Filter = null
endif
endfunction
function WithinRangeGUIDeRegister takes nothing returns nothing
//When called with Range 0 or below all Ranges will be removed.
if udg_WithinRangeRange <= 0 then
call DeRegisterUnitWithinRangeUnit( udg_WithinRangeUnit)
else
call DeRegisterUnitWithinRange( udg_WithinRangeUnit, udg_WithinRangeRange)
endif
endfunction
//===========================================================================
function InitTrig_WithinRange takes nothing returns nothing
set udg_WithinRangeHash = InitHashtable()
set udg_WithinRangeWanted_Event = UnitWithinRangeDefaultEvent()
set gg_trg_WithinRange = CreateTrigger()
set udg_WithinRange__DeRegister = CreateTrigger()
call TriggerAddAction(gg_trg_WithinRange, function WithinRangeGUIRegister)
call TriggerAddAction(udg_WithinRange__DeRegister, function WithinRangeGUIDeRegister)
endfunction
//CapturePoint System 1.4
// By Tasyen
//Allows to Make any Unit, you Register, captureable by staying near to it.
//This System has to be called before it starts working, is done in "CapturePoint Init" on default.
//Uses the UnitWithinRangeEvent
//=========================================================================================================
//Capture Style:
//=========================================================================================================
// 0 = +1 Influence, if only Allies are inside the CaptureZone. -1 If only Foes.
// 1 = Like 0; but Lose Influence, if no Ally is inside.
// 2 = +1 Influence if more allies; -1 if more foes
// 3 = Like 2; but Lose Influence, if no Ally is inside.
// 4 = Influence gain/loss is done by difference of Foes and allies
// 5 = Like 4; but Lose Influence, if no Ally is inside.
// to define new Styles Checkout "function CaptureGetInfluenceChange" and inser them
//=========================================================================================================
//CapturePointEvent
//=========================================================================================================
// With CapturePointEvent you can catch some nice Situations.
//
// CatpurePointEvent = 1 udg_CapturePointEventMovedUnit Starts Influenceing udg_CapturePointEventUnit
// CapturePointEvent = -1 udg_CapturePointEventMovedUnit stopps Influenceing udg_CapturePointEventUnit
// InfluencePercent Steps: udg_CapturePointEventPlayer = leadingPlayer, on a negative capturePointEvent its equal to owner.
// CapturePointEvent = 25 udg_CapturePointEventPlayer reached 25% Influence on udg_CapturePointEventUnit
// CapturePointEvent = 50 udg_CapturePointEventPlayer reached 50% Influence on udg_CapturePointEventUnit
// CapturePointEvent = 75 udg_CapturePointEventPlayer reached 75% Influence on udg_CapturePointEventUnit
// CapturePointEvent = -75 controlled CapturePoint udg_CapturePointEventUnit was reduced below 75%
// CapturePointEvent = -50 controlled CapturePoint udg_CapturePointEventUnit was reduced below 50%
// CapturePointEvent = -25 controlled CapturePoint udg_CapturePointEventUnit was reduced below 25%
// You can modify the Percent Events in the approaching Definition
//=========================================================================================================
//Definitions:
//=========================================================================================================
// function CapturePointDefaultFiler takes nothing returns boolean
// Defines who is excluded from influencing capture points.
// Default: Structures, Neutral Passive Units, Capture Points and Aloc Units are exclude from using capturing.
// function Captureinfluence takes unit u returns integer
// Definies how much a unit does Influence CapturePoints
// Default: Hero 2, Non-Hero 1, summoned 0.
// constant function CaptureTimerInterval takes nothing returns real
// Defines Bar/Influence Update Interval
// constant function CaptureBarUnitType takes nothing returns integer
// The ObjectId of the used GenericBar Unit, Make sure it is correct.
// constant function CaptureUsePercentEvents takes nothing returns boolean
// Enables % Influence Events
// constant function CapturePercentEventBase takes nothing returns integer
// On which x * base % a Event is Thrown
// constant function CapturePointDefaultStyle takes nothing returns integer
// constant function CapturePointDefaultInfluence takes nothing returns integer
// constant function CapturePointDefaultRange takes nothing returns real
// used in RegisterCapturePointSimple
// constant function CaptureBarDefaultX_Offset takes nothing returns real
// constant function CaptureBarDefaultY_Offset takes nothing returns real
// constant function CaptureBarDefaultZ_Offset takes nothing returns real
// used by RegisterCapturePointSimple & RegisterCapturePoint
//=========================================================================================================
//API:
//=========================================================================================================
// function RegisterCapturePointSpecific takes unit u, real range, integer influence, integer style, real x, real y, real z, real scale returns boolean
// Makes an Unit Captureable and generateds an CaptureBar over it.
// function RegisterCapturePoint takes unit u, real range, integer influence, integer style returns boolean
// Makes an Unit Captureable and generateds an CaptureBar over it.
// Simple Ones use default X/Y/Z offset and the unit scale from Object Editor
// function RegisterCapturePointSimple takes unit u returns boolean
// Wrapper for RegisterCapturePoint by using the Default Values in Definitions
// Except for the unit.
// function DeRegisterCapturePoint takes unit u, boolean DeregisterUnitWithin returns boolean
// Makes an Captureable Unit uncaptureable again.
// If true the unit will be kicked out of UnitWithin too.
// function CapturePointStopTimer takes nothing returns nothing
// Stops the Influence Timer and the Grafic Update Timer of CapturePoint
// function CapturePointStartTimer takes nothing returns nothing
// Starts the timers of this System.
// Is done if you call this System the first time.
// udg_CatpurePointEvent = 1 | -1
//=========================================================================================================
// Definitions:
//=========================================================================================================
//Define how much influnce Influnce Generated by unit u
//If you don't want such a behaviour simply remove anything except the last "return 1"
function Captureinfluence takes unit u returns integer
if IsUnitType(u, UNIT_TYPE_HERO) and not(IsUnitType(u,UNIT_TYPE_SUMMONED) or IsUnitType(u,UNIT_TYPE_STUNNED) or IsUnitType(u,UNIT_TYPE_ETHEREAL) or IsUnitType(u,UNIT_TYPE_SLEEPING) or IsUnitType(u,UNIT_TYPE_POLYMORPHED)) then
return 1
endif
return 0
endfunction
//Structures, Neutral Passive Units, Capture Points and Aloc Units are exclude from using capturing.
function CapturePointDefaultFiler takes nothing returns boolean
local unit u = GetTriggerUnit()
local boolean b = not IsUnitType(u, UNIT_TYPE_STRUCTURE) and GetOwningPlayer(u) != Player(PLAYER_NEUTRAL_PASSIVE) and not IsUnitInGroup(u, udg_CapturePoints) and GetUnitAbilityLevel(u,'Aloc') == 0
set u = null
return b
endfunction
constant function CaptureUsePercentEvents takes nothing returns boolean
return true
endfunction
//If Influence Rises/Falls over a negative/positive x time of this value a Event with this Value is thrown
//Default 25/50/75 %;
//0% Event is hardcoded excluded.
// Anything below 5 is not Recommented.
// Insering 0 or 1 will break the system.
constant function CapturePercentEventBase takes nothing returns integer
return 25
endfunction
//Is used in RegisterCapturePointSimple
constant function CapturePointDefaultStyle takes nothing returns integer
return 0
endfunction
constant function CapturePointDefaultRange takes nothing returns real
return 200.0
endfunction
constant function CapturePointDefaultInfluence takes nothing returns integer
return 30
endfunction
//Is used in RegisterCapturePointSimple & RegisterCapturePoint
constant function CaptureBarDefaultX_Offset takes nothing returns real
return 0.0
endfunction
constant function CaptureBarDefaultY_Offset takes nothing returns real
return 50.0
endfunction
constant function CaptureBarDefaultZ_Offset takes nothing returns real
return 300.0
endfunction
constant function CaptureBarDefaultScale takes nothing returns real
return 3.0
endfunction
//How long is one Interval of Capture, The time to capture a CapturePoint is CaptureTimerInterval*Influence (*2, if Controled by foe)
//Capture Points first have to be neutralised
constant function CaptureTimerInterval takes nothing returns real
return 0.5
endfunction
//=========================================================================================================
//Hashtable Indexes:
//=========================================================================================================
//Handle
function CapturePointHashIndex_Group takes nothing returns integer
return 0
endfunction
function CapturePointHashIndex_LeadingPlayer takes nothing returns integer
return 1
endfunction
function CapturePointHashIndex_Bar takes nothing returns integer
return 2
endfunction
//Real
function CapturePointHashIndex_Range takes nothing returns integer
return 0
endfunction
function CapturePointHashIndex_XOffset takes nothing returns integer
return 1
endfunction
function CapturePointHashIndex_YOffset takes nothing returns integer
return 2
endfunction
function CapturePointHashIndex_ZOffset takes nothing returns integer
return 3
endfunction
//Int
function CapturePointHashIndex_Influence takes nothing returns integer
return 0
endfunction
function CapturePointHashIndex_InfluenceNeed takes nothing returns integer
return 1
endfunction
function CapturePointHashIndex_Style takes nothing returns integer
return 2
endfunction
//Boolean
function CapturePointHashIndex_UseOffset takes nothing returns integer
return 0
endfunction
//======================================================================================================
//System Code Start
//======================================================================================================
function CapturePointCreateBar takes unit u, real x, real y, real z, real scale returns nothing
local integer cpId = GetHandleId(u)
local player owner = GetOwningPlayer(u)
local effect bar = AddSpecialEffect(udg_CapturePointBarType, GetUnitX(u)+x, GetUnitY(u)+y)
call BlzSetSpecialEffectTimeScale(bar, 0) //Disalbe AutoAnimation
call BlzSetSpecialEffectTime(bar, 0)
call BlzSetSpecialEffectScale(bar, scale)
call BlzSetSpecialEffectHeight(bar, GetUnitFlyHeight(u) + z + BlzGetLocalUnitZ(u))
call SaveEffectHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Bar(), bar)
if x != CaptureBarDefaultX_Offset() or y != CaptureBarDefaultY_Offset() or z != CaptureBarDefaultZ_Offset() then
call SaveBoolean(udg_CapturePointHash,cpId,CapturePointHashIndex_UseOffset(),true)
call SaveReal(udg_CapturePointHash,cpId,CapturePointHashIndex_XOffset(),x)
call SaveReal(udg_CapturePointHash,cpId,CapturePointHashIndex_YOffset(),y)
call SaveReal(udg_CapturePointHash,cpId,CapturePointHashIndex_ZOffset(),z)
endif
if owner != Player(PLAYER_NEUTRAL_PASSIVE) then
call BlzSetSpecialEffectTime(bar, 1)
call BlzSetSpecialEffectColorByPlayer(bar, owner)
endif
set bar = null
set owner = null
endfunction
function CapturePointSetupData takes unit u, real range, integer influence, integer style returns boolean
local integer cpId = GetHandleId(u)
local player owner = GetOwningPlayer(u)
if IsUnitInGroup( u, udg_CapturePoints) then
return false
endif
call RegisterUnitWithinRangeSuper(u, range, true, udg_CapturePointDefaultFilter, gg_trg_CapturePoint, 0, false)
call GroupAddUnit(udg_CapturePoints, u)
call SaveGroupHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Group(), CreateGroup() )
call SavePlayerHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_LeadingPlayer(),owner)
call SaveReal(udg_CapturePointHash,cpId,CapturePointHashIndex_Range(),range)
call SaveInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_InfluenceNeed(),influence)
//Start with Max Influence, if Controled already
if owner != Player(PLAYER_NEUTRAL_PASSIVE) then
call SaveInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_Influence(),influence)
endif
call SaveInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_Style(),style)
set owner = null
return true
endfunction
//Inser a Unit as Captureable Capture Unit, Range is the distance from which the unit can be captured,
//Influence * CaptureTimerInterval() time in seconds, style defines under which situation influences changes
//Uses more arguments to define x/y/z/facing indiviudal
function RegisterCapturePointSpecific takes unit u, real range, integer influence, integer style, real x, real y, real z, real scale returns boolean
if CapturePointSetupData(u, range, influence, style) then
call CapturePointCreateBar(u, x, y, z, scale)
return true
else
return false
endif
endfunction
function RegisterCapturePoint takes unit u, real range, integer influence, integer style returns boolean
if CapturePointSetupData(u, range, influence, style) then
call CapturePointCreateBar(u, CaptureBarDefaultX_Offset(), CaptureBarDefaultY_Offset(), CaptureBarDefaultZ_Offset(), CaptureBarDefaultScale())
return true
else
return false
endif
endfunction
function RegisterCapturePointSimple takes unit u returns boolean
return RegisterCapturePoint( u, CapturePointDefaultRange(), CapturePointDefaultInfluence(), CapturePointDefaultStyle())
endfunction
//Makes a Capture Point uncapturable, second argument asks if it should be removed from the "Unit within"-System too.
//Removes the Bar Unit from the game.
function DeRegisterCapturePoint takes unit u, boolean DeregisterUnitWithin returns boolean
local integer cpId = GetHandleId(u)
if DeregisterUnitWithin then
call DeRegisterUnitWithinRangeUnit(u)
endif
call GroupRemoveUnit(udg_CapturePoints, u)
call DestroyGroup(LoadGroupHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Group()) )
call BlzSetSpecialEffectTimeScale(LoadEffectHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Bar()), 10)
call DestroyEffect(LoadEffectHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Bar()))
call FlushChildHashtable(udg_CapturePointHash, cpId)
return true
endfunction
//This catches the WithingRangeEvent = -1
// aka Removed/Killed/Replaced
//We do not clean in WithinRange cause it does it onitself if this event is thrown.
function CapturePointAutoClean takes nothing returns nothing
call DeRegisterCapturePoint (udg_WithinRangeUnit,false)
endfunction
function CapturePointGetOwner takes player p returns player
local integer teamNr = GetPlayerTeam(p)
if GetPlayerId(p) <= GetBJMaxPlayers() and udg_CapturePointTeamLeader[teamNr] != null then
//swap owner to the Team Leader
return udg_CapturePointTeamLeader[teamNr]
else
return p
endif
endfunction
//Is Called with the Custom-Event UnitWithin = 1.
function CapturePointEnter takes nothing returns nothing
local integer cpId = GetHandleId(udg_WithinRangeUnit)
local player owner = GetOwningPlayer(udg_WithinRangeEnteringUnit)
local group g = LoadGroupHandle( udg_CapturePointHash,cpId,CapturePointHashIndex_Group())
if IsUnitInGroup(udg_WithinRangeEnteringUnit, g) then
set owner = null
set g = null
return //Do not allow twice
endif
call GroupAddUnit(g ,udg_WithinRangeEnteringUnit)
//Become the Leading Player if current Leadingplayer is Neutral_Passive.
if LoadPlayerHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_LeadingPlayer()) == Player(PLAYER_NEUTRAL_PASSIVE) then
//this team has a Leader?
set owner = CapturePointGetOwner(owner)
call SavePlayerHandle(udg_CapturePointHash, cpId, CapturePointHashIndex_LeadingPlayer(), owner)
call BlzSetSpecialEffectColorByPlayer(LoadEffectHandle(udg_CapturePointHash, cpId,CapturePointHashIndex_Bar()), owner)
endif
//Event Entered
set udg_CapturePointEventMovedUnit = udg_WithinRangeEnteringUnit
set udg_CapturePointEventUnit = udg_WithinRangeUnit
set udg_CapturePointEvent = 1
set udg_CapturePointEvent = 0
set owner = null
set g = null
endfunction
//Will Return influenceChange the result will be in Bounds of 0 to Max depending on Style regarding foes/allies.
function CaptureGetInfluenceChange takes integer influence, integer influenceMax, integer allies, integer foes, integer style returns integer
if style == 0 then
if allies != 0 and foes == 0 then //Only Allies?
if influence == influenceMax then //Exceed Limit?
return 0 //It execeeds.
else
return 1
endif
endif
if allies == 0 and foes != 0 then //Only Foes?
if influence == 0 then //Exceed Limit?
return 0 //It execeeds.
else
return -1
endif
endif
endif
if style == 1 then
if allies != 0 and foes == 0 then //Only Allies?
if influence == influenceMax then
return 0
else
return 1
endif
else
if allies == 0 then //No allies?
if influence == 0 then
return 0
else
return -1
endif
else
return 0 //There are Allies and Foes, do nothing!
endif
endif
endif
if style == 2 then
if allies > foes then //More Allies?
if influence == influenceMax then
return 0
else
return 1
endif
endif
if allies < foes then //Less Allies?
if influence == 0 then
return 0
else
return -1
endif
endif
endif
if style == 3 then
if allies > foes then
if influence == influenceMax then
return 0
else
return 1
endif
endif
if allies < foes or allies == 0 then //Less Allies or none Ally?
if influence == 0 then
return 0
else
return -1
endif
endif
endif
if style == 4 then
if influence + (allies - foes) < influenceMax then //New Influence below Upper Limit?
if influence + (allies - foes) > 0 then //New Influence above lower Limit?
return (allies - foes)
else
return -influence //Below Lower Limit Reduce by current Influence, to 0 it!
endif
else
return influenceMax - influence //Above Upper Limit Return Missing to Upper Limit!
endif
endif
if style == 5 then
if allies == 0 and foes == 0 then //No Influncing Unit -> Lose 1 Influence?
if influence == 0 then
return 0
else
return -1
endif
else //Style 4
if influence + (allies - foes) < influenceMax then
if influence + (allies - foes) > 0 then
return (allies - foes)
else
return -influence
endif
else
return influenceMax - influence
endif
endif
endif
if style == 6 then
if allies == 0 then
if influence == 0 then
return 0
else
return -1
endif
elseif foes == 0 then
if influence + allies < influenceMax then //New Influence below Upper Limit?
if influence + allies > 0 then //New Influence above lower Limit?
return allies
else
return -influence //Below Lower Limit Reduce by current Influence, to 0 it!
endif
else
return influenceMax - influence //Above Upper Limit Return Missing to Upper Limit!
endif
elseif foes != 0 then
return 0
endif
endif
return 0
endfunction
//Checks all x times of CapturePercentEventBase() and throws the first found Event.
//Throws negative Events if Influence fall and a positive if Influence Rises.
// udg_CapturePointEventUnit CapturePoint;
// udg_CapturePointEventPlayer = leadingPlayer -> Rising = the one will get the Point; falling the one who is losing this Point
function CapturePointThrowEvent takes integer oldPercent, integer newPercent, unit cp, player p returns boolean
local integer oldStep = oldPercent / CapturePercentEventBase()
local integer newStep = newPercent / CapturePercentEventBase()
if oldStep != newStep then //Step changed?
set udg_CapturePointEventUnit = cp
set udg_CapturePointEventPlayer = p
if oldStep < newStep then //Rise?
set udg_CapturePointEvent = newStep * CapturePercentEventBase()
else //Fallen below newstep + 1 (old => 8 new = 6 you enter 60% realm -> lose the 70% Influence)
set udg_CapturePointEvent = -(newStep+1) * CapturePercentEventBase()
endif
set udg_CapturePointEvent = 0
return true
endif
return false
endfunction
//Group Enumeration for all CapturePoints, Changes Influence, Ownership and Bar Color.
function CapturePointsLoop takes nothing returns nothing
local unit cp = GetEnumUnit()
local unit u
local real oldPercent
local real newPercent
local integer cpId = GetHandleId(cp)
local player leadingPlayer = LoadPlayerHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_LeadingPlayer())
local group influencingUnits = LoadGroupHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Group())
local integer index = 0
local integer allies = 0
local integer foes = 0
local real range = LoadReal(udg_CapturePointHash,cpId,CapturePointHashIndex_Range())
local integer influence = LoadInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_Influence())
local integer influenceMax = LoadInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_InfluenceNeed())
local integer array playerInfluence
local integer playerId
local integer playerIdMax = bj_MAX_PLAYER_SLOTS
local integer influenceGain
local integer style = LoadInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_Style())
local effect bar = LoadEffectHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Bar())
local integer influencePower
set playerInfluence[playerIdMax] = -1
//call GroupClear(udg_CapturePoint_TempGroup)
loop
set u = FirstOfGroup(influencingUnits)
exitwhen u == null
call GroupRemoveUnit(influencingUnits, u)
//Is Unit still Influencing?
if not IsUnitType(u, UNIT_TYPE_DEAD) and IsUnitInRange (u, cp, range) and GetUnitTypeId(u)!=0 then
call GroupAddUnit(udg_CapturePoint_TempGroup, u)
if not (IsUnitPaused(u)) and not (IsUnitHidden(u)) then //can it influence now?
//Save Influence of this Player
set playerId = GetPlayerId( GetOwningPlayer (u))
set influencePower = Captureinfluence(u)
set playerInfluence[playerId] = playerInfluence[playerId] + influencePower
if playerInfluence[playerId] > playerInfluence[playerIdMax] then
set playerIdMax = playerId
endif
//Count allies/Foes.
if IsUnitAlly (u, leadingPlayer) then
set allies = allies + influencePower
else
set foes = foes + influencePower
endif
endif
else
//This unit is no Influencer for this point anymore.
//Event Unit stops Influenceing
set udg_CapturePointEventUnit = cp
set udg_CapturePointEventMovedUnit = u
set udg_CapturePointEvent = -1
set udg_CapturePointEvent = 0
endif
endloop
//Refill
loop
set u = FirstOfGroup(udg_CapturePoint_TempGroup)
exitwhen u == null
call GroupRemoveUnit(udg_CapturePoint_TempGroup, u)
call GroupAddUnit(influencingUnits,u)
endloop
set influenceGain = CaptureGetInfluenceChange(influence,influenceMax, allies, foes, style)
//Is there InfluenceGain?
if influenceGain != 0 then
set oldPercent = I2R(influence) / influenceMax
set influence = influence + influenceGain
call SaveInteger(udg_CapturePointHash,cpId,CapturePointHashIndex_Influence(),influence)
set newPercent = I2R(influence) / influenceMax
call BlzSetSpecialEffectTime(bar, newPercent)
//Call Influence %-Event?
if CaptureUsePercentEvents() then
call CapturePointThrowEvent(R2I(oldPercent*100),R2I(newPercent*100),cp,leadingPlayer)
endif
endif
if influenceGain != 0 or not IsUnitOwnedByPlayer (cp, leadingPlayer) then
//Neutralise the Point?
if influence == 0 then
//ControlLose with units?
if FirstOfGroup(influencingUnits) != null then
set leadingPlayer = Player(playerIdMax)
call BlzSetSpecialEffectColorByPlayer(bar, leadingPlayer)
else
set leadingPlayer = Player(PLAYER_NEUTRAL_PASSIVE)
call BlzSetSpecialEffectColorByPlayer(bar, leadingPlayer)
endif
call SetUnitOwner (cp, Player(PLAYER_NEUTRAL_PASSIVE), true)
call SavePlayerHandle(udg_CapturePointHash, cpId, CapturePointHashIndex_LeadingPlayer(), CapturePointGetOwner(leadingPlayer))
call BlzSetSpecialEffectTime(bar, 0)
else
//Leading Player captures it?
if influence == influenceMax and not IsUnitOwnedByPlayer (cp, leadingPlayer) then
call SetUnitOwner (cp, leadingPlayer, true)
//Added 1.4a to support changing the ownership of the captured unit inside the change owner event
set leadingPlayer = GetOwningPlayer(cp)
call SavePlayerHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_LeadingPlayer(),leadingPlayer)
endif
call BlzSetSpecialEffectColorByPlayer(bar, leadingPlayer)
endif
endif
//Clear Unit stack
set leadingPlayer = null
set cp = null
set bar = null
set influencingUnits = null
endfunction
//Group Enumeration for all CapturePoints repos Bars
function CapturePointsReposBar takes nothing returns nothing
local unit cp = GetEnumUnit()
local integer cpId = GetHandleId(cp)
local effect bar =LoadEffectHandle(udg_CapturePointHash,cpId,CapturePointHashIndex_Bar())
//use Speciifc Offset?
if LoadBoolean(udg_CapturePointHash,cpId,CapturePointHashIndex_UseOffset()) then
call BlzSetSpecialEffectPosition(bar, GetUnitX(cp) + LoadReal(udg_CapturePointHash,cpId,CapturePointHashIndex_XOffset()), GetUnitY(cp) + LoadReal(udg_CapturePointHash,cpId,CapturePointHashIndex_YOffset()), GetUnitFlyHeight(cp) + LoadReal(udg_CapturePointHash,cpId,CapturePointHashIndex_ZOffset()) )
else
//Used Default
call BlzSetSpecialEffectPosition(bar, GetUnitX(cp) + CaptureBarDefaultX_Offset(), GetUnitY(cp) + CaptureBarDefaultY_Offset(), GetUnitFlyHeight(cp) + BlzGetLocalUnitZ(cp) + CaptureBarDefaultZ_Offset() )
endif
set cp = null
set bar = null
endfunction
function CaptureTimerReposBar takes nothing returns nothing
call ForGroup (udg_CapturePoints, function CapturePointsReposBar)
endfunction
function CaptureTimerInfluence takes nothing returns nothing
call ForGroup (udg_CapturePoints, function CapturePointsLoop)
endfunction
function CapturePointStartTimer takes nothing returns nothing
call TimerStart(udg_CapturePointTimer[0], CaptureTimerInterval(), true, function CaptureTimerInfluence)
call TimerStart(udg_CapturePointTimer[1], 1.0/32.0, true, function CaptureTimerReposBar)
endfunction
function CapturePointStopTimer takes nothing returns nothing
call PauseTimer(udg_CapturePointTimer[0])
call PauseTimer(udg_CapturePointTimer[1])
endfunction
//Is Executed if you run CapturePoint the first time.
//Start Catching Events thrown by UnitWithinRange
//Start timer[0][1]
function CaptureInit takes nothing returns nothing
//Auto deregister on death/Killed/Removed
set udg_CapturePointDefaultFilter = Condition( function CapturePointDefaultFiler)
set udg_CapturePointAutoDeregister = CreateTrigger()
call TriggerRegisterVariableEvent( udg_CapturePointAutoDeregister, "udg_WithinRangeEvent", EQUAL, -1 )
call TriggerAddAction(udg_CapturePointAutoDeregister,function CapturePointAutoClean)
//enable Capturing
call TriggerClearActions(gg_trg_CapturePoint)
call TriggerRegisterVariableEvent( gg_trg_CapturePoint, "udg_WithinRangeEvent", EQUAL, 1 )
call TriggerAddAction(gg_trg_CapturePoint,function CapturePointEnter)
call CapturePointStartTimer()
set udg_CapturePointHash = InitHashtable()
set udg_CapturePoint_Register_Range = CapturePointDefaultRange()
set udg_CapturePoint_Register_Influ = CapturePointDefaultInfluence()
set udg_CapturePoint_Register_Style = CapturePointDefaultStyle()
endfunction
function CaptureRegisterGUI takes nothing returns nothing
if udg_CapturePoint_Register_Range <= 0 then
set udg_CapturePoint_Register_Range = CapturePointDefaultRange()
endif
call RegisterCapturePoint(udg_CapturePoint_Register_Unit, udg_CapturePoint_Register_Range, udg_CapturePoint_Register_Influ, udg_CapturePoint_Register_Style)
set udg_CapturePoint_Register_Range = CapturePointDefaultRange()
set udg_CapturePoint_Register_Influ = CapturePointDefaultInfluence()
set udg_CapturePoint_Register_Style = CapturePointDefaultStyle()
endfunction
function CaptureDeRegisterGUI takes nothing returns nothing
call DeRegisterCapturePoint(udg_CapturePoint_Register_Unit, true)
endfunction
//===========================================================================
function InitTrig_CapturePoint takes nothing returns nothing
set gg_trg_CapturePoint = CreateTrigger()
call TriggerAddAction(gg_trg_CapturePoint, function CaptureInit)
set udg_CapturePoint_DeRegister = CreateTrigger()
set udg_CapturePoint_Register = CreateTrigger()
call TriggerAddAction(udg_CapturePoint_DeRegister, function CaptureDeRegisterGUI)
call TriggerAddAction(udg_CapturePoint_Register, function CaptureRegisterGUI)
endfunction
//==========================================================================
// Dark Dragon Library Code v1.3
//
// * Made on Warcraft III v1.30.4
//
// Installation:
//
// 1) Export instantdummy.mdx from this map and import it to your map, leave path at "war3mapImported/instantdummy.mdx"
// 2) Copy this trigger to your map, save your map and then change below line "// external ... " or copy "DD Dummy" and paste it in your map
// 3) Copy and paste "Unit Chill" ability from this map to your map
// 4) Match the rawcodes below to your map or use same ones as below
//
// Credits:
// ('Vexorian' - dummy.mdx)
//============================================================================
// *** Change "// external" to "//! external", save your map, close map, change back from "//!" to "//" and save map again.
// *** This will create dummy in your map
//
// ==================================
// external ObjectMerger w3u ushd dumy uabi "Aloc,Amrf" uble 0 ucbs 0 ucpt 0 umxp 0 umxr 0 umdl "war3mapImported\instantdummy.mdx" ushu "None" umvh 0 umvs 1 umas 1 umis 1 ucol 0 ufoo 0 uhom 1 umpi 10000 umpm 10000 usid 1 usin 1 unam "DD Dummy"
// ==================================
//! zinc
library DDLib requires optional TimerUtils, optional GroupUtils
{
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// *** Lib constants ***
public {
// ----------------------------------------------------------------------
// * Start modify/match rawcodes to your map
constant integer DD_DUMMYCODE = 'ndum';
constant integer DD_ABILITY_CROWN_FORM = 'Amrf';
constant integer DD_CHILL = 'Achl';
constant integer DD_CHILL_BUFF = 'Bfro';
// * End modify
// ----------------------------------------------------------------------
constant integer p_null = (0x0);
constant real DD_INTERVAL = .017;
// map min and max coords
real DDMinX = 0.;
real DDMinY = 0.;
real DDMaxX = 0.;
real DDMaxY = 0.;
}
private {
constant integer HARVEST_ID = 'Ahrl';
constant real TRIGGER_REFRESH_RATE = (60.)*3.; /// damage detection trigger
unit TreeChecker = null;
trigger TempTrig = null;
integer NTrig = 0;
trigger DmgTrig[];
p_real EnumVec = p_null;
boolexpr EnumFilter = null;
sound ErrorSound = null;
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// * types
public {
// *** pointer to list of data ***
type p_integer extends integer[8];
type p_real extends real[8];
type p_unit extends unit[8];
function H2ID(handle h) -> integer {
return GetHandleId(h) - 0x100000;
}
function New_pInteger(integer i) -> p_integer
{ p_integer p = p_integer.create(); p[0] = i; return p; }
function New_pReal(real r) -> p_real
{ p_real p = p_real.create(); p[0] = r; return p; }
function New_pUnit(unit u) -> p_unit
{ p_unit p = p_unit.create(); p[0] = u; return p; }
function pVector(real x, real y, real z) -> p_real {
p_real v = p_real.create();
v[0] = x; v[1] = y; v[2] = z;
return v;
}
// --------------------------------------------------------------------------------------
function DDMsg(string str) {
DisplayTimedTextFromPlayer(GetLocalPlayer(), 0., 0., 30., str);
}
// --------------------------------------------------------------------------------------
function DisplayErrorMsgPlayer(player p, real dur, string msg) {
if (GetLocalPlayer() == p) {
StartSound(ErrorSound);
DisplayTimedTextFromPlayer(p, 0., 0., dur, "|cffffcc00"+ msg +"|r");
}
}
}
// -----------------------------------------------------------------------
// -> ***** private globals *****
// -----------------------------------------------------------------------
private {
location TempLoc = Location(0., 0.);
timer TimerStack[];
integer TimN = 0;
group GroupStack[];
integer GrpN = 0;
unit DummyStack[];
integer DumN = 0;
integer TimTicks[];
integer TimData[];
timer TimTim1[];
timer TimTim2[];
integer UnitStackData = 0;
unit UnitStack[];
integer US_N = 0;
public hashtable DDHT = InitHashtable();
}
// -----------------------------------------------------------------------
public {
// *** Global funcs
function Pw_2(real x) -> real {
return x*x;
}
function DDHypot(real x, real y) -> real {
return (x*x) + (y*y);
}
function DDTerrZ(real x, real y) -> real {
MoveLocation(TempLoc, x, y);
return GetLocationZ(TempLoc);
}
function DDWidgetTerrZ(widget w) -> real {
MoveLocation(TempLoc, GetWidgetX(w), GetWidgetY(w));
return GetLocationZ(TempLoc);
}
function DDEffectTerrZ(effect e) -> real {
MoveLocation(TempLoc, BlzGetLocalSpecialEffectX(e), BlzGetLocalSpecialEffectY(e));
return GetLocationZ(TempLoc);
}
function DDGetUnitZ(unit u) -> real {
return BlzGetUnitZ(u) + GetUnitFlyHeight(u);
}
// =================================================================
// *** Save Handle data ****
// =================================================================
function DDSet(handle h, integer id, integer val) {
SaveInteger(DDHT, id+1, GetHandleId(h), val);
}
function DDGet(handle h, integer id) -> integer {
return LoadInteger(DDHT, id+1, GetHandleId(h));
}
function DDHas(handle h, integer id) -> boolean {
return HaveSavedInteger(DDHT, id+1, GetHandleId(h));
}
function DDFlush(integer id) {
FlushChildHashtable(DDHT, id+1);
}
// =================================================================
// *** Timer Handling ****
// =================================================================
// -> check if timer is recycled
function DDIsTimRecycled(timer t) -> boolean {
integer i;
for(i=TimN-01; i >= 00; i-=01)
if (TimerStack[i] == t)
return true;
return false;
}
// -> Load timer for recycling
function DDLoadTim() -> timer {
static if (LIBRARY_TimerUtils) { return NewTimer(); }
else {
if (TimN > 0) {
TimN -= 1;
return TimerStack[TimN];
}
return CreateTimer();
}
}
// -> recycle loaded timer
function DDRecycleTim(timer t) {
static if (LIBRARY_TimerUtils) { ReleaseTimer(t); }
else {
static if (DEBUG_MODE)
if (DDIsTimRecycled(t)) {
DDMsg("Multiple recycle of timer!");
return;
}
TimerStack[TimN] = t;
TimN += 1;
}
}
// ** Get data stored on expired timer
function DDTimData() -> integer {
return TimData[H2ID(GetExpiredTimer())];
}
// *** Custom timer tick
function DDCTimTick(timer t) -> integer {
return TimTicks[H2ID(t)];
}
// *** Gets current tick and adds next one ***
function DDTimTick() -> integer {
integer id = H2ID(GetExpiredTimer());
TimTicks[id] += 01;
return TimTicks[id];
}
// ** start timer with data storage
function DDStartTim(real secs, boolean looping, integer pdata, code func) -> timer {
timer t = DDLoadTim();
TimData[H2ID(t)] = pdata;
TimerStart(t, secs, looping, func);
return t;
}
// ** start timer with data storage, and launches it instantly
function DDStartTimInst(real secs, boolean looping, integer pdata, code func) -> timer {
timer t1 = DDLoadTim(), t2 = DDLoadTim(), t3 = DDLoadTim();
TimData[H2ID(t2)] = pdata;
TimerStart(t2, 0., false, func);
TimTim1[H2ID(t3)] = t1;
TimTim2[H2ID(t3)] = t2;
TimerStart(t3, .005, false, function() {
timer t = GetExpiredTimer();
integer id = H2ID(t);
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
t = TimTim2[id];
if (DDIsTimRecycled(t))
t = TimTim1[id];
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
});
TimData[H2ID(t1)] = pdata;
TimerStart(t1, secs, looping, func);
return t1;
}
// *** Quit expired timer ***
function DDQuitTim() {
timer t = GetExpiredTimer();
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
}
function DDQuitTimEx(timer t) {
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
}
// =================================================================
// *** Group Handling ****
// =================================================================
// -> Load timer for recycling
function DDLoadGroup() -> group {
static if (LIBRARY_GroupUtils) { return NewGroup(); }
else {
if (GrpN > 0) {
GrpN -= 1;
return GroupStack[GrpN];
}
return CreateGroup();
}
}
// -> Recycle group
function DDRecycleGroup(group g) {
static if (LIBRARY_GroupUtils) { ReleaseGroup(g); }
else {
GroupClear(g);
GroupStack[GrpN] = g;
GrpN += 1;
}
}
// --------------------------------------------------------
// -- Quick filter area
private integer GroupFilterData = 00;
function DDGroupFilterArea(real x, real y, real radius, integer data, code func) {
group g = DDLoadGroup();
GroupFilterData = data;
GroupEnumUnitsInRange(g, x, y, radius, Filter(func));
DDRecycleGroup(g);
}
// --------------------------------------------------------
// -- Quick filter rect
function DDGroupFilterRect(rect r, integer data, code func) {
group g = DDLoadGroup();
GroupFilterData = data;
GroupEnumUnitsInRect(g, r, Filter(func));
DDRecycleGroup(g);
}
function DDGFilterData() -> integer {
return GroupFilterData;
}
function DDGFilterDataSet(integer data) {
GroupFilterData = data;
}
// --------------------------------------------------------
// *** Filtrates and fills units in to memory
function DDGroupFillMemArea(real x, real y, real radius, integer data, code filter) {
group g = DDLoadGroup();
boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
UnitStack[US_N] = GetFilterUnit();
US_N += 1;
return false;
}));
US_N = 0;
UnitStack[0] = null;
UnitStackData = data;
GroupEnumUnitsInRange(g, x, y, radius, exp);
DDRecycleGroup(g);
DestroyBoolExpr(exp);
exp = null;
}
function DDGroupFillMemRect(rect r, integer data, code filter) {
group g = DDLoadGroup();
boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
UnitStack[US_N] = GetFilterUnit();
US_N += 1;
return false;
}));
US_N = 0;
UnitStack[0] = null;
UnitStackData = data;
GroupEnumUnitsInRect(g, r, exp);
DDRecycleGroup(g);
DestroyBoolExpr(exp);
exp = null;
}
function DDMemUnitN() -> integer { return US_N; }
function DDMemUnitData() -> integer { return UnitStackData; }
function DDMemUnit(integer index) -> unit {
if (US_N == 0) return null;
debug {
if (index < 0) {
BJDebugMsg("DDMemUnit: index less than 0");
index = 0;
} else if (index >= US_N) {
BJDebugMsg("DDMemUnit: index greater than units alloc size");
index = 0;
}
}
return UnitStack[index];
}
// --------------------------------------------------------
// --------------------------------------------------------
// ***
// =================================================================
// *** Dummy Handling ****
// =================================================================
// -> Load dummy for recycling
function DDLoadDummy() -> unit {
if (DumN > 0) {
DumN -= 1;
PauseUnit(DummyStack[DumN], false);
return DummyStack[DumN];
}
return CreateUnit(Player(0xF), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
}
// *** prepares/setups dummy for spell casting
function DDLoadSpellDummy(player owner, real x, real y, integer abil, integer abilLevel) -> unit {
unit dummy = DDLoadDummy();
SetUnitOwner(dummy, owner, false);
SetUnitX(dummy, x);
SetUnitY(dummy, y);
if (abil != p_null) {
UnitAddAbility(dummy, abil);
SetUnitAbilityLevel(dummy, abil, abilLevel);
}
return dummy;
}
// -> Recycle dummy
function DDRecycleDummy(unit u) {
PauseUnit(u, true);
DummyStack[DumN] = u;
DumN += 1;
}
// -> Recycle dummy timed
function DDRecycleDummyTimed(unit u, real secs) {
DDStartTim(secs, false, New_pUnit(u), function() {
DDRecycleDummy(p_unit(DDTimData())[0]);
p_unit(DDTimData()).destroy();
DDQuitTim();
});
}
// *** shares vision for timed amount, usually for dummy casting
function DDUnitShareVisionTimed(unit u, player toP, real secs) {
p_integer pi = p_integer.create();
pi[0] = New_pUnit(u);
pi[1] = GetPlayerId(toP);
UnitShareVision(u, toP, true);
DDStartTim(secs, false, pi, function() {
p_integer pi = DDTimData();
UnitShareVision(p_unit(pi[0])[0], Player(pi[1]), false);
p_unit(pi[0])[0] = null;
p_unit(pi[0]).destroy();
pi.destroy();
DDQuitTim();
});
}
// *** Remove ability timed ***
private struct uratimed {
private {
unit u;
integer abil;
}
static method create(unit whichUnit, integer id, real time) -> uratimed {
thistype this = allocate();
u = whichUnit;
abil = id;
DDStartTim(time, false, this, function() {
thistype this = DDTimData();
UnitRemoveAbility(u, abil);
DDQuitTim();
deallocate();
});
return 0;
}
}
function DDRemoveAbilityTimed(unit u, integer abil, real secs) { uratimed.create(u, abil, secs); }
function DDSpellDamage(unit u, unit v, real dmg) {
real life = GetWidgetLife(v);
real dmgfactor = 1.;
if (IsUnitType(v, UNIT_TYPE_HERO)) {
if (UnitHasItemOfTypeBJ(v, 'brac'))
dmgfactor = .5;
else
dmgfactor = .75;
}
if (life > dmg*dmgfactor) {
SetWidgetLife(v, life-(dmg*dmgfactor));
} else
UnitDamageTarget(u, v, 99999., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null);
}
// -------------------------------------------------------------------------------------
// *** Chills target unit
private struct chill {
unit u, dmy;
real dur;
static chill Data[];
//static key CHILL_KEY;
}
function DDUnitChill(player p, unit u, real dur) -> boolean {
//chill c = DDGet(u, chill.CHILL_KEY);
chill c = chill.Data[H2ID(u)];
unit d;
real rad;
if (c == p_null) {
c = chill.create();
c.u = u; c.dur = dur;
chill.Data[H2ID(u)] = c;
//DDSet(u, chill.CHILL_KEY, c);
d = DDLoadDummy();
c.dmy = d;
rad = GetUnitFacing(d) * bj_DEGTORAD;
SetUnitOwner(d, p, false);
UnitAddAbility(d, DD_CHILL);
SetUnitX(d, GetUnitX(u) - 20.*Cos(rad));
SetUnitY(d, GetUnitY(u) - 20.*Sin(rad));
if (IssueTargetOrder(d, "frostnova", u)) {
DDStartTim(.1, true, c, function() {
chill c = DDTimData();
c.dur -= .1;
if (c.dur <= 0. || GetUnitAbilityLevel(c.u, DD_CHILL_BUFF) == 00) {
UnitRemoveAbility(c.u, DD_CHILL_BUFF);
UnitRemoveAbility(c.dmy, DD_CHILL);
DDRecycleDummy(c.dmy);
chill.Data[H2ID(c.u)] = p_null;
//DDSet(c.u, chill.CHILL_KEY, p_null);
c.u = null;
c.destroy();
DDQuitTim();
}
});
return true;
}
return false;
}
c.dur = dur;
return true;
}
// ------------------------------------------------------------------------------------------------
struct fade {
unit u;
real trans;
real rate, e_trans, dur;
static constant real INTERVAL = .1;
static method create(unit u, real dur, real s_trans, real e_trans) -> fade {
fade this = allocate();
this.u = u;
this.trans = s_trans;
this.rate = ((e_trans-s_trans)/dur)*fade.INTERVAL;
this.e_trans = e_trans;
this.dur = dur;
return this;
}
}
// *** Fades unit over time ***
public function DDFadeUnit(unit u, integer from_alpha, integer to_alpha, real duration) {
fade f = fade.create(u,
duration,
from_alpha/2.55,
to_alpha/2.55);
SetUnitVertexColor(u, 255, 255, 255, from_alpha);
// --- Start thread ---
DDStartTim(fade.INTERVAL, true, f, function() {
fade f = DDTimData();
f.trans += f.rate;
f.dur -= fade.INTERVAL;
SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.trans*2.55));
if (f.dur < 0.) {
SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.e_trans*2.55));
f.u = null;
f.destroy();
DDQuitTim();
}
});
}
// ------------------------------------------------------------------------------------------------
// Check if unit is invulnerable
function DDIsUnitInvulnerable(unit u) -> boolean {
unit d = DDLoadDummy();
real hp = GetWidgetLife(u);
boolean flag;
UnitDamageTarget(d, u, 1., true, false, null, null, null);
flag = GetWidgetLife(u) == hp;
SetWidgetLife(u, hp);
DDRecycleDummy(d);
return flag;
}
// *** check if unit is ward
function DDIsUnitWard(unit whichUnit) -> boolean {
return GetUnitDefaultMoveSpeed(whichUnit) == 0.;
}
// =================================================================
// *** Effect Handling ****
// =================================================================
// -----------------------------------------------
// *** Define movable effect
struct ddeffect {
private {
effect e;
real fac; // facing angle in radians
real pitch; // pitch in radians
real decay;
static constant real EFFECT_DECAY = 5.;
}
// =========================================================================================
// =========================================================================================
static method create(string mdl, real x, real y, real facRad, real size) -> ddeffect {
ddeffect this = allocate();
this.e = AddSpecialEffect(mdl, x, y);
this.fac = facRad;
BlzSetSpecialEffectRoll(this.e, facRad);
BlzSetSpecialEffectScale(this.e, size);
return this;
}
static method createZ(string mdl, real x, real y, real z, real facRad, real size) -> ddeffect {
ddeffect this = allocate();
this.e = AddSpecialEffect(mdl, x, y);
this.fac = facRad;
BlzSetSpecialEffectRoll(this.e, facRad);
BlzSetSpecialEffectScale(this.e, size);
BlzSetSpecialEffectZ(this.e, z);
return this;
}
// -----------------
method destroy() {
DestroyEffect(this.e);
this.e = null;
deallocate();
}
// *** destroys effect timed
method destroyx(real decayTime) {
DDStartTim(decayTime, false, this, function() {
ddeffect se = DDTimData();
BlzSetSpecialEffectPosition(se.e, DDMaxX, DDMaxY, 0.);
DestroyEffect(se.e);
se.e = null;
se.deallocate();
DDQuitTim();
});
}
// =========================================================================================
// =========================================================================================
method Position(real x, real y) { BlzSetSpecialEffectPosition(this.e, x, y, DDEffectTerrZ(this.e)); }
method PositionZ(real x, real y, real z) { BlzSetSpecialEffectPosition(this.e, x, y, z); }
method operator Z=(real z) { BlzSetSpecialEffectZ(this.e, z); }
method operator X() -> real { return BlzGetLocalSpecialEffectX(this.e); }
method operator Y() -> real { return BlzGetLocalSpecialEffectY(this.e); }
method operator Z() -> real { return BlzGetLocalSpecialEffectZ(this.e); }
method operator WZ() -> real { return DDEffectTerrZ(this.e); }
method operator Height() -> real { return this.Z-this.WZ; }
method operator Facing=(real facRad) { BlzSetSpecialEffectRoll(this.e, facRad); this.fac = facRad; }
method operator Facing() -> real { return this.fac; }
//method operator Pitch=(integer pitch) { SetUnitAnimationByIndex(u, pitch); }
//method Face(widget w) { Facing = Atan2(GetWidgetY(w)-Y, GetWidgetX(w)-X)*bj_RADTODEG; }
}
private type timedeffect extends effect[01];
function DestroyEffectTimed(effect e, real secs) {
timedeffect te = timedeffect.create();
te[00] = e;
DDStartTim(secs, true, te, function() {
timedeffect te = DDTimData();
DestroyEffect(te[00]);
te.destroy();
DDQuitTim();
});
}
}
// ----------------------------------------------------------------------------
// *** Main damage detection function, registers any damage dealt to units ***
public function DDTriggerRegisterAnyUnitDamaged(trigger t) {
DmgTrig[NTrig] = t;
NTrig += 1;
}
function InitDamageDetection() {
code c = function() {
if (TempTrig != null)
DestroyTrigger(TempTrig);
TempTrig = CreateTrigger();
TriggerRegisterEnterRectSimple(TempTrig, bj_mapInitialPlayableArea);
TriggerAddCondition(TempTrig, function() -> boolean {
integer i;
// *** Check if we need to exec triggers or register an unit ***
if (GetTriggerEventId() == EVENT_UNIT_DAMAGED) {
for(i=0; i < NTrig; i+=1)
if (IsTriggerEnabled(DmgTrig[i]))
if (TriggerEvaluate(DmgTrig[i]))
TriggerExecute(DmgTrig[i]);
}
else
// *** Register new unit ***
TriggerRegisterUnitEvent(GetTriggeringTrigger(),
GetTriggerUnit(),
EVENT_UNIT_DAMAGED);
return false;
});
DDGroupFilterRect(bj_mapInitialPlayableArea, 00, function() -> boolean {
TriggerRegisterUnitEvent(TempTrig, GetFilterUnit(), EVENT_UNIT_DAMAGED);
return false;
});
};
trigger t = CreateTrigger();
TriggerAddAction(t, c);
TriggerExecute(t);
DestroyTrigger(t);
TimerStart(CreateTimer(), TRIGGER_REFRESH_RATE, true, c);
t = null;
}
// ---------------------------------------------------------------------------------
// *** Main enum dests in range function ***
public function DDEnumDestsInRange(p_real vec, real radius, boolexpr filter, code pfunc) {
rect r = Rect(vec[0]-radius, vec[1]-radius, vec[0]+radius, vec[1]+radius);
EnumVec[0] = vec[0];
EnumVec[1] = vec[1];
EnumVec[2] = radius;
if (filter != null) filter = And(EnumFilter, filter);
else filter = EnumFilter;
EnumDestructablesInRect(r, filter, pfunc);
if (filter != EnumFilter) { DestroyBoolExpr(filter); filter = null; }
RemoveRect(r);
r = null;
}
function InitEnumDests() {
EnumVec = p_real.create();
EnumFilter = Filter(function() -> boolean {
return Pw_2(EnumVec[0]-GetDestructableX(GetFilterDestructable())) + Pw_2(EnumVec[1]-GetDestructableY(GetFilterDestructable())) < Pw_2(EnumVec[2]);
});
}
// --------------------------------------------------------------------------------------
// *** checks is destruct tree ***
public function DDIsDestructableTree(destructable d) -> boolean {
if (d != null) {
PauseUnit(TreeChecker, false);
if (IssueTargetOrder(TreeChecker, "harvest", d)) {
PauseUnit(TreeChecker, true);
return true;
}
PauseUnit(TreeChecker, true);
}
return false;
}
function InitDestTreeCheck() {
TreeChecker = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
UnitAddAbility(TreeChecker, HARVEST_ID);
PauseUnit(TreeChecker, true);
}
// --------------------------------------------------------------------------------------
public function DDNewTextTagUnit(unit whichUnit, string text, real dur, real red, real green, real blue, real transparency) {
CreateTextTagUnitBJ( text, whichUnit, 0., 11.00, red, green, blue, transparency );
SetTextTagPermanentBJ( bj_lastCreatedTextTag, false );
SetTextTagVelocityBJ( bj_lastCreatedTextTag, 48.00, 90 );
SetTextTagFadepointBJ( bj_lastCreatedTextTag, dur-1.25 );
SetTextTagLifespanBJ( bj_lastCreatedTextTag, dur );
}
// --------------------------------------------------------------------------------------
struct cameranoisedata {
player p[12];
integer n=00;
}
public function DDCameraSetSourceNoiseForPlayers(real x, real y, real mag, real vel, real maxDist, real duration) {
integer i;
real d;
cameranoisedata cnd = cameranoisedata.create();
for (i=00; i < bj_MAX_PLAYERS; i+=01) {
if (GetLocalPlayer() == Player(i)) {
d = SquareRoot( Pw_2(GetCameraTargetPositionX()-x) + Pw_2(GetCameraTargetPositionY()-y) );
if (d < maxDist) {
cnd.p[cnd.n] = Player(i);
CameraSetSourceNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
CameraSetTargetNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
cnd.n += 01;
}
}
}
DDStartTim(duration, false, cnd, function() {
cameranoisedata cnd = DDTimData();
while(cnd.n != 00) {
cnd.n -= 01;
if (GetLocalPlayer() == cnd.p[cnd.n])
CameraSetSourceNoise(0., 0.);
CameraSetTargetNoise(0., 0.);
}
cnd.destroy();
DDQuitTim();
});
}
// --------------------------------------------------------------------------------------
hashtable GenSndTable = null;
public function DDGenericSound(string file, real vol, real x, real y, real mxDist, real pitch) {
integer sh = StringHash(file),
snd_n = LoadInteger(GenSndTable, sh, 04),
i;
sound s = LoadSoundHandle(GenSndTable, sh, snd_n);
real d;
if (s == null) {
s = CreateSound(file, false, false, false, 10, 10, "");
SaveSoundHandle(GenSndTable, sh, snd_n, s);
} else if (GetSoundIsPlaying(s)) {
StopSound(s, false, false);
}
SetSoundPitch(s, pitch);
snd_n += 01;
if (snd_n == 04)
snd_n = 00;
SaveInteger(GenSndTable, sh, 04, snd_n);
// Play sound and shake camera for players within spell cast range
for (i=00; i < bj_MAX_PLAYERS; i+=01) {
if (GetLocalPlayer() == Player(i)) {
d = SquareRoot( DDHypot(GetCameraTargetPositionX()-x, GetCameraTargetPositionY()-y) );
if (d < mxDist) {
SetSoundVolume(s, R2I(vol-d*(vol/mxDist)));
StartSound(s);
}
}
}
}
// ====================================================================
function onInit() {
InitDamageDetection();
InitDestTreeCheck();
InitEnumDests();
DDMinX = GetRectMinX(bj_mapInitialPlayableArea);
DDMinY = GetRectMinY(bj_mapInitialPlayableArea);
DDMaxX = GetRectMaxX(bj_mapInitialPlayableArea);
DDMaxY = GetRectMaxY(bj_mapInitialPlayableArea);
GenSndTable = InitHashtable();
ErrorSound = CreateSound( "Sound\\Interface\\Error.wav", false, false, false, 10, 10, "" );
SetSoundParamsFromLabel( ErrorSound, "InterfaceError" );
SetSoundDuration( ErrorSound, 614 );
SetSoundVolume(ErrorSound, 127);
}
}
//! endzinc
// ===============================================================================
// * System: Item Combine v2
//
// * Installation:
//
// 1) Copy "DD Library" "Load Items", "Item Disassemble" and "Item Combine Core" triggers to your map
// note: dummy unit and other stuff for "DD Library" trigger is not in this map because this system does not need dummies...
// 2) Copy ability "Disassemble" and paste it in your map, unless you use different method of item disassemble
// 3) Export and import "ItemFuse.mdx", "Item_Disassembly.wav" and "Item_Disassemble.mdx" to your map
// Import path: Same as in this map
// If you want to change path or use different effect, change that below
// 4) Make your own recipes in "Load Items" trigger
// 5) Enjoy!
//
// Credits: Magos, Audacity team, Notepad++ team, Vexorian, Blizzard
// ===============================================================================
//! zinc
library DDItemCombineBasic requires DDLib
{
// -------------------------------------------------------
// *** Edit to your own will ***
// * This is effect that will be displayed when items combine/disassemble and attachment point
constant string ITEM_COMBINE_EFFECT = "Units\\NightElf\\Wisp\\WispExplode.mdl";
constant string ITEM_DISASSAMBLE_EFFECT = "Units\\NightElf\\Wisp\\WispExplode.mdl";
constant string ATTACH_POINT = "origin";
// * If you want to use custom sound, setup it below
// * "Sound path", "time in second to play sound after combine is done", "volume" and "pitch" of sound
constant boolean USE_CUSTOM_SOUND = true;
constant real SOUND_MAX_DISTANCE = 3000;
constant string SOUND_FILE = "Sound\\Interface\\ItemReceived.wav";
constant real SOUND_VOL = 90;
constant real SOUND_PITCH = 1;
// * This is disassemble sound
constant string SOUND_FILE_2 = "Sound\\Interface\\GoodJob.wav";
constant real SOUND_VOL_2 = 90;
constant real SOUND_PITCH_2 = 1;
// *** End edit ***
// -------------------------------------------------------
//private keyword Table
// ===========================================================================
// ===========================================================================
sound ItemCombineSound = null;
sound ItemDisassembleSound = null;
integer CType[];
boolean CTypeDisassemble[];
integer ItemN = 0;
// ===========================================================================
// -----------------------------------------------------------------------
// ** Items in CItemType from 1-6 are user items that we need to shift to next memory locations, that is why for this recipe system
// slots lower than 6 are not used, we store items in higher slots
public function NewItemGroup() {
integer i = ItemN*bj_MAX_INVENTORY + 07;
integer h = 01;
if (bj_gameStarted || udg_CItemType[00] == 00)
return;
while(h != 07) {
udg_CItemType[i] = udg_CItemType[h];
udg_CItemType[h] = 00;
h += 01;
i += 01;
}
CType[ItemN] = udg_CItemType[00];
CTypeDisassemble[ItemN] = udg_CItemDisassemble;
udg_CItemType[00] = 00;
ItemN += 01;
//udg_CItemDisassemble = false;
}
// -----------------------------------------------------------------------
// ** Primary public function for item disassemble
public function SlotItemDisassemble(unit u, integer slot) {
item it = UnitItemInSlot(u, slot-01);
integer it_id = GetItemTypeId(it);
real x = GetUnitX(u);
real y = GetUnitY(u);
// *** is slot empty? ***
if (it != null) {
// *** search for registerd item recipe ***
for(slot=00; slot < ItemN; slot+=01) {
// *** found the item ***
if (CType[slot] == it_id) {
// *** Check if allow disassemble by user? ***
if (!CTypeDisassemble[slot]) {
// *** Disassembly not allowed, but null the item
it = null;
return;
}
// *** Do remove and creation jobs ***
RemoveItem(it);
slot = slot*bj_MAX_INVENTORY + 07; // get to first item id of this recipe
while(udg_CItemType[slot] != 00) {
CreateItem(udg_CItemType[slot], x, y);
slot += 01;
}
// -------------------------------------------------------------------------------------
// *** play custom sound and effect ***
// *** If items are disassembled too fast, sound might be playing, so first we have to stop it
DDGenericSound(SOUND_FILE_2, SOUND_VOL_2, x, y, SOUND_MAX_DISTANCE, SOUND_PITCH_2);
DestroyEffect( AddSpecialEffectTarget(ITEM_DISASSAMBLE_EFFECT, u, ATTACH_POINT) );
// *** Item is removed, now null
it = null;
return;
}
}
// *** invalid item, do null anyway ***
it = null;
}
}
// ====================================================================================
function UnitRemoveItemById(unit whichUnit, integer itemId) {
integer i = 00;
item it;
for(i=00; i < bj_MAX_INVENTORY; i+=01) {
it = UnitItemInSlot(whichUnit, i);
if (GetItemTypeId(it) == itemId) {
RemoveItem(it);
break;
}
}
it = null;
}
//===========================================================================
function onInit() {
trigger t = CreateTrigger();
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM);
TriggerAddCondition(t, function() -> boolean {
unit u = GetTriggerUnit();
integer it[];
integer n, i = 07;
integer h;
integer x, y, z;
boolean b = true;
integer hero_item_type[];
static if (USE_CUSTOM_SOUND)
timer t;
// Get hero items
for(x=00; x < bj_MAX_INVENTORY; x+=01)
hero_item_type[x] = GetItemTypeId(UnitItemInSlot(u, x));
for(n=00; n < ItemN; n+=01) {
h = i + bj_MAX_INVENTORY;
x = 00;
it[x] = hero_item_type[x]; x = 01;
it[x] = hero_item_type[x]; x = 02;
it[x] = hero_item_type[x]; x = 03;
it[x] = hero_item_type[x]; x = 04;
it[x] = hero_item_type[x]; x = 05;
it[x] = hero_item_type[x]; x = 06;
//y = 00; // N of items that hero has ()
//z = 00; // N of items needed ()
for(y=00, z=00; i < h; i+=01) {
if (udg_CItemType[i] == 0)
break;
z += 01;
// Does unit contain item n
for(x=00; x < bj_MAX_INVENTORY; x+=01) {
if (it[x] == udg_CItemType[i]) {
// Kick out the item
it[x] = 00;
y += 01;
// And increase by 1
break;
}
}
}
i = h;
if (y == z) {
i -= bj_MAX_INVENTORY;
while(i <= h && udg_CItemType[i] != 00) {
UnitRemoveItemById(u, udg_CItemType[i]);
i += 01;
}
UnitAddItemById(u, CType[n]);
static if (USE_CUSTOM_SOUND)
DDGenericSound(SOUND_FILE, SOUND_VOL, GetWidgetX(u), GetWidgetY(u), SOUND_MAX_DISTANCE, SOUND_PITCH);
DestroyEffect(AddSpecialEffectTarget(ITEM_COMBINE_EFFECT, u, ATTACH_POINT));
u = null;
return false;
}
}
u = null;
return false;
});
}
}
//! endzinc
function Random_GroupUnit takes group g returns unit
// local integer i = GetRandomInt(0,BlzGroupGetSize(g)-1)
// call BJDebugMsg("Group size: "+I2S(BlzGroupGetSize(g))+", random unit was no. "+I2S(i)+", its name is "+GetUnitName(BlzGroupUnitAt(g,i))+".")
if BlzGroupGetSize(g)>0 then
return BlzGroupUnitAt(g,GetRandomInt(0,BlzGroupGetSize(g)-1))
endif
return null
endfunction
function Roll takes integer i returns integer
return GetRandomInt(1,i)
endfunction
function GetCoordZ takes real x, real y returns real
local location loc = Location(x,y)
local real z = GetLocationZ(loc)
call RemoveLocation(loc)
set loc = null
return z
endfunction
//Attack is valid on non-structures enemies
function IsAttackValid takes nothing returns boolean
// return (udg_IsDamageAttack and udg_DamageEventType<11 and not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource))) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE)))
return not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource))) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE))
endfunction
//Attack is valid on non-structures, non-mechanical enemies
function IsAttackValidOrganic takes nothing returns boolean
// return (udg_IsDamageAttack and udg_DamageEventType<11 and not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource))) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE)) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MECHANICAL)))
return not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource))) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE)) and not(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MECHANICAL))
endfunction
//Attack is valid on all types of enemies
function IsAttackValidAll takes nothing returns boolean
// return (udg_IsDamageAttack and udg_DamageEventType<11 and not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource))))
return not(IsUnitAlly(udg_DamageEventTarget,GetOwningPlayer(udg_DamageEventSource)))
endfunction
//Attack is valid on any player
function IsAttackValidUniverse takes nothing returns boolean
// return (udg_IsDamageAttack and udg_DamageEventType<11)
return true
endfunction
function AbilPreloadDummy takes integer id returns nothing
local string text = null
local integer i = 0
local integer i_max = 6
if not UnitAlive(udg_Preload_Dummy) then
set udg_Preload_Dummy=CreateUnit(udg_Spell__DummyOwner,'ndum',0,0,0)
endif
if UnitAddAbility(udg_Preload_Dummy,id) and UnitRemoveAbility(udg_Preload_Dummy,id) then
loop
set text=GetAbilityEffectBJ(id,ConvertEffectType(i),0)
if text!=null then
// call BJDebugMsg(text)
call DestroyEffect(AddSpecialEffect(text,GetCameraBoundMaxX(),GetCameraBoundMaxY()))
endif
set i = i + 1
exitwhen i > i_max
endloop
endif
endfunction
function SetAbilityRealField takes unit u, integer id, integer field, integer level, real value returns boolean
return BlzSetAbilityRealLevelField(BlzGetUnitAbility(u,id),ConvertAbilityRealLevelField(field),level-1,value)
endfunction
function SetAbilityRealFieldOne takes unit u, integer id, integer field, real value returns boolean
return BlzSetAbilityRealLevelField(BlzGetUnitAbility(u,id),ConvertAbilityRealLevelField(field),0,value)
endfunction
function SetAbilityIntField takes unit u, integer id, integer field, integer level, integer value returns boolean
return BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u,id),ConvertAbilityIntegerLevelField(field),level-1,value)
endfunction
function SetAbilityIntFieldOne takes unit u, integer id, integer field, integer value returns boolean
return BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u,id),ConvertAbilityIntegerLevelField(field),0,value)
endfunction
function DoombruteTalentCondition takes unit source, unit target returns boolean
local real MaxAngle = 60
local real dy = GetUnitY(source) - GetUnitY(target)
local real dx = GetUnitX(source) - GetUnitX(target)
local real Deg0 = GetUnitFacing(target)
local real Deg1 = Atan2BJ(dy,dx)
if Deg1 < 0 then
set Deg1 = Deg1+360
endif
if RAbsBJ(Deg1-Deg0) <= MaxAngle or 360-RAbsBJ(Deg1-Deg0) <= MaxAngle then
return true
endif
return false
endfunction
function KnockshotAction takes unit source, unit target, integer level returns real
local real Sx = udg_A_KnockShotX[GetUnitUserData(source)]
local real Sy = udg_A_KnockShotY[GetUnitUserData(source)]
local real Tx = GetUnitX(target)
local real Ty = GetUnitY(target)
// local real DistanceDamage = (0.1+0.05*udg_A_KnockShotLevel[GetUnitUserData(source)])*SquareRoot((Tx-Sx)*(Tx-Sx)+(Ty-Sy)*(Ty-Sy))
local real DistanceDamage = (0.1+0.05*level)*SquareRoot((Tx-Sx)*(Tx-Sx)+(Ty-Sy)*(Ty-Sy))
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(source),'ndum',Sx,Sy,Atan2BJ(Ty-Sy,Tx-Sx))
call UnitApplyTimedLife( GetLastCreatedUnit(), 'BTLF', 1.00 )
call UnitAddAbility( GetLastCreatedUnit(), 'Atbc' )
call IssueTargetOrder( GetLastCreatedUnit(), "chainlightning", target )
if DistanceDamage > 350 then
set DistanceDamage = 350
endif
// call UnitDamageTargetBJ(udg_A_KnockShotMaster[GetUnitUserData(source)],target,15*udg_A_KnockShotLevel[GetUnitUserData(source)]+DistanceDamage,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC)
return DistanceDamage
endfunction
function SearingBladeAction takes unit source, unit target returns nothing
local real Sx = GetUnitX(source)
local real Sy = GetUnitY(source)
local real Tx = GetUnitX(target)
local real Ty = GetUnitY(target)
local unit u = CreateUnit(GetOwningPlayer(source),'ndum',Sx,Sy,Atan2BJ(Ty-Sy,Tx-Sx))
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Amaa')
call IssueTargetOrder(u,"soulburn",target)
call DestroyEffect(AddSpecialEffectTarget("Piercing Thrust.mdx",u,"origin"))
set u = null
set udg_A_SearingBladeCount[GetUnitUserData(source)] = udg_A_SearingBladeCount[GetUnitUserData(source)] + GetUnitAbilityLevel(source,'Ama3') - 9
endfunction
function FelhoundBiteAction takes unit source, unit target returns real
local real Mana = GetUnitState(target,UNIT_STATE_MANA)
local real ToBurn = GetUnitAbilityLevel(source,'Afh3')*30
if Roll(3)==3 then
set bj_lastCreatedEffect=AddSpecialEffectTarget("war3.w3mod:Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl",target,"head")
call BlzPlaySpecialEffect(GetLastCreatedEffectBJ(),ANIM_TYPE_DEATH)
call DestroyEffect(GetLastCreatedEffectBJ())
call SetUnitState(target,UNIT_STATE_MANA,Mana-ToBurn)
call SetUnitState(source,UNIT_STATE_MANA,GetUnitState(source,UNIT_STATE_MANA)+Mana-GetUnitState(target,UNIT_STATE_MANA))
if ToBurn>Mana then
return ToBurn-Mana
endif
endif
return 0.0
endfunction
function GlaiveRemoveStacks takes nothing returns nothing
local unit u
local integer i = 1
local integer i_max = BlzGroupGetSize(udg_A_GlaveStackGroup)
loop
set u = BlzGroupUnitAt(udg_A_GlaveStackGroup,i-1)
if GetExpiredTimer()==udg_A_GlaveStackTimer[GetUnitUserData(u)] then
call DestroyTimer(GetExpiredTimer())
call GroupRemoveUnit(udg_A_GlaveStackGroup,u)
set udg_A_GlaveStackTimer[GetUnitUserData(u)] = null
set i = i_max
endif
set i = i + 1
exitwhen i > i_max
endloop
set u = null
endfunction
function HuntingDaggerAction takes unit source returns real
local real ScalingFactor = I2R(udg_A_DaggerLevel[GetUnitUserData(source)])*0.3+0.6
local real Dmge = I2R(BlzGetUnitBaseDamage(source,0)+GetRandomInt(1,11))*ScalingFactor
return Dmge
endfunction
function Minotaur_bonus_A takes unit source, unit target, real damage, attacktype AT, damagetype DT returns nothing
local integer i = 0
local integer i_max
local group g = CreateGroup()
local group topick = CreateGroup()
// call GroupEnumUnitsInRange(g, GetUnitX(source), GetUnitY(source), 300, Condition(function Minotaur_bonus_Filter))
call GroupEnumUnitsInRange(g, GetUnitX(source), GetUnitY(source), 300, null)
call GroupRemoveUnit(g,target)
set i_max = BlzGroupGetSize(g)-1
if i_max > -1 then
loop
if UnitAlive(BlzGroupUnitAt(g,i)) and BlzIsUnitSelectable(BlzGroupUnitAt(g,i)) and IsUnitEnemy(BlzGroupUnitAt(g,i),GetOwningPlayer(source)) and not(IsUnitType(BlzGroupUnitAt(g,i),UNIT_TYPE_STRUCTURE)) then
call GroupAddUnit(topick,BlzGroupUnitAt(g,i))
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call UnitDamageTargetBJ(source,Random_GroupUnit(topick),damage*GetUnitAbilityLevel(source,'Tmtt')/2,AT,DT)
call DestroyGroup(g)
call DestroyGroup(topick)
set g = null
set topick = null
endfunction
function BerserkLifeStealAction takes unit source, real damage returns nothing
local real ToHeal = udg_A_BerserkSteal[GetUnitUserData(source)]*damage/100
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",source,"origin"))
if GetWidgetLife(source)+ToHeal > GetUnitState(source,UNIT_STATE_MAX_LIFE) then
set udg_A_BerserkOverLife[GetUnitUserData(source)] = udg_A_BerserkOverLife[GetUnitUserData(source)] + R2I(ToHeal)
call BlzSetUnitMaxHP(source, BlzGetUnitMaxHP(source) + R2I(ToHeal))
endif
call SetWidgetLife(source, GetWidgetLife(source) + ToHeal)
endfunction
function GoblinTalentAction takes unit u returns nothing
local integer level = GetUnitAbilityLevel(u,'Tgat')
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(u),'ndga',GetUnitX(u),GetUnitY(u),0)
set udg_A_GoblinArmorMaster[GetUnitUserData(GetLastCreatedUnit())] = u
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Defend\\DefendCaster.mdl",u,"origin"))
call UnitApplyTimedLife( GetLastCreatedUnit(), 'BTLF', 10.00 )
call UnitAddAbility(GetLastCreatedUnit(),'Tgat')
call SetUnitAbilityLevel(GetLastCreatedUnit(),'Tgat',level)
call BlzSetUnitArmor( u, BlzGetUnitArmor(u) + I2R(level) )
endfunction
function Intel_damage_A takes unit source, unit target returns nothing
local real Tx = GetUnitX(target)
local real Ty = GetUnitY(target)
local real level = I2R(GetUnitAbilityLevel(source,'Abea'))
local unit u
if level > 0 then
set u = CreateUnit(GetOwningPlayer(source),udg_Spell__DummyType,Tx,Ty,0)
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Abec')
call IssueTargetOrderById(u,852274,target)
call UnitDamageTargetBJ(udg_A_CopyCaster[GetUnitUserData(source)], target, GetHeroInt(udg_A_CopyCaster[GetUnitUserData(source)],true)*(level/2+1), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC)
endif
set u = null
endfunction
function Black_shield_passive_A takes unit source, unit target, real damage returns nothing
if UnitHasItemOfTypeBJ(target, 'Iyc6') and Roll(5)>3 then
set bj_lastCreatedEffect=AddSpecialEffectTarget("war3.w3mod:Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl",source,"head")
call BlzPlaySpecialEffect( GetLastCreatedEffectBJ(), ANIM_TYPE_DEATH )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
set udg_NextDamageType = udg_DamageTypeItemBTShield
set udg_DamageEventOverride = true
call UnitDamageTargetBJ( target, source, damage, ATTACK_TYPE_HERO, DAMAGE_TYPE_ENHANCED )
endif
endfunction
function Tower_Filter takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit())=='hg1a' or GetUnitTypeId(GetFilterUnit())=='hg1b')
endfunction
function Tower_Force_Center takes group g returns nothing
local integer i = 0
local integer i_max = BlzGroupGetSize(g)-1
local unit u
loop
set u = BlzGroupUnitAt(g,i)
if GetUnitX(u) != GetUnitX(udg_CP_Tower[GetUnitUserData(u)]) or GetUnitY(u) != GetUnitY(udg_CP_Tower[GetUnitUserData(u)]) then
call SetUnitPosition(u,GetUnitX(udg_CP_Tower[GetUnitUserData(u)]),GetUnitY(udg_CP_Tower[GetUnitUserData(u)]))
endif
set i = i+1
exitwhen i > i_max
endloop
set u = null
endfunction
function Tower_Enum_AlliesAction takes group g, player p returns nothing
local integer i = 0
local integer i_max = BlzGroupGetSize(g)-1
local unit u
loop
set u = BlzGroupUnitAt(g,i)
if IsUnitInGroup(u,udg_H_AllHeroes) and IsUnitAlly(u,p) then
call SetHeroXP(u,GetHeroXP(u)+40,true)
endif
set i = i+1
exitwhen i > i_max
endloop
set u = null
endfunction
function GuardPostTakeDamage takes unit u, integer dmgtype returns real
local real DmgeTake = 1
//If the attacker is a Hero, they deal 5 damage to the tower. If the attacker is a siege creep, they deal 20 damage to it.
if IsUnitType(u,UNIT_TYPE_HERO) then
set DmgeTake = 5
elseif dmgtype == udg_ATTACK_TYPE_SIEGE then
set DmgeTake = 20
endif
//Final check: If the attacker is an illusion or a skeleton creep, they have a 50% damage penalty.
if IsUnitIllusion(u) or GetUnitTypeId(u) == 'udks' or GetUnitTypeId(u) == 'udk2' or GetUnitTypeId(u) == 'udk3' or GetUnitTypeId(u) == 'udk4' then
set DmgeTake = DmgeTake/2
endif
return DmgeTake
endfunction
function Trig_Guard_post_damage_Conditions takes nothing returns boolean
return (GetUnitTypeId(udg_DamageEventTarget)=='hg1a' or GetUnitTypeId(udg_DamageEventTarget)=='hg1b')
endfunction
function Trig_Guard_post_damage_Actions takes nothing returns nothing
local real DmgeTake = 1
//If the attacker is a Hero, they deal 5 damage to the tower. If the attacker is a siege creep, they deal 20 damage to it.
if IsUnitType(udg_DamageEventSource,UNIT_TYPE_HERO) then
set DmgeTake = 5
elseif udg_DamageEventAttackT == udg_ATTACK_TYPE_SIEGE then
set DmgeTake = 20
endif
//Final check: If the attacker is an illusion or a skeleton creep, they have a 50% damage penalty.
if IsUnitIllusion(udg_DamageEventSource) or GetUnitTypeId(udg_DamageEventSource) == 'udks' or GetUnitTypeId(udg_DamageEventSource) == 'udk2' or GetUnitTypeId(udg_DamageEventSource) == 'udk3' or GetUnitTypeId(udg_DamageEventSource) == 'udk4' then
set DmgeTake = DmgeTake/2
endif
set udg_DamageEventAmount = DmgeTake
endfunction
//===========================================================================
function InitTrig_ControlPoint_Tower_Damage takes nothing returns nothing
set gg_trg_ControlPoint_Tower_Damage = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_ControlPoint_Tower_Damage, "udg_DamageModifierEvent", EQUAL, 4.00 )
call TriggerAddCondition( gg_trg_ControlPoint_Tower_Damage, Condition( function Trig_Guard_post_damage_Conditions ) )
call TriggerAddAction( gg_trg_ControlPoint_Tower_Damage, function Trig_Guard_post_damage_Actions )
endfunction
globals
framehandle udg_W_NorthDisplay
framehandle udg_W_NorthDisplayFrame
framehandle udg_W_SouthDisplay
framehandle udg_W_SouthDisplayFrame
endglobals
function South_ScoreUI takes nothing returns nothing
set udg_W_SouthDisplayFrame = BlzCreateFrameByType( "BACKDROP", "SouthFrame", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), "", 0 )
call BlzFrameSetAbsPoint(udg_W_SouthDisplayFrame , FRAMEPOINT_CENTER, 0.32, 0.55 )
call BlzFrameSetSize(udg_W_SouthDisplayFrame , 0.088,0.048 )
// "UI\\Widgets\\Glues\\GlueScreen-Checkbox-BackgroundPressed.blp"
call BlzFrameSetTexture(udg_W_SouthDisplayFrame, "UI\\Widgets\\console\\human\\human-button-lvls-overlay.dds",0, true)
set udg_W_SouthDisplay = BlzCreateFrameByType( "TEXT", "South", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), "", 0 )
call BlzFrameSetAbsPoint(udg_W_SouthDisplay , FRAMEPOINT_CENTER, 0.32, 0.55 )
call BlzFrameSetText(udg_W_SouthDisplay , "|cffFE8A0E"+I2S(R2I(udg_W_SouthTickets))+"|r")
call BlzFrameSetScale(udg_W_SouthDisplay , 2.24 )
endfunction
function North_ScoreUI takes nothing returns nothing
set udg_W_NorthDisplayFrame = BlzCreateFrameByType( "BACKDROP", "NorthFrame", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), "", 0 )
call BlzFrameSetAbsPoint(udg_W_NorthDisplayFrame, FRAMEPOINT_CENTER, 0.48, 0.55 )
call BlzFrameSetSize(udg_W_NorthDisplayFrame, 0.088,0.048 )
call BlzFrameSetTexture(udg_W_NorthDisplayFrame, "UI\\Widgets\\console\\human\\human-button-lvls-overlay.dds",0, true)
set udg_W_NorthDisplay = BlzCreateFrameByType( "TEXT", "North", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), "", 0 )
call BlzFrameSetAbsPoint(udg_W_NorthDisplay, FRAMEPOINT_CENTER, 0.48, 0.55 )
call BlzFrameSetText(udg_W_NorthDisplay, "|cff00EAFF"+I2S(R2I(udg_W_NorthTickets))+"|r")
call BlzFrameSetScale(udg_W_NorthDisplay, 2.24 )
endfunction
function BeginVictoryCinematic takes nothing returns nothing
//Begin cinematic
call PauseAllUnitsBJ( true )
call BlzDestroyFrame(udg_W_NorthDisplay)
call BlzDestroyFrame(udg_W_NorthDisplayFrame)
call BlzDestroyFrame(udg_W_SouthDisplay)
call BlzDestroyFrame(udg_W_SouthDisplayFrame)
call CinematicModeBJ( true, GetPlayersAll() )
//Reveal map
set bj_lastCreatedUnit=CreateUnit(Player(5),'ndum',0,0,0)
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
call UnitAddItemById(GetLastCreatedUnit(),'gomn')
set bj_lastCreatedUnit=CreateUnit(Player(14),'ndum',0,0,0)
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
call UnitAddItemById(GetLastCreatedUnit(),'gomn')
endfunction
function EndVictoryCinematic takes nothing returns nothing
//Display victory text
local string text
if GetExpiredTimer()==udg_W_SouthCinTimer then
set text= "|cffFE8A0EThe Lenothians are victorious! Game ends in one minute...|r"
call MultiboardSetTitleText(udg_P_Multiboard,"|cffFE8A0ELenothian Victory|r")
elseif GetExpiredTimer()==udg_W_NorthCinTimer then
set text= "|cff00EAFFThe Boreans are victorious! Game ends in one minute...|r"
call MultiboardSetTitleText(udg_P_Multiboard,"|cff00EAFFBorean Victory|r")
endif
call DisplayTextToPlayer(GetLocalPlayer(),0,0,text)
//Exit cinematic
// call CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 1, "ReplaceableTextures\\CameraMasks\\Black_mask.blp",0,0,0,0)
call CinematicModeBJ(false,GetPlayersAll())
call ResetToGameCamera(1)
call PauseAllUnitsBJ(false)
endfunction
function EndVictoryDialog takes nothing returns nothing
local player p
if GetExpiredTimer()==udg_W_SouthWinTimer then
set p = Player(5)
elseif GetExpiredTimer()==udg_W_NorthWinTimer then
set p = Player(14)
endif
if IsPlayerAlly(GetLocalPlayer(),p) then
call CustomVictoryBJ(GetLocalPlayer(),true,true)
else
call CustomDefeatBJ(GetLocalPlayer(),"The battle is lost!")
endif
endfunction
function EndVictorySpeech takes unit u returns nothing
call DoTransmissionBasicsXYBJ(GetUnitTypeId(u),GetPlayerColor(GetOwningPlayer(u)),0,0,null,GetHeroProperName(u),udg_E_SpeechWin[GetUnitUserData(u)],10)
endfunction
function Trig_Init_Actions takes nothing returns nothing
call SetDayNightModels("war3.w3mod:Environment\\DNC\\DNCUnderground\\DNCUndergroundTerrain\\DNCUndergroundTerrain.mdl", "war3.w3mod:Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl")
call MeleeStartingVisibility( )
call EnableCreepSleepBJ( false )
call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(5) )
call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(14) )
call SetPlayerColorBJ( Player(PLAYER_NEUTRAL_PASSIVE), PLAYER_COLOR_SNOW, true )
set udg_P_ColorString[GetConvertedPlayerId(Player(0))] = "|cffff0303"
set udg_P_ColorString[GetConvertedPlayerId(Player(1))] = "|cff0042ff"
set udg_P_ColorString[GetConvertedPlayerId(Player(3))] = "|cff540081"
set udg_P_ColorString[GetConvertedPlayerId(Player(4))] = "|cfffffc00"
set udg_P_ColorString[GetConvertedPlayerId(Player(7))] = "|cffe55bb0"
set udg_P_ColorString[GetConvertedPlayerId(Player(8))] = "|cff969696"
set udg_P_ColorString[GetConvertedPlayerId(Player(9))] = "|cff7EBFF1"
set udg_P_ColorString[GetConvertedPlayerId(Player(10))] = "|cff106246"
set udg_P_ColorString[GetConvertedPlayerId(Player(15))] = "|cffBE00FE"
set udg_P_ColorString[GetConvertedPlayerId(Player(16))] = "|cffebcd87"
set udg_P_ColorString[GetConvertedPlayerId(Player(17))] = "|cfff8a48b"
set udg_P_ColorString[GetConvertedPlayerId(Player(18))] = "|cffbfff80"
set udg_P_ColorString[GetConvertedPlayerId(Player(19))] = "|cffDCB9EB"
set udg_P_ColorString[GetConvertedPlayerId(Player(20))] = "|cff282828"
set udg_P_ColorString[GetConvertedPlayerId(Player(22))] = "|cff00781e"
set udg_P_ColorString[GetConvertedPlayerId(Player(23))] = "|cffA46F33"
call ConditionalTriggerExecute( gg_trg_Item_Recipes_Init )
call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUT, 0.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0 )
call CinematicModeBJ( true, GetPlayersAll() )
call SetUserControlForceOff( GetPlayersAll() )
// Preload some abilities
set udg_Preload_Dummy=CreateUnit(udg_Spell__DummyOwner,'ndum',0,GetCameraBoundMaxX(),GetCameraBoundMaxY())
call AbilPreloadDummy('Au00')
call AbilPreloadDummy('Au01')
call AbilPreloadDummy('Au02')
call AbilPreloadDummy('Au03')
call AbilPreloadDummy('Au04')
call AbilPreloadDummy('Au05')
call AbilPreloadDummy('Au06')
call AbilPreloadDummy('Au07')
call AbilPreloadDummy('Au08')
call AbilPreloadDummy('Au09')
call AbilPreloadDummy('Aflk')
call AbilPreloadDummy('AOsh')
call AbilPreloadDummy('AOws')
call AbilPreloadDummy('AHtb')
call AbilPreloadDummy('AHtc')
call AbilPreloadDummy('AHre')
call AbilPreloadDummy('AHfs')
call AbilPreloadDummy('AUin')
call AbilPreloadDummy('AUim')
call AbilPreloadDummy('AUan')
call AbilPreloadDummy('AIdg')
call AbilPreloadDummy('Arai')
call AbilPreloadDummy('Aens')
call AbilPreloadDummy('ANdp')
// Preload units
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hg1a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hg1b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc1a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc2a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc3a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc4a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc5a',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc1b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc2b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc3b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc4b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hc5b',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hels',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hel2',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hel3',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'hel4',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'udks',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'udk2',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'udk3',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'udk4',0,0,0))
call RemoveUnit(CreateUnit(udg_Spell__DummyOwner,'udkm',0,0,0))
endfunction
//===========================================================================
function InitTrig_Init takes nothing returns nothing
set gg_trg_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Init, function Trig_Init_Actions )
endfunction
function Kill_Group_Filter takes nothing returns boolean
return (IsUnitType(GetFilterUnit(),UNIT_TYPE_HERO) and IsUnitAlly(GetFilterUnit(),GetOwningPlayer(GetKillingUnitBJ())) and GetOwningPlayer(GetFilterUnit())!=GetOwningPlayer(GetKillingUnitBJ()))
endfunction
function Kill_Assist_Effect takes player p, unit u returns integer
local string vfxpath = "Abilities\\Spells\\Items\\ResourceItems\\ResourceEffectTarget.mdl"
local integer level = GetHeroLevel(u)
local integer ToAdd=5*level
if level>14 then
set ToAdd=7*(level-14)+77
elseif level>7 then
set ToAdd=6*(level-7)+35
endif
if p != GetLocalPlayer() then
set vfxpath = ""
endif
call DestroyEffect(AddSpecialEffect(vfxpath,GetUnitX(u),GetUnitY(u)))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + ToAdd)
set udg_H_AssistGold=ToAdd
return udg_H_AssistGold
endfunction
function Kill_Bounty_Effect takes player p, unit u returns integer
local string vfxpath = "Abilities\\Spells\\Other\\Transmute\\PileOfGold.mdl"
local integer gold = 1200/(25-GetHeroLevel(u))+4*GetHeroLevel(u)
if p != GetLocalPlayer() then
set vfxpath = ""
endif
call DestroyEffect(AddSpecialEffect(vfxpath,GetUnitX(u),GetUnitY(u)))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + gold)
set udg_H_KillGold=gold
return udg_H_KillGold
endfunction
function Kill_TeamCreep_Effect takes player p, unit u returns integer
local integer gold = 462/(23-GetHeroLevel(u))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + gold)
set udg_H_TeamGold=gold
return udg_H_TeamGold
endfunction
function Respawn_ally_filter takes nothing returns boolean
return (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) and UnitAlive(GetFilterUnit()))
endfunction
function Respawn_check_ally takes player p returns unit
local integer i = 0
local integer i_max
local integer Dex = GetConvertedPlayerId(p)
local group g = CreateGroup()
if udg_H_RezX[Dex] != GetPlayerStartLocationX(p) or udg_H_RezY[Dex] != GetPlayerStartLocationY(p) then
call GroupEnumUnitsInRange(g,udg_H_RezX[Dex],udg_H_RezY[Dex],200,null)
set i_max = BlzGroupGetSize(g)-1
if i_max>-1 then
loop
if IsUnitType(BlzGroupUnitAt(g,i),UNIT_TYPE_STRUCTURE) and UnitAlive(BlzGroupUnitAt(g,i)) then
return BlzGroupUnitAt(g,i)
endif
set i = i+1
exitwhen i>i_max
endloop
else
set udg_H_RezX[Dex] = GetPlayerStartLocationX(p)
set udg_H_RezY[Dex] = GetPlayerStartLocationY(p)
endif
endif
call DestroyGroup(g)
set g = null
return null
endfunction
function Hero_IsChosen takes player p, unit Hero returns nothing
local integer i = GetPlayerId(p)+1
local real x = GetPlayerStartLocationX(p)
local real y = GetPlayerStartLocationY(p)
set udg_H_RezX[i] = x
set udg_H_RezY[i] = y
set udg_P_Hero[i] = Hero
set udg_P_COP[i] = CreateUnit(p,'ncp0',x,y,0)
call UnitAddItemToSlotById(udg_P_COP[i],'Ioo0',1)
call UnitAddItemToSlotById(udg_P_COP[i],'Ioo1',2)
call UnitAddItemToSlotById(udg_P_COP[i],'Ioo2',3)
call SetUnitPosition(Hero,x,y)
call SelectUnitForPlayerSingle(Hero, p)
call DisplayTextToPlayer(GetLocalPlayer(),0,0, udg_P_ColorString[i] + GetPlayerName(p) + "|r has picked |cff87ceeb" + GetUnitName(Hero) + "|r")
call DisplayTextToPlayer(p,0,0,"\n|cff87ceebYour Circle of Power contains supporting abilities and information.\nToggle Creep Camp display to see neutral camps on the map.|r\n")
call MultiboardSetItemValueBJ( udg_P_Multiboard, 2, udg_P_MultiboardIndexForPlayer[i], udg_P_ColorString[i] + GetPlayerName(p) + "|r |cff87ceeb(" + GetUnitName(Hero) + ")|r" )
call MultiboardSetItemValueBJ( udg_P_Multiboard, 3, udg_P_MultiboardIndexForPlayer[i], "1")
call MultiboardSetItemIconBJ(udg_P_Multiboard, 1, udg_P_MultiboardIndexForPlayer[i], BlzGetAbilityIcon(GetUnitTypeId(Hero)))
call GroupAddUnit(udg_H_AllHeroes,Hero)
call TriggerRegisterUnitEvent( gg_trg_Hero_death_trigger, Hero, EVENT_UNIT_DEATH )
if p == GetLocalPlayer() then
call SetCameraPosition(x,y)
endif
endfunction
function Unit_Infantry takes unit u, location Loc returns unit
local integer i = GetUnitUserData(u)
call BlzSetUnitBaseDamage(u, BlzGetUnitBaseDamage(u, 0) + 2 * ( udg_WP_TotalSpawnInstances / 10 ), 0 )
call BlzSetUnitMaxHP( u, udg_WP_UnitMeleeMaxLife )
call SetUnitLifePercentBJ( u, 100 )
call BlzSetUnitIntegerFieldBJ( u,UNIT_IF_GOLD_BOUNTY_AWARDED_BASE, udg_WP_TotalSpawnInstances / 15 + 120 / ( 7 - GetUnitLevel(u) ) )
call IssuePointOrder( u, "attack",GetLocationX(Loc),GetLocationY(Loc) )
set udg_WP_NorthA1reached[i]=false
set udg_WP_NorthA2reached[i]=false
set udg_WP_NorthB1reached[i]=false
set udg_WP_NorthB2reached[i]=false
set udg_WP_NorthC1reached[i]=false
set udg_WP_NorthC2reached[i]=false
set udg_WP_SouthA1reached[i]=false
set udg_WP_SouthA2reached[i]=false
set udg_WP_SouthB1reached[i]=false
set udg_WP_SouthB2reached[i]=false
set udg_WP_SouthC1reached[i]=false
set udg_WP_SouthC2reached[i]=false
return u
endfunction
function Unit_Cavalry takes unit u, location Loc returns unit
local integer i = GetUnitUserData(u)
call BlzSetUnitBaseDamage( u,BlzGetUnitBaseDamage(u,0) + 3 * ( udg_WP_TotalSpawnInstances / 10 ) ,0 )
call BlzSetUnitMaxHP( u,udg_WP_UnitMountedMaxLife )
call SetUnitLifePercentBJ( u,100 )
call BlzSetUnitIntegerFieldBJ( u,UNIT_IF_GOLD_BOUNTY_AWARDED_BASE, udg_WP_TotalSpawnInstances / 15 + 120 / ( 7 - GetUnitLevel(u) ) )
call IssuePointOrder( u, "attack",GetLocationX(Loc),GetLocationY(Loc) )
set udg_WP_NorthA1reached[i]=false
set udg_WP_NorthA2reached[i]=false
set udg_WP_NorthB1reached[i]=false
set udg_WP_NorthB2reached[i]=false
set udg_WP_NorthC1reached[i]=false
set udg_WP_NorthC2reached[i]=false
set udg_WP_SouthA1reached[i]=false
set udg_WP_SouthA2reached[i]=false
set udg_WP_SouthB1reached[i]=false
set udg_WP_SouthB2reached[i]=false
set udg_WP_SouthC1reached[i]=false
set udg_WP_SouthC2reached[i]=false
return u
endfunction
function Unit_Healer takes unit u, location Loc returns unit
local integer i = GetUnitUserData(u)
call BlzSetUnitBaseDamage( u,BlzGetUnitBaseDamage(u,0) + 1 * ( udg_WP_TotalSpawnInstances / 10 ) ,0 )
call BlzSetUnitMaxHP( u,udg_WP_UnitHealerMaxLife )
call SetUnitLifePercentBJ( u,100 )
call BlzSetUnitIntegerFieldBJ( u,UNIT_IF_GOLD_BOUNTY_AWARDED_BASE, udg_WP_TotalSpawnInstances / 15 + 120 / ( 7 - GetUnitLevel(u) ) )
call IssuePointOrder( u, "attack",GetLocationX(Loc),GetLocationY(Loc) )
set udg_WP_NorthA1reached[i]=false
set udg_WP_NorthA2reached[i]=false
set udg_WP_NorthB1reached[i]=false
set udg_WP_NorthB2reached[i]=false
set udg_WP_NorthC1reached[i]=false
set udg_WP_NorthC2reached[i]=false
set udg_WP_SouthA1reached[i]=false
set udg_WP_SouthA2reached[i]=false
set udg_WP_SouthB1reached[i]=false
set udg_WP_SouthB2reached[i]=false
set udg_WP_SouthC1reached[i]=false
set udg_WP_SouthC2reached[i]=false
return u
endfunction
function Unit_Ranged takes unit u, location Loc returns unit
local integer i = GetUnitUserData(u)
call BlzSetUnitBaseDamage( u,BlzGetUnitBaseDamage(u,0) + 1 * ( udg_WP_TotalSpawnInstances / 10 ) ,0 )
call BlzSetUnitMaxHP( u,udg_WP_UnitRangedMaxLife )
call SetUnitLifePercentBJ( u,100 )
call BlzSetUnitIntegerFieldBJ( u,UNIT_IF_GOLD_BOUNTY_AWARDED_BASE, udg_WP_TotalSpawnInstances / 15 + 120 / ( 7 - GetUnitLevel(u) ) )
call IssuePointOrder( u, "attack",GetLocationX(Loc),GetLocationY(Loc) )
set udg_WP_NorthA1reached[i]=false
set udg_WP_NorthA2reached[i]=false
set udg_WP_NorthB1reached[i]=false
set udg_WP_NorthB2reached[i]=false
set udg_WP_NorthC1reached[i]=false
set udg_WP_NorthC2reached[i]=false
set udg_WP_SouthA1reached[i]=false
set udg_WP_SouthA2reached[i]=false
set udg_WP_SouthB1reached[i]=false
set udg_WP_SouthB2reached[i]=false
set udg_WP_SouthC1reached[i]=false
set udg_WP_SouthC2reached[i]=false
return u
endfunction
function Unit_Artillery takes unit u, location Loc returns unit
local integer i = GetUnitUserData(u)
call IssuePointOrder( u, "attack",GetLocationX(Loc),GetLocationY(Loc) )
set udg_WP_NorthA1reached[i]=false
set udg_WP_NorthA2reached[i]=false
set udg_WP_NorthB1reached[i]=false
set udg_WP_NorthB2reached[i]=false
set udg_WP_NorthC1reached[i]=false
set udg_WP_NorthC2reached[i]=false
set udg_WP_SouthA1reached[i]=false
set udg_WP_SouthA2reached[i]=false
set udg_WP_SouthB1reached[i]=false
set udg_WP_SouthB2reached[i]=false
set udg_WP_SouthC1reached[i]=false
set udg_WP_SouthC2reached[i]=false
return u
endfunction
function NeutralSpawnAction takes nothing returns nothing
local integer i = 0
local integer i_max = BlzGroupGetSize(udg_NPC_CreepToSpawn)-1
local unit u
loop
set u = BlzGroupUnitAt(udg_NPC_CreepToSpawn,i)
if GetExpiredTimer()==udg_NPC_CreepTimer[GetUnitUserData(u)] then
call DestroyTimer(GetExpiredTimer())
call GroupRemoveUnit(udg_NPC_CreepToSpawn,u)
call SetUnitX(u,udg_NPC_CreepX[GetUnitUserData(u)])
call SetUnitY(u,udg_NPC_CreepY[GetUnitUserData(u)])
call BlzSetUnitFacingEx(u,udg_NPC_CreepFacing[GetUnitUserData(u)])
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl",udg_NPC_CreepX[GetUnitUserData(u)],udg_NPC_CreepY[GetUnitUserData(u)]))
call SetUnitPathing(u,true)
call ShowUnit(u,true)
set i = i_max
endif
set i = i + 1
exitwhen i > i_max
endloop
set u = null
endfunction
function Modifier_Lifesteal takes unit u, real ToHeal returns nothing
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",u,"origin"))
call SetWidgetLife(u,GetWidgetLife(u)+ToHeal/100)
endfunction
function Modifier_LifestealAction takes unit u, real damage returns nothing
if UnitHasItemOfTypeBJ(u,'Icc9') or UnitHasItemOfTypeBJ(u,'Icca') then
call Modifier_Lifesteal(u,damage*20)
elseif UnitHasItemOfTypeBJ(u,'Icc8') then
call Modifier_Lifesteal(u,damage*15)
elseif UnitHasItemOfTypeBJ(u,'Ic07') then
call Modifier_Lifesteal(u,damage*10)
endif
endfunction
function Modifier_Corrosion takes unit target, integer Level returns nothing
local unit u=CreateUnit(udg_Spell__DummyOwner,'ndum',GetUnitX(target),GetUnitY(target),0)
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Au02')
call SetUnitAbilityLevel(u,'Au02',Level)
call IssueTargetOrder(u,"faeriefire",target)
set u=null
endfunction
function Modifier_CorrosionAction takes unit source, unit enemy returns nothing
if UnitHasItemOfTypeBJ(source,'Iccd') then
call Modifier_Corrosion(enemy,3)
elseif UnitHasItemOfTypeBJ(source,'Iccc') then
call Modifier_Corrosion(enemy,2)
elseif UnitHasItemOfTypeBJ(source,'Ic09') then
call Modifier_Corrosion(enemy,1)
endif
endfunction
function Trig_Black_shield_passive_Conditions takes nothing returns boolean
return (UnitHasItemOfTypeBJ(udg_DamageEventTarget, 'Iyc6') and IsAttackValid())
endfunction
function Trig_Black_shield_passive_Actions takes nothing returns nothing
if Roll(5)>3 then
set bj_lastCreatedEffect=AddSpecialEffectTarget("Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl",udg_DamageEventSource,"head")
call BlzPlaySpecialEffect( GetLastCreatedEffectBJ(), ANIM_TYPE_DEATH )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
set udg_NextDamageType = udg_DamageTypeItemBTShield
call UnitDamageTargetBJ( udg_DamageEventTarget, udg_DamageEventSource, udg_DamageEventAmount, ATTACK_TYPE_HERO, DAMAGE_TYPE_ENHANCED )
endif
endfunction
//===========================================================================
function InitTrig_Black_shield_passive takes nothing returns nothing
set gg_trg_Black_shield_passive = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Black_shield_passive, "udg_AfterDamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Black_shield_passive, Condition( function Trig_Black_shield_passive_Conditions ) )
call TriggerAddAction( gg_trg_Black_shield_passive, function Trig_Black_shield_passive_Actions )
endfunction
function Claws_PassiveAction takes unit source, unit target returns nothing
if UnitHasItemOfTypeBJ(source, 'Icu1') and Roll(3)==3 then
set bj_lastCreatedUnit=CreateUnit(udg_Spell__DummyOwner,'ndum',GetUnitX(target),GetUnitY(target),0)
call UnitApplyTimedLifeBJ( 1.00, 'BTLF', GetLastCreatedUnit() )
call UnitAddAbilityBJ( 'Au00', GetLastCreatedUnit() )
call IssueTargetOrder(GetLastCreatedUnit(), "slow", target)
endif
endfunction
function Trig_Claws_passive_Conditions takes nothing returns boolean
return (UnitHasItemOfTypeBJ(udg_DamageEventSource, 'Icu1') and IsAttackValid())
endfunction
function Trig_Claws_passive_Actions takes nothing returns nothing
if Roll(3)==3 then
set bj_lastCreatedUnit=CreateUnit(udg_Spell__DummyOwner,'ndum',GetUnitX(udg_DamageEventTarget),GetUnitY(udg_DamageEventTarget),0)
call UnitApplyTimedLifeBJ( 1.00, 'BTLF', GetLastCreatedUnit() )
call UnitAddAbilityBJ( 'Au00', GetLastCreatedUnit() )
call IssueTargetOrder(GetLastCreatedUnit(), "slow", udg_DamageEventTarget)
endif
endfunction
//===========================================================================
function InitTrig_Claws_passive takes nothing returns nothing
set gg_trg_Claws_passive = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Claws_passive, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Claws_passive, Condition( function Trig_Claws_passive_Conditions ) )
call TriggerAddAction( gg_trg_Claws_passive, function Trig_Claws_passive_Actions )
endfunction
function Trig_Scroll_stacking_Conditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == 'Ia07' or GetItemTypeId(GetManipulatedItem()) == 'Ia08'
endfunction
function Trig_Scroll_stacking_Actions takes nothing returns nothing
local integer Dex = 1
local integer DexEnd = 6
loop
exitwhen Dex > DexEnd
if GetItemTypeId(UnitItemInSlotBJ(GetTriggerUnit(), Dex)) == GetItemTypeId(GetManipulatedItem()) and UnitItemInSlotBJ(GetTriggerUnit(), Dex) != GetManipulatedItem() then
call SetItemCharges( UnitItemInSlotBJ(GetTriggerUnit(), Dex), GetItemCharges(UnitItemInSlotBJ(GetTriggerUnit(), Dex))+GetItemCharges(GetManipulatedItem()))
call RemoveItem(GetManipulatedItem())
set Dex = 7
endif
set Dex = Dex + 1
endloop
endfunction
//===========================================================================
function InitTrig_Consumable_stacking takes nothing returns nothing
set gg_trg_Consumable_stacking = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Consumable_stacking, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Consumable_stacking, Condition( function Trig_Scroll_stacking_Conditions ) )
call TriggerAddAction( gg_trg_Consumable_stacking, function Trig_Scroll_stacking_Actions )
endfunction
function Trig_Eat_the_meat_Conditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == 'Ia04'
endfunction
function Trig_Eat_the_meat_Actions takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
local integer i_max
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),600,null)
set i_max = BlzGroupGetSize(g)-1
loop
if GetOwningPlayer(BlzGroupUnitAt(g,i))==Player(PLAYER_NEUTRAL_AGGRESSIVE) then
call IssuePointOrder(BlzGroupUnitAt(g,i),"attack",GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()))
endif
set i = i+1
exitwhen i > i_max
endloop
call DestroyGroup(g)
set g = null
endfunction
//===========================================================================
function InitTrig_Eat_the_meat takes nothing returns nothing
set gg_trg_Eat_the_meat = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Eat_the_meat, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( gg_trg_Eat_the_meat, Condition( function Trig_Eat_the_meat_Conditions ) )
call TriggerAddAction( gg_trg_Eat_the_meat, function Trig_Eat_the_meat_Actions )
endfunction
function Trig_Talent_speech_Conditions takes nothing returns boolean
return OrderId2String(GetIssuedOrderId()) == "berserk"
endfunction
function Trig_Talent_speech_Actions takes nothing returns nothing
local integer d14 = GetRandomInt(1,14)
local string T = udg_E_SpeechLineX[GetUnitUserData(GetTriggerUnit())]
if d14 < 4 then
set T = udg_E_SpeechLine1[GetUnitUserData(GetTriggerUnit())]
elseif d14 < 7 then
set T = udg_E_SpeechLine2[GetUnitUserData(GetTriggerUnit())]
elseif d14 < 10 then
set T = udg_E_SpeechLine3[GetUnitUserData(GetTriggerUnit())]
elseif d14 < 13 then
set T = udg_E_SpeechLine4[GetUnitUserData(GetTriggerUnit())]
endif
if GetLocalPlayer()==GetOwningPlayer(GetTriggerUnit()) then
call DoTransmissionBasicsXYBJ(GetUnitTypeId(GetTriggerUnit()),GetPlayerColor(GetOwningPlayer(GetTriggerUnit())),GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),null,GetHeroProperName(GetTriggerUnit()),T,5)
endif
endfunction
//===========================================================================
function InitTrig_Talent_speech takes nothing returns nothing
set gg_trg_Talent_speech = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Talent_speech, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Talent_speech, Condition( function Trig_Talent_speech_Conditions ) )
call TriggerAddAction( gg_trg_Talent_speech, function Trig_Talent_speech_Actions )
endfunction
function PaladinTalentAction takes unit u, integer level returns nothing
local unit dum = null
if level == 0 then
return
endif
set dum = CreateUnit(GetOwningPlayer(u),udg_Spell__DummyType,GetUnitX(u),GetUnitY(u),0)
call UnitApplyTimedLife(dum,'BTLF',1)
call UnitAddAbility(dum,'Apad')
call IssueTargetOrder(dum,"rejuvination",u)
set dum = null
endfunction
function WingRemoveBuff takes nothing returns nothing
local unit u = null
set bj_forLoopAIndex = 1
set bj_forLoopAIndexEnd = BlzGroupGetSize(udg_A_WingCasterGroup)
loop
set u=BlzGroupUnitAt(udg_A_WingCasterGroup,bj_forLoopAIndex-1)
if GetExpiredTimer()==udg_A_WingCasterTimer[GetUnitUserData(u)] then
call UnitRemoveAbility(u,'Apab')
call GroupRemoveUnit(udg_A_WingCasterGroup,u)
set udg_A_WingLevel[GetUnitUserData(u)] = 0.00
set bj_forLoopAIndex = bj_forLoopAIndexEnd
endif
set bj_forLoopAIndex = bj_forLoopAIndex + 1
exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
endloop
set u = null
endfunction
function Trig_Vampire_overlord_talent_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and not(IsUnitIllusion(GetTriggerUnit())) and (GetUnitAbilityLevel(udg_P_Hero[GetPlayerId(GetOwningPlayer(GetKillingUnitBJ()))+1],'Tvat') > 0 or GetUnitAbilityLevel(GetKillingUnitBJ(),'Tvat') > 0)
endfunction
function Trig_Vampire_overlord_talent_Actions takes nothing returns nothing
local unit u = null
local unit killer = GetKillingUnitBJ()
local integer i = 0
local integer iEnd = 5
loop
exitwhen i > iEnd
set u = CreateUnit(GetOwningPlayer(killer),'ndum',GetUnitX(killer),GetUnitY(killer),60*i)
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Avad')
call SetUnitAbilityLevel(u,'Avad',GetUnitAbilityLevel(killer,'Tvat'))
call IssuePointOrder(u,"carrionswarm",GetUnitX(u)+20*CosBJ(GetUnitFacing(u)),GetUnitY(u)+20*SinBJ(GetUnitFacing(u)))
set u = null
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_Vampire_overlord_talent takes nothing returns nothing
set gg_trg_Vampire_overlord_talent = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vampire_overlord_talent, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Vampire_overlord_talent, Condition( function Trig_Vampire_overlord_talent_Conditions ) )
call TriggerAddAction( gg_trg_Vampire_overlord_talent, function Trig_Vampire_overlord_talent_Actions )
endfunction
function BlinkStrikeAction takes nothing returns nothing
local unit u
set bj_forLoopAIndex = 1
set bj_forLoopAIndexEnd = BlzGroupGetSize(udg_A_VampBlinkGroup)
loop
set u=BlzGroupUnitAt(udg_A_VampBlinkGroup,bj_forLoopAIndex-1)
if GetExpiredTimer()==udg_A_VampBlinkTimer[GetUnitUserData(u)] then
call UnitRemoveAbility(u,'Apab')
call GroupRemoveUnit(udg_A_VampBlinkGroup,u)
set udg_A_VampBlinkSteal[GetUnitUserData(u)] = 0.00
set udg_A_VampBlinkTarget[GetUnitUserData(u)] = null
set bj_forLoopAIndex = bj_forLoopAIndexEnd
endif
set bj_forLoopAIndex = bj_forLoopAIndex + 1
exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
endloop
set u = null
endfunction
function Trig_Huntground_fx_Actions takes nothing returns nothing
local unit u = CreateUnit(udg_Spell__CasterOwner,udg_Spell__DummyType,GetUnitX(udg_Spell__Caster),GetUnitY(udg_Spell__Caster),0)
local real A = 18
local integer i = 0
local integer iEnd = 19
set udg_Spell__Duration = 12
set udg_Spell__Time = udg_Spell__Interval
set udg_A_UnholyGroundX[GetUnitUserData(udg_Spell__Caster)] = GetUnitX(udg_Spell__Caster)
set udg_A_UnholyGroundY[GetUnitUserData(udg_Spell__Caster)] = GetUnitY(udg_Spell__Caster)
// set udg_A_UnholyGroundAura[udg_Spell__Index] = CreateUnit(udg_Spell__CasterOwner,udg_Spell__DummyType,udg_A_UnholyGroundX[GetUnitUserData(udg_Spell__Caster)],udg_A_UnholyGroundY[GetUnitUserData(udg_Spell__Caster)],0)
// set udg_A_UnholyGroundDummyGroup[udg_Spell__Index] = CreateGroup()
call UnitAddAbility(u,'Avbc')
call SetUnitAbilityLevel(u,'Avbc',udg_Spell__Level)
call UnitAddAbility(u,'Avbd')
call SetUnitAbilityLevel(u,'Avbd',udg_Spell__Level)
call UnitApplyTimedLifeBJ( 12, 'BTLF', u )
loop
exitwhen i > iEnd
// call SaveUnitHandle(udg_Spell__Hash,udg_Spell__Index,i,CreateUnit(udg_Spell__CasterOwner,udg_Spell__DummyType,GetUnitX(udg_Spell__Caster)+400*CosBJ(A*i),GetUnitY(udg_Spell__Caster)+400*SinBJ(A*i),A*i))
// set u = CreateUnit(udg_Spell__CasterOwner,udg_Spell__DummyType,udg_A_UnholyGroundX[GetUnitUserData(udg_Spell__Caster)]+400*CosBJ(A*i),udg_A_UnholyGroundY[GetUnitUserData(udg_Spell__Caster)]+400*SinBJ(A*i),A*i)
// set udg_A_UnholyGroundFX[GetUnitUserData(u)] = AddSpecialEffect("war3.w3mod:Abilities\\Spells\\Demon\\DarkConversion\\ZombifyTarget.mdl",GetUnitX(u),GetUnitY(u))
// call GroupAddUnit(udg_A_UnholyGroundDummyGroup[udg_Spell__Index],u)
call SaveEffectHandle(udg_Spell__Hash,udg_Spell__Index,i,AddSpecialEffect("Abilities\\Spells\\Demon\\DarkConversion\\ZombifyTarget.mdl",GetUnitX(udg_Spell__Caster)+400*CosBJ(A*i),GetUnitY(udg_Spell__Caster)+400*SinBJ(A*i)))
set i = i + 1
endloop
set u = null
endfunction
//===========================================================================
function InitTrig_Huntground_fx takes nothing returns nothing
set gg_trg_Huntground_fx = CreateTrigger( )
call TriggerAddAction( gg_trg_Huntground_fx, function Trig_Huntground_fx_Actions )
endfunction
function Trig_Warlock_talent_Conditions takes nothing returns boolean
return GetKillingUnitBJ() != null
endfunction
function Trig_Warlock_talent_Actions takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
local integer i_max
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),600,null)
set i_max = BlzGroupGetSize(g)-1
loop
if GetUnitAbilityLevel(BlzGroupUnitAt(g,i),'Twat') > 0 and IsUnitAlly(BlzGroupUnitAt(g,i), GetOwningPlayer(GetTriggerUnit())) then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",BlzGroupUnitAt(g,i),"origin"))
call SetWidgetLife(GetEnumUnit(),GetWidgetLife(GetEnumUnit())+60*GetUnitAbilityLevel(BlzGroupUnitAt(g,i),'Twat')-40)
endif
set i = i + 1
exitwhen i > i_max
endloop
call DestroyGroup(g)
set g = null
endfunction
//===========================================================================
function InitTrig_Warlock_talent takes nothing returns nothing
set gg_trg_Warlock_talent = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Warlock_talent, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Warlock_talent, Condition( function Trig_Warlock_talent_Conditions ) )
call TriggerAddAction( gg_trg_Warlock_talent, function Trig_Warlock_talent_Actions )
endfunction
function Trig_Psychic_talent_Conditions takes nothing returns boolean
return (GetUnitAbilityLevel(GetTriggerUnit(),'Topt') > 0 and (GetSpellAbilityId()=='Aop1' or GetSpellAbilityId()=='Aop2' or GetSpellAbilityId()=='Aop3' or GetSpellAbilityId()=='Aopu'))
endfunction
function Trig_Psychic_talent_Actions takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
local integer i_max
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),300,null)
set i_max = BlzGroupGetSize(g)-1
if i_max>-1 then
loop
if not(IsUnitType(BlzGroupUnitAt(g,i),UNIT_TYPE_STRUCTURE)) and IsUnitEnemy(BlzGroupUnitAt(g,i), GetOwningPlayer(GetTriggerUnit())) and Roll(4) <= GetUnitAbilityLevel(GetTriggerUnit(),'Topt') then
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(GetTriggerUnit()),udg_Spell__DummyType,GetUnitX(BlzGroupUnitAt(g,i)),GetUnitY(BlzGroupUnitAt(g,i)),0)
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
call UnitAddAbility(GetLastCreatedUnit(),'Aopa')
call IssueTargetOrder(GetLastCreatedUnit(),"slow",GetEnumUnit())
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(g)
set g = null
endfunction
//===========================================================================
function InitTrig_Psychic_talent takes nothing returns nothing
set gg_trg_Psychic_talent = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Psychic_talent, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Psychic_talent, Condition( function Trig_Psychic_talent_Conditions ) )
call TriggerAddAction( gg_trg_Psychic_talent, function Trig_Psychic_talent_Actions )
endfunction
function Trig_Mana_flare_damage_Conditions takes nothing returns boolean
return UnitHasBuffBJ(GetTriggerUnit(), 'Bsib') and BlzGetUnitAbilityManaCost(GetTriggerUnit(), GetSpellAbilityId(), GetUnitAbilityLevel(GetTriggerUnit(), GetSpellAbilityId())-1)>0
endfunction
function Trig_Mana_flare_damage_Actions takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
local integer i_max
local real ScaleFactor
local real Dmge
local unit u
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),600,null)
if BlzGroupGetSize(g) > 0 then
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\ManaFlare\\ManaFlareBoltImpact.mdl",GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit())))
set i_max = BlzGroupGetSize(g)-1
loop
set u = BlzGroupUnitAt(g,i)
set ScaleFactor = I2R(GetUnitAbilityLevel(u,'Asia'))/5
if ScaleFactor > 0 and IsUnitEnemy(u,GetOwningPlayer(GetTriggerUnit())) then
set Dmge = I2R(BlzGetUnitAbilityManaCost(GetTriggerUnit(), GetSpellAbilityId(), GetUnitAbilityLevel(GetTriggerUnit(), GetSpellAbilityId())-1))*ScaleFactor
call UnitDamageTargetBJ( u, GetTriggerUnit(), Dmge, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(g)
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_Spellbreaker_mana_flare takes nothing returns nothing
set gg_trg_Spellbreaker_mana_flare = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spellbreaker_mana_flare, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spellbreaker_mana_flare, Condition( function Trig_Mana_flare_damage_Conditions ) )
call TriggerAddAction( gg_trg_Spellbreaker_mana_flare, function Trig_Mana_flare_damage_Actions )
endfunction
function Trig_Night_blessing_damage_block_Conditions takes nothing returns boolean
return (GetUnitAbilityLevel(udg_DamageEventTarget,'Aty3') > 0 and (GetTimeOfDay()>18 or GetTimeOfDay()<6))
endfunction
function Trig_Night_blessing_damage_block_Actions takes nothing returns nothing
if udg_IsDamageSpell or (IsAttackValid() and udg_IsDamageRanged) then
set udg_DamageEventAmount = udg_DamageEventAmount*(0.88-0.06*I2R(GetUnitAbilityLevel(udg_DamageEventTarget,'Aty3')))
endif
endfunction
//===========================================================================
function InitTrig_Night_blessing_damage_block takes nothing returns nothing
set gg_trg_Night_blessing_damage_block = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Night_blessing_damage_block, "udg_DamageModifierEvent", EQUAL, 4.00 )
call TriggerAddCondition( gg_trg_Night_blessing_damage_block, Condition( function Trig_Night_blessing_damage_block_Conditions ) )
call TriggerAddAction( gg_trg_Night_blessing_damage_block, function Trig_Night_blessing_damage_block_Actions )
endfunction
function Trig_Blue_ranger_bonus_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO) and not(IsUnitIllusionBJ(GetTriggerUnit())) and IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(GetKillingUnitBJ()))
endfunction
function Ranger_AgiGain takes unit u returns nothing
call ModifyHeroStat(bj_HEROSTAT_AGI,u,bj_MODIFYMETHOD_ADD,GetUnitAbilityLevel(u,'Tbrt')*2-1)
endfunction
function Trig_Blue_ranger_bonus_Actions takes nothing returns nothing
if GetUnitAbilityLevel(GetKillingUnitBJ(),'Tbrt') > 0 then
call Ranger_AgiGain(GetKillingUnitBJ())
elseif GetUnitAbilityLevel(udg_P_Hero[GetPlayerId(GetOwningPlayer(GetKillingUnitBJ()))+1],'Tbrt') > 0 then
call Ranger_AgiGain(udg_P_Hero[GetPlayerId(GetOwningPlayer(GetKillingUnitBJ()))+1])
endif
endfunction
//===========================================================================
function InitTrig_Blue_ranger_bonus takes nothing returns nothing
set gg_trg_Blue_ranger_bonus = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Blue_ranger_bonus, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Blue_ranger_bonus, Condition( function Trig_Blue_ranger_bonus_Conditions ) )
call TriggerAddAction( gg_trg_Blue_ranger_bonus, function Trig_Blue_ranger_bonus_Actions )
endfunction
function Trig_Haunt_teleport_Conditions takes nothing returns boolean
return (GetSpellAbilityId() == 'ALcb' and UnitAlive(udg_A_GhostyDummy[GetUnitUserData(GetTriggerUnit())]))
endfunction
function Trig_Haunt_teleport_Actions takes nothing returns nothing
local real Sx = GetUnitX(GetTriggerUnit())
local real Sy = GetUnitY(GetTriggerUnit())
local real Tx = GetUnitX(udg_A_GhostyDummy[GetUnitUserData(GetTriggerUnit())])
local real Ty = GetUnitY(udg_A_GhostyDummy[GetUnitUserData(GetTriggerUnit())])
local unit u = CreateUnit(GetOwningPlayer(GetTriggerUnit()),udg_Spell__DummyType,Tx,Ty,0)
local group g = CreateGroup()
set bj_lastCreatedEffect = AddSpecialEffect("Units\\undead\\HeroLichCIN\\HeroLichCIN",Sx,Sy)
call BlzSetSpecialEffectAlpha( GetLastCreatedEffectBJ(), 170 )
call BlzSetSpecialEffectColorByPlayer( GetLastCreatedEffectBJ(), GetOwningPlayer(GetTriggerUnit()) )
call BlzSetSpecialEffectYaw( GetLastCreatedEffectBJ(), Deg2Rad(GetUnitFacing(GetTriggerUnit())) )
call BlzPlaySpecialEffect( GetLastCreatedEffectBJ(), ANIM_TYPE_DEATH )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call KillUnit( udg_A_GhostyDummy[GetUnitUserData(GetTriggerUnit())] )
call SetUnitX(GetTriggerUnit(),Tx)
call SetUnitY(GetTriggerUnit(),Ty)
call SetUnitScale(u,2,2,2)
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'ALcc')
call SetUnitAbilityLevel(u,'ALcc',GetUnitAbilityLevel(GetTriggerUnit(),'ALc3'))
call IssuePointOrder(u,"silence",Tx,Ty)
call GroupEnumUnitsInRange(g,Tx,Ty,200,null)
set bj_forLoopAIndex = 0
set bj_forLoopAIndexEnd = BlzGroupGetSize(g)-1
loop
if not(IsUnitType(BlzGroupUnitAt(g,bj_forLoopAIndex),UNIT_TYPE_STRUCTURE)) and IsUnitEnemy(BlzGroupUnitAt(g,bj_forLoopAIndex), GetOwningPlayer(GetTriggerUnit())) then
call UnitDamageTargetBJ(GetTriggerUnit(),BlzGroupUnitAt(g,bj_forLoopAIndex),40*GetUnitAbilityLevel(GetTriggerUnit(),'ALc3'),ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC)
endif
set bj_forLoopAIndex = bj_forLoopAIndex+1
exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
endloop
call DestroyGroup(g)
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_Haunt_teleport takes nothing returns nothing
set gg_trg_Haunt_teleport = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Haunt_teleport, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Haunt_teleport, Condition( function Trig_Haunt_teleport_Conditions ) )
call TriggerAddAction( gg_trg_Haunt_teleport, function Trig_Haunt_teleport_Actions )
endfunction
function Trig_Frost_nova_armor_fx_Conditions takes nothing returns boolean
return (IsAttackValid() and UnitHasBuffBJ(udg_DamageEventTarget, 'BLca'))
endfunction
function Trig_Frost_nova_armor_fx_Actions takes nothing returns nothing
local real Tx = GetUnitX(udg_DamageEventSource)
local real Ty = GetUnitY(udg_DamageEventSource)
if Roll(20) <= udg_A_FrostArmorFactor[GetUnitUserData(udg_DamageEventTarget)]+4 then
set bj_lastCreatedUnit = CreateUnit(udg_A_FrostArmorOwner[GetUnitUserData(udg_DamageEventTarget)],udg_Spell__DummyType,Tx,Ty,0)
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
call UnitAddAbility(GetLastCreatedUnit(),'ALca')
call IssueTargetOrder(GetLastCreatedUnit(),"frostnova",udg_DamageEventSource)
endif
endfunction
//===========================================================================
function InitTrig_Frost_nova_armor_fx takes nothing returns nothing
set gg_trg_Frost_nova_armor_fx = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Frost_nova_armor_fx, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Frost_nova_armor_fx, Condition( function Trig_Frost_nova_armor_fx_Conditions ) )
call TriggerAddAction( gg_trg_Frost_nova_armor_fx, function Trig_Frost_nova_armor_fx_Actions )
endfunction
function Trig_Tauren_chief_talent_init_Conditions takes nothing returns boolean
if GetUnitAbilityLevelSwapped('Tott', GetTriggerUnit()) > 0 and (GetSpellAbilityId()=='Aot1' or GetSpellAbilityId()=='Aot2') then
return true
endif
return false
endfunction
function Trig_Tauren_chief_talent_init_Actions takes nothing returns nothing
local real X = GetUnitX(GetTriggerUnit())+200*CosBJ(GetUnitFacing(GetTriggerUnit()))
local real Y = GetUnitY(GetTriggerUnit())+200*SinBJ(GetUnitFacing(GetTriggerUnit()))
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(GetTriggerUnit()),'ndum',X,Y,0)
set udg_A_PullMaster[GetUnitUserData(GetLastCreatedUnit())] = GetTriggerUnit()
call UnitApplyTimedLifeBJ( 1.00, 'BTLF', GetLastCreatedUnit() )
call UnitAddAbilityBJ( 'Aotb', GetLastCreatedUnit() )
call IssueImmediateOrderBJ( GetLastCreatedUnit(), "roar" )
endfunction
//===========================================================================
function InitTrig_Tauren_chief_talent_init takes nothing returns nothing
set gg_trg_Tauren_chief_talent_init = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Tauren_chief_talent_init, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Tauren_chief_talent_init, Condition( function Trig_Tauren_chief_talent_init_Conditions ) )
call TriggerAddAction( gg_trg_Tauren_chief_talent_init, function Trig_Tauren_chief_talent_init_Actions )
endfunction
function Trig_Berserk_lifesteal_Conditions takes nothing returns boolean
return (IsAttackValid() and udg_A_BerserkOn[GetUnitUserData(udg_DamageEventSource)])
endfunction
function Trig_Berserk_lifesteal_Actions takes nothing returns nothing
local real ToHeal = udg_A_BerserkSteal[GetUnitUserData(udg_DamageEventSource)]*udg_DamageEventAmount/100
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",udg_DamageEventSource,"origin"))
if GetWidgetLife(udg_DamageEventSource)+ToHeal > GetUnitState(udg_DamageEventSource,UNIT_STATE_MAX_LIFE) then
set udg_A_BerserkOverLife[GetUnitUserData(udg_DamageEventSource)] = udg_A_BerserkOverLife[GetUnitUserData(udg_DamageEventSource)] + R2I(ToHeal)
call BlzSetUnitMaxHP(udg_DamageEventSource, BlzGetUnitMaxHP(udg_DamageEventSource) + R2I(ToHeal))
endif
call SetWidgetLife(udg_DamageEventSource, GetWidgetLife(udg_DamageEventSource) + ToHeal)
endfunction
//===========================================================================
function InitTrig_Berserk_lifesteal takes nothing returns nothing
set gg_trg_Berserk_lifesteal = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Berserk_lifesteal, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Berserk_lifesteal, Condition( function Trig_Berserk_lifesteal_Conditions ) )
call TriggerAddAction( gg_trg_Berserk_lifesteal, function Trig_Berserk_lifesteal_Actions )
endfunction
function Trig_Demonknight_talent_Conditions takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('Tdbt', udg_DamageEventTarget) > 0 ) ) then
return false
endif
return true
endfunction
function Trig_Demonknight_talent_Actions takes nothing returns nothing
local real MaxAngle = 60
local real dy = GetUnitY(udg_DamageEventSource) - GetUnitY(udg_DamageEventTarget)
local real dx = GetUnitX(udg_DamageEventSource) - GetUnitX(udg_DamageEventTarget)
local real Deg0 = GetUnitFacing(udg_DamageEventTarget)
local real Deg1 = Atan2BJ(dy,dx)
if Deg1 < 0 then
set Deg1 = Deg1+360
endif
if RAbsBJ(Deg1-Deg0) <= MaxAngle or 360-RAbsBJ(Deg1-Deg0) <= MaxAngle then
set udg_DamageEventAmount = ( udg_DamageEventAmount * ( 1.05 - ( 0.15 * I2R(GetUnitAbilityLevelSwapped('Tdbt', udg_DamageEventTarget)) ) ) )
endif
endfunction
//===========================================================================
function InitTrig_Demonknight_talent takes nothing returns nothing
set gg_trg_Demonknight_talent = CreateTrigger( )
call TriggerAddCondition( gg_trg_Demonknight_talent, Condition( function Trig_Demonknight_talent_Conditions ) )
call TriggerAddAction( gg_trg_Demonknight_talent, function Trig_Demonknight_talent_Actions )
endfunction
function WardenTalentAction takes unit source, integer level returns nothing
local unit u = CreateUnit(GetOwningPlayer(source),'ndum',GetUnitX(source),GetUnitY(source),0)
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Awdd')
call SetUnitAbilityLevel(u,'Awdd',level)
call IssueImmediateOrder(u,"fanofknives")
set u = null
endfunction
function Trig_Goblin_talent_trigger_Conditions takes nothing returns boolean
return (GetUnitAbilityLevel(udg_DamageEventTarget,'Tgat') > 0 and IsUnitEnemy(udg_DamageEventSource,GetOwningPlayer(udg_DamageEventTarget)) and (udg_IsDamageRanged or udg_IsDamageMelee))
endfunction
function Trig_Goblin_talent_trigger_Actions takes nothing returns nothing
local integer level = GetUnitAbilityLevel(udg_DamageEventTarget,'Tgat')
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(udg_DamageEventTarget),'ndga',GetUnitX(udg_DamageEventTarget),GetUnitY(udg_DamageEventTarget),0)
call UnitApplyTimedLife( GetLastCreatedUnit(), 'BTLF', 10.00 )
set udg_A_GoblinArmorMaster[GetUnitUserData(GetLastCreatedUnit())] = udg_DamageEventTarget
call UnitAddAbility(GetLastCreatedUnit(),'Tgat')
call SetUnitAbilityLevel(GetLastCreatedUnit(),'Tgat',level)
call BlzSetUnitArmor( udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + I2R(level) )
// call BlzSetUnitArmor( udg_DamageEventTarget, ( BlzGetUnitArmor(udg_DamageEventTarget) + udg_A_GoblinArmor[GetUnitUserData(GetLastCreatedUnit())] ) )
endfunction
//===========================================================================
function InitTrig_Goblin_talent_trigger takes nothing returns nothing
set gg_trg_Goblin_talent_trigger = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Goblin_talent_trigger, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Goblin_talent_trigger, Condition( function Trig_Goblin_talent_trigger_Conditions ) )
call TriggerAddAction( gg_trg_Goblin_talent_trigger, function Trig_Goblin_talent_trigger_Actions )
endfunction
function EnrageRemoveBuff takes nothing returns nothing
local integer i = 0
local integer i_max = BlzGroupGetSize(udg_A_ChemRageGroup)-1
local real hp
local unit u
loop
set u = BlzGroupUnitAt(udg_A_ChemRageGroup,i)
if GetExpiredTimer()==udg_A_ChemRageTimer[GetUnitUserData(u)] then
set hp = GetWidgetLife(u)
call DestroyTimer(GetExpiredTimer())
call GroupRemoveUnit(udg_A_ChemRageGroup,u)
call AddUnitAnimationProperties(u,"alternate",false)
call SetHeroStr(u,GetHeroStr(u,false)-udg_A_ChemRageBonus[GetUnitUserData(u)]*10,true)
call SetUnitState(u,UNIT_STATE_LIFE,hp)
set i = i_max
endif
set i = i + 1
exitwhen i > i_max
endloop
set u = null
endfunction
function Trig_Giant_talent_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO) and not(IsUnitIllusion(GetTriggerUnit()))
endfunction
function Trig_Giant_talent_Actions takes nothing returns nothing
local integer i = 0
local integer i_max
local unit u
local group g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),400,null)
set i_max = BlzGroupGetSize(g)-1
if i_max>-1 then
loop
set u = BlzGroupUnitAt(g,i)
if GetUnitAbilityLevel(u,'Tsgt') > 0 and GetUnitAbilityLevel(u,'Asg1') > 0 and IsUnitEnemy(GetTriggerUnit(),GetOwningPlayer(u)) and Roll(3)<=GetUnitAbilityLevel(u,'Tsgt') then
call BlzEndUnitAbilityCooldown( u, 'Asg1' )
call DestroyEffect( AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIre\\AIreTarget.mdl",u,"origin") )
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(g)
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_Giant_talent takes nothing returns nothing
set gg_trg_Giant_talent = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Giant_talent, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Giant_talent, Condition( function Trig_Giant_talent_Conditions ) )
call TriggerAddAction( gg_trg_Giant_talent, function Trig_Giant_talent_Actions )
endfunction
function Trig_Sea_elemental_recall_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'Asgc'
endfunction
function Trig_Sea_elemental_recall_Actions takes nothing returns nothing
local integer i = 0
local integer i_max
local unit u
local group Group = GetUnitsOfPlayerAndTypeId(GetOwningPlayer(GetTriggerUnit()),'hsgs')
set i_max = BlzGroupGetSize(Group)-1
if i_max>-1 then
loop
set u = BlzGroupUnitAt(Group,i)
set bj_lastCreatedEffect=AddSpecialEffect("GreatSeaElemental.mdx",GetUnitX(u),GetUnitY(u))
call BlzSetSpecialEffectColorByPlayer( GetLastCreatedEffectBJ(), GetOwningPlayer(GetTriggerUnit()) )
call BlzSetSpecialEffectYaw( GetLastCreatedEffectBJ(), Deg2Rad(GetUnitFacing(u)) )
call BlzPlaySpecialEffect( GetLastCreatedEffectBJ(), ANIM_TYPE_DEATH )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call SetUnitPosition(u,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()))
call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl",u,"origin"))
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(Group)
set Group = null
set u = null
endfunction
//===========================================================================
function InitTrig_Sea_elemental_recall takes nothing returns nothing
set gg_trg_Sea_elemental_recall = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Sea_elemental_recall, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Sea_elemental_recall, Condition( function Trig_Sea_elemental_recall_Conditions ) )
call TriggerAddAction( gg_trg_Sea_elemental_recall, function Trig_Sea_elemental_recall_Actions )
endfunction
function SatyrRemoveBuff takes nothing returns nothing
local unit u
local integer i = 1
local integer i_max = BlzGroupGetSize(udg_A_SatyrInvisGroup)
loop
set u = BlzGroupUnitAt(udg_A_SatyrInvisGroup,i-1)
if GetExpiredTimer()==udg_A_SatyrInvisTimer[GetUnitUserData(u)] then
call UnitRemoveAbility(u,'Asae')
call GroupRemoveUnit(udg_A_SatyrInvisGroup,u)
set i = i_max
endif
set i = i + 1
exitwhen i > i_max
endloop
set u = null
endfunction
function Trig_Meteor_rain_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'Asa3'
endfunction
function Trig_Meteor_rain_Actions takes nothing returns nothing
local integer i = 0
local integer i_max
local group g = CreateGroup()
local unit u
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),650,null)
set i_max = BlzGroupGetSize(g)-1
if i_max>-1 then
loop
set u = BlzGroupUnitAt(g,i)
if BlzIsUnitSelectable(u) and IsUnitEnemy(u,GetOwningPlayer(GetTriggerUnit())) and not(IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
call DestroyEffect(AddSpecialEffect("Units\\Demon\\Infernal\\InfernalBirth.mdl",GetUnitX(u),GetUnitY(u)))
set bj_lastCreatedUnit=CreateUnit(GetOwningPlayer(GetTriggerUnit()),'ndum',GetUnitX(u),GetUnitY(u),0)
set udg_A_MeteorMaster[GetUnitUserData(GetLastCreatedUnit())]=GetTriggerUnit()
set udg_A_MeteorLevel[GetUnitUserData(GetLastCreatedUnit())]=GetUnitAbilityLevel(GetTriggerUnit(),'Asa3')
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(g)
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_Meteor_rain takes nothing returns nothing
set gg_trg_Meteor_rain = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Meteor_rain, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Meteor_rain, Condition( function Trig_Meteor_rain_Conditions ) )
call TriggerAddAction( gg_trg_Meteor_rain, function Trig_Meteor_rain_Actions )
endfunction
function Trig_Meteor_damage_Conditions takes nothing returns boolean
return udg_A_MeteorMaster[GetUnitUserData(GetTriggerUnit())] != null
endfunction
function Trig_Meteor_damage_Actions takes nothing returns nothing
local integer i = 0
local integer i_max
local group g = CreateGroup()
local unit u
call GroupEnumUnitsInRange(g,GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),150,null)
set i_max = BlzGroupGetSize(g)-1
if i_max>-1 then
loop
set u = BlzGroupUnitAt(g,i)
if BlzIsUnitSelectable(u) and IsUnitEnemy(u,GetOwningPlayer(GetTriggerUnit())) and not(IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
set bj_lastCreatedUnit=CreateUnit(GetOwningPlayer(GetTriggerUnit()),'ndum',GetUnitX(u),GetUnitY(u),0)
call UnitApplyTimedLife(GetLastCreatedUnit(),'BTLF',1)
call UnitAddAbility(GetLastCreatedUnit(),'Asab')
call IssueTargetOrder(GetLastCreatedUnit(),"slow",u)
call UnitDamageTargetBJ(udg_A_MeteorMaster[GetUnitUserData(GetTriggerUnit())],u,udg_A_MeteorLevel[GetUnitUserData(GetTriggerUnit())]*40+20,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC)
endif
set i = i+1
exitwhen i > i_max
endloop
endif
call DestroyGroup(g)
set g = null
set u = null
set udg_A_MeteorMaster[GetUnitUserData(GetTriggerUnit())] = null
endfunction
//===========================================================================
function InitTrig_Meteor_damage takes nothing returns nothing
set gg_trg_Meteor_damage = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Meteor_damage, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Meteor_damage, Condition( function Trig_Meteor_damage_Conditions ) )
call TriggerAddAction( gg_trg_Meteor_damage, function Trig_Meteor_damage_Actions )
endfunction
function Trig_Bite_fx_Conditions takes nothing returns boolean
return IsAttackValidOrganic() and GetUnitState(udg_DamageEventTarget,UNIT_STATE_MAX_MANA)>0 and GetUnitAbilityLevel(udg_DamageEventSource,'Afh3')>0 and not(IsUnitType(udg_DamageEventTarget,UNIT_TYPE_MAGIC_IMMUNE))
endfunction
function Trig_Bite_fx_Actions takes nothing returns nothing
local real Mana = GetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA)
local real ToBurn = GetUnitAbilityLevel(udg_DamageEventSource,'Afh3')*30
if Roll(3)==3 then
call SetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA,Mana-ToBurn)
call SetUnitState(udg_DamageEventSource,UNIT_STATE_MANA,GetUnitState(udg_DamageEventSource,UNIT_STATE_MANA)+Mana-GetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA))
if ToBurn>Mana then
set udg_DamageEventAmount=udg_DamageEventAmount+ToBurn-Mana
endif
set bj_lastCreatedEffect=AddSpecialEffectTarget("war3.w3mod:Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl",udg_DamageEventTarget,"head")
call BlzPlaySpecialEffect(GetLastCreatedEffectBJ(),ANIM_TYPE_DEATH)
call DestroyEffect(GetLastCreatedEffectBJ())
endif
endfunction
//===========================================================================
function InitTrig_Bite_fx takes nothing returns nothing
set gg_trg_Bite_fx = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Bite_fx, "udg_DamageModifierEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Bite_fx, Condition( function Trig_Bite_fx_Conditions ) )
call TriggerAddAction( gg_trg_Bite_fx, function Trig_Bite_fx_Actions )
endfunction
function MinoBonus_Filter takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and GetFilterUnit()!=udg_DamageEventTarget and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(udg_DamageEventSource)) and not(IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)) and BlzIsUnitSelectable(GetFilterUnit())
endfunction
function Trig_Minotaur_bonus_Conditions takes nothing returns boolean
return IsAttackValid() and GetUnitAbilityLevel(udg_DamageEventSource,'Tmtt')>0
endfunction
function Trig_Minotaur_bonus_Actions takes nothing returns nothing
local group g = CreateGroup()
call GroupEnumUnitsInRange(g, GetUnitX(udg_DamageEventSource), GetUnitY(udg_DamageEventSource), 300, Condition(function MinoBonus_Filter))
call UnitDamageTargetBJ(udg_DamageEventSource,Random_GroupUnit(g),udg_DamageEventAmount*GetUnitAbilityLevel(udg_DamageEventSource,'Tmtt')/2,ATTACK_TYPE_HERO,DAMAGE_TYPE_ENHANCED)
call DestroyGroup(g)
set g = null
endfunction
//===========================================================================
function InitTrig_Minotaur_bonus takes nothing returns nothing
set gg_trg_Minotaur_bonus = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Minotaur_bonus, "udg_AfterDamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Minotaur_bonus, Condition( function Trig_Minotaur_bonus_Conditions ) )
call TriggerAddAction( gg_trg_Minotaur_bonus, function Trig_Minotaur_bonus_Actions )
endfunction
function Trig_Maria_bonus_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO) and not(IsUnitIllusion(GetTriggerUnit())) and IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(GetKillingUnitBJ()))
endfunction
function IntThief_Steal takes unit u, unit Target returns nothing
call ModifyHeroStat(bj_HEROSTAT_INT,u,bj_MODIFYMETHOD_ADD,GetUnitAbilityLevel(u,'Tmat')*2)
call ModifyHeroStat(bj_HEROSTAT_INT,Target,bj_MODIFYMETHOD_ADD,-2)
endfunction
function Trig_Maria_bonus_Actions takes nothing returns nothing
if GetUnitAbilityLevel(GetKillingUnitBJ(),'Tmat') > 0 then
call IntThief_Steal(GetKillingUnitBJ(),GetTriggerUnit())
elseif GetUnitAbilityLevel(udg_P_Hero[GetPlayerId(GetOwningPlayer(GetKillingUnitBJ()))+1],'Tmat') > 0 then
call IntThief_Steal(udg_P_Hero[GetPlayerId(GetOwningPlayer(GetKillingUnitBJ()))+1],GetTriggerUnit())
endif
endfunction
//===========================================================================
function InitTrig_Maria_bonus takes nothing returns nothing
set gg_trg_Maria_bonus = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Maria_bonus, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Maria_bonus, Condition( function Trig_Maria_bonus_Conditions ) )
call TriggerAddAction( gg_trg_Maria_bonus, function Trig_Maria_bonus_Actions )
endfunction
function Trig_Searing_blade_count_Conditions takes nothing returns boolean
return (IsAttackValidAll() and GetUnitAbilityLevelSwapped('Ama3', udg_DamageEventSource) > 0)
endfunction
function Trig_Searing_blade_count_Actions takes nothing returns nothing
set udg_A_SearingBladeCount[GetUnitUserData(udg_DamageEventSource)] = ( udg_A_SearingBladeCount[GetUnitUserData(udg_DamageEventSource)] + 1 )
endfunction
//===========================================================================
function InitTrig_Searing_blade_count takes nothing returns nothing
set gg_trg_Searing_blade_count = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Searing_blade_count, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Searing_blade_count, Condition( function Trig_Searing_blade_count_Conditions ) )
call TriggerAddAction( gg_trg_Searing_blade_count, function Trig_Searing_blade_count_Actions )
endfunction
function Trig_Searing_blade_fx_Conditions takes nothing returns boolean
return (IsAttackValidOrganic() and GetUnitAbilityLevel(udg_DamageEventSource,'Ama3') > 0 and udg_A_SearingBladeCount[GetUnitUserData(udg_DamageEventSource)] >= 9 - GetUnitAbilityLevel(udg_DamageEventSource,'Ama3'))
endfunction
function Trig_Searing_blade_fx_Actions takes nothing returns nothing
local real Sx = GetUnitX(udg_DamageEventSource)
local real Sy = GetUnitY(udg_DamageEventSource)
local real Tx = GetUnitX(udg_DamageEventTarget)
local real Ty = GetUnitY(udg_DamageEventTarget)
local unit u = CreateUnit(GetOwningPlayer(udg_DamageEventSource),'ndum',Sx,Sy,Atan2BJ(Ty-Sy,Tx-Sx))
call UnitApplyTimedLife(u,'BTLF',1)
call UnitAddAbility(u,'Amaa')
call IssueTargetOrder(u,"soulburn",udg_DamageEventTarget)
call DestroyEffect(AddSpecialEffectTarget("Piercing Thrust.mdx",u,"origin"))
set u = null
set udg_A_SearingBladeCount[GetUnitUserData(udg_DamageEventSource)] = udg_A_SearingBladeCount[GetUnitUserData(udg_DamageEventSource)] + GetUnitAbilityLevel(udg_DamageEventSource,'Ama3') - 9
endfunction
//===========================================================================
function InitTrig_Searing_blade_fx takes nothing returns nothing
set gg_trg_Searing_blade_fx = CreateTrigger( )
// call TriggerRegisterVariableEvent( gg_trg_Searing_blade_fx, "udg_DamageModifierEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Searing_blade_fx, Condition( function Trig_Searing_blade_fx_Conditions ) )
call TriggerAddAction( gg_trg_Searing_blade_fx, function Trig_Searing_blade_fx_Actions )
endfunction
function EnchantRemoveBuff takes nothing returns nothing
local unit u
set bj_forLoopAIndex = 1
set bj_forLoopAIndexEnd = BlzGroupGetSize(udg_A_EnchantGroup)
loop
set u = BlzGroupUnitAt(udg_A_EnchantGroup,bj_forLoopAIndex-1)
//set udg_A_EnchantEnum = BlzGroupUnitAt(udg_A_EnchantGroup,bj_forLoopAIndex-1)
if GetExpiredTimer()==udg_A_EnchantTimer[GetUnitUserData(u)] then
call UnitRemoveAbility(u,'Amab')
call DestroyEffect(udg_A_EnchantFX[GetUnitUserData(u)])
call GroupRemoveUnit(udg_A_EnchantGroup,u)
set bj_forLoopAIndex = bj_forLoopAIndexEnd
endif
set bj_forLoopAIndex = bj_forLoopAIndex + 1
exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
endloop
set u = null
endfunction