Name | Type | is_array | initial_value |
_GUIKeyIsPressed | boolean | No | |
_GUIKeyIsReleased | boolean | No | |
_GUIKeyMeta | integer | No | |
_GUIKeyPlayer | player | No | |
_GUIKeyTrigger | integer | No | |
Aang_Ava_Angle | real | Yes | |
Aang_Ava_dmg | real | No | |
Aang_Ava_int_l | integer | No | |
Aang_Blast_CosR | real | No | |
Aang_Blast_Group | group | Yes | |
Aang_Boosted_dmg | real | No | |
Aang_change_cd | real | No | |
Aang_change_cd_boo | boolean | No | |
Aang_change_int | integer | No | |
Aang_change_u | unit | No | |
Aang_Element | integer | Yes | |
Aegi_SClaw_G | group | Yes | |
Aegi_SClaw_VFX | effect | Yes | |
Aegi_Shield_boo | boolean | Yes | |
Aegi_Shield_durR | real | No | |
Aegi_Shield_VFX | effect | Yes | |
Aegi_Stance | integer | Yes | |
Aegi_Ult_G | group | 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 | |
Atk_Boost_CanAtk | boolean | Yes | true |
Atk_Boost_CD | real | Yes | |
Atk_Boost_Int | integer | Yes | |
Atk_Boost_IsAtkReady | boolean | Yes | |
Atk_Boost_TempG | group | Yes | |
Atk_Boost_TempL | location | Yes | |
Atk_Boost_VFX | effect | 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 | |
Base_Origin_Blu | location | No | |
Base_Origin_Red | location | No | |
Blizzard_AoE | real | No | |
Blizzard_FX | string | No | |
Blizzard_Shards | integer | Yes | |
Boss_1stSpawn_Timer | timer | No | |
Boss_BeginVFXSpawn_Timer | timer | No | |
Boss_Bot_dmgR | real | No | |
Boss_Bot_loc | location | No | |
Boss_Bot_u | unit | No | |
Boss_FinalSpawn | timer | No | |
Boss_FinalStart_boo | boolean | No | |
Boss_i_used_boo | boolean | Yes | |
Boss_Kill_Team | force | No | |
Boss_Mid_dmgR | real | No | |
Boss_Mid_loc | location | No | |
Boss_Mid_u | unit | No | |
Boss_Skill_u | unit | No | |
Boss_Timer_vfx | effect | Yes | |
Boss_Top_dmgR | real | No | |
Boss_Top_loc | location | No | |
Boss_Top_u | unit | No | |
Buff_Atk_Spd | real | Yes | |
Buff_Atk_Spd_i | integer | No | |
Buff_Atk_Spd_r | real | No | |
Buff_Speed | real | Yes | |
Buff_Speed_Dur | real | Yes | |
Buff_Speed_Target | unit | Yes | |
Buff_Speed_VFX | effect | Yes | |
Buff_Stun | real | Yes | |
Buff_Stun_Dur | real | Yes | |
Buff_Stun_Target | unit | Yes | |
Buff_Stun_VFX | effect | Yes | |
Buff_THP | real | Yes | |
Buff_THP_Dur | real | Yes | |
Buff_THP_Target | unit | Yes | |
Buff_THP_VFX | effect | Yes | |
Bush_g_vision | group | No | |
Bush_IsInBush | boolean | No | |
Bush_max_int | integer | No | |
Bush_NextPos | location | No | |
Bush_Pos | location | No | |
Bush_region | rect | Yes | |
Cam_Inv | boolean | Yes | |
Cam_KeyPressed | boolean | Yes | |
Cam_P | integer | No | |
CamShake_Dur | real | No | |
CamShake_Mag | real | No | |
CamShake_Player | player | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CEvBlock | boolean | Yes | |
CEvNext | integer | Yes | |
CEvPrev | integer | Yes | |
CEvSpecial | boolean | Yes | |
CEvUnloadTimer | timer | No | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
Cine_timer | timer | No | |
CineSkip_Boo | boolean | No | |
ClearDamageEvent | trigger | No | |
Color_b | integer | Yes | |
Color_g | integer | Yes | |
Color_r | integer | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CP_HiddenItems | item | Yes | |
CP_HiddenItemsIndex | integer | No | |
CP_Item | item | No | |
CP_Point | location | No | |
CP_PointIsWalkable | boolean | No | |
CP_Rect | rect | No | |
DAMAGE_FACTOR_BRACERS | real | No | |
DAMAGE_FACTOR_ELUNES | real | No | |
DAMAGE_FACTOR_ETHEREAL | real | 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 | |
DamageBlockingAbility | abilcode | No | |
DamageEvent | real | No | |
DamageEvent_Copy | 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 | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterMinAmount | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DeathEvent | real | No | |
DebugInt | integer | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
DEMO_EvenomedSpears_Positon | integer | No | |
DEMO_FurySwipes_Positon | integer | No | |
DEMO_GLGR_Position | integer | No | |
DEMO_Hash | hashtable | No | |
DEMO_Immolation_Positon | integer | No | |
DEMO_SpiriLinkPosition | integer | No | |
DEMO_SpiritLinkDamage | real | No | |
DEMO_Stagger_Positon | integer | No | |
DEMO_TempGroup | group | No | |
DEMO_TempInteger1 | integer | No | |
DEMO_TempInteger2 | integer | No | |
DEMO_TempPoint1 | location | No | |
DEMO_TempPoint2 | location | No | |
DEMO_TempUnit1 | unit | No | |
DEMO_Weave1_Positon | integer | No | |
DEMO_Weave2_Positon | integer | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
DEvAbility | abilcode | No | |
DEvAbilityTemp | abilcode | No | |
DEvBlock | boolean | Yes | |
DEvList | integer | Yes | |
DEvRemoved | boolean | Yes | |
Dipper_Angle | real | No | |
Dipper_AngleDelta | real | No | |
Dipper_AttackType | attacktype | No | |
Dipper_DamageBase | real | No | |
Dipper_DamagePerLvl | real | No | |
Dipper_DamageType | damagetype | No | |
Dipper_Dummy | unit | No | |
Dipper_DummyModel | string | No | |
Dipper_FailFX | string | No | |
Dipper_FinisherFX | string | No | |
Dipper_Loop | integervar | No | |
Dipper_Phase | integer | No | |
Dipper_PhaseDur | real | Yes | |
Dipper_Phases | integer | Yes | |
Dipper_PhaseWait | real | Yes | |
Dipper_Radius | real | No | |
Dipper_RadiusBase | real | No | |
Dipper_RadiusPerLvl | real | No | |
Dipper_StarCount | integer | No | |
Dipper_StarFX | effect | Yes | |
DisplayBar | string | No | |
DisplayBarCount | real | No | |
DisplayHidden | boolean | No | |
DisplayLoopInteger | integervar | No | |
DisplayShieldTypeColor | string | Yes | |
DisplayUnitNeedsUpdate | boolean | Yes | |
DmgEvBracers | itemcode | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
Dummy_abil | ability | No | |
Dummy_CamShake | boolean | Yes | |
Dummy_index | integer | No | |
Dummy_LocMain | location | No | |
Dummy_u_i | unit | Yes | |
DummyTempL | location | No | |
DummyTempL2 | location | No | |
EnhancedDamageTarget | unit | No | |
Gaara_G1 | group | Yes | |
Gaara_Passive_Mult | real | No | |
Gaara_SPit_Int | integer | Yes | |
Gaara_SPit_VFX | effect | Yes | |
Gaara_STombBuff_G | group | No | |
Gate_Blu | destructable | No | |
Gate_Red | destructable | No | |
GBS_BuffAmountOnUnit | integer | No | |
GBS_BuffCounter | integer | Yes | |
GBS_Buffgroup | group | No | |
GBS_BuffId | integer | No | |
GBS_BuffKey | integer | No | |
GBS_BuffLink | integer | No | |
GBS_BuffLinkMax | integer | No | |
GBS_BuffLooper | integervar | No | |
GBS_C_BuffAmountOnUnit | integer | No | |
GBS_C_BuffId | integer | No | |
GBS_C_BuffKey | integer | No | |
GBS_C_BuffLink | integer | No | |
GBS_C_BuffLinkMax | integer | No | |
GBS_C_Bufflooper | integervar | No | |
GBS_C_Bufflooper2 | integervar | No | |
GBS_C_BuffOnUnit | integer | No | |
GBS_C_Duration | real | No | |
GBS_C_EventDuration | real | No | |
GBS_C_EventInterval | real | No | |
GBS_C_InsertedReal | real | Yes | |
GBS_C_MainIndex | integer | No | |
GBS_C_ModKeys | integer | Yes | |
GBS_C_Source | unit | No | |
GBS_C_Target | unit | No | |
GBS_Condition1 | integer | No | |
GBS_Condition2 | integer | No | |
GBS_Define_Buff | buffcode | No | |
GBS_Define_Class | integer | No | |
GBS_Define_Looper | integervar | No | |
GBS_Define_Module_OnAlloc | trigger | No | |
GBS_Define_Module_OnApply | trigger | No | |
GBS_Define_Module_OnRead | trigger | No | |
GBS_Define_Module_OnSave | trigger | No | |
GBS_Define_Module_ReqSpace | integer | No | |
GBS_Define_OnlyAura | boolean | No | |
GBS_Define_Positive | boolean | No | |
GBS_Define_Priority | integer | No | |
GBS_Define_Space | integer | No | |
GBS_Define_Spellbook | abilcode | No | |
GBS_Define_Stack | integer | No | |
GBS_Duration | real | No | |
GBS_Event | real | No | |
GBS_EventDuration | real | No | |
GBS_EventInterval | real | No | |
GBS_Hash | hashtable | No | |
GBS_Init_Buff | buffcode | Yes | |
GBS_Init_BuffAmount | integer | No | |
GBS_Init_Class | integer | Yes | |
GBS_Init_IsPreloaded | boolean | Yes | |
GBS_Init_Modulespace | integer | Yes | |
GBS_Init_OnlyAura | boolean | Yes | |
GBS_Init_Positive | boolean | Yes | |
GBS_Init_Priority | integer | Yes | |
GBS_Init_Space | integer | Yes | |
GBS_Init_Spellbook | abilcode | Yes | |
GBS_Init_Stack | integer | Yes | |
GBS_Init_Timer | real | No | |
GBS_InsertedReal | real | Yes | |
GBS_Link_Buff | integer | No | |
GBS_Link_Mod | integer | No | |
GBS_MainIndex | integer | No | |
GBS_ModKeys | integer | Yes | |
GBS_Module_Amount | integer | No | |
GBS_Module_Hash | hashtable | No | |
GBS_Module_OnAlloc | trigger | Yes | |
GBS_Module_OnApply | trigger | Yes | |
GBS_Module_OnRead | trigger | Yes | |
GBS_Module_OnSave | trigger | Yes | |
GBS_Module_ReqSpace | integer | Yes | |
GBS_PeriodicEvent | real | No | |
GBS_PickFunction | trigger | No | |
GBS_Security | boolean | No | |
GBS_ShadowVariable | integer | No | |
GBS_Source | unit | No | |
GBS_Target | unit | No | |
GBS_TempInteger | integervar | No | |
GBS_TempInteger2 | integervar | No | |
GBS_TempPoint | location | No | |
Ghia_Frz_vfx | effect | Yes | |
Ghia_Ice_AoE_i | real | Yes | |
Ghia_Ice_Dur | real | No | |
Ghia_Ice_Dur_i | real | Yes | |
Ghia_Ice_Index | integer | No | |
Ghia_Ice_Loc | location | No | |
Ghia_Ice_Loc_i | location | Yes | |
Ghia_Ice_loop | integer | No | |
Ghia_Ice_rX_i | real | Yes | |
Ghia_Ice_rY_i | real | Yes | |
Ghia_Ice_Scale | real | No | |
Ghia_Ice_u | unit | No | |
Ghia_Ice_u_i | unit | Yes | |
Ghia_Ice_vfx_i | effect | Yes | |
Ghia_Wave_G | group | Yes | |
Ghia_Wave_G2 | group | Yes | |
Ghia_Wave_i | integer | Yes | |
Ghia_Weeps_boo | boolean | Yes | |
Ghia_Weeps_u | unit | Yes | |
Ghia_Weeps_vfx | effect | Yes | |
Ghia_Weeps_vfx_2 | effect | Yes | |
GLGR_Group | group | No | |
GUIKEY_0 | integer | No | |
GUIKEY_1 | integer | No | |
GUIKEY_2 | integer | No | |
GUIKEY_3 | integer | No | |
GUIKEY_4 | integer | No | |
GUIKEY_5 | integer | No | |
GUIKEY_6 | integer | No | |
GUIKEY_7 | integer | No | |
GUIKEY_8 | integer | No | |
GUIKEY_9 | integer | No | |
GUIKEY_A | integer | No | |
GUIKEY_ADD | integer | No | |
GUIKEY_ALT | integer | No | |
GUIKEY_APPS | integer | No | |
GUIKEY_B | integer | No | |
GUIKEY_BACKSPACE | integer | No | |
GUIKEY_C | integer | No | |
GUIKEY_CAPSLOCK | integer | No | |
GUIKEY_CLEAR | integer | No | |
GUIKEY_CONTROL | integer | No | |
GUIKEY_D | integer | No | |
GUIKEY_DECIMAL | integer | No | |
GUIKEY_DELETE | integer | No | |
GUIKEY_DIVIDE | integer | No | |
GUIKEY_DOWN | integer | No | |
GUIKEY_E | integer | No | |
GUIKEY_END | integer | No | |
GUIKEY_ESCAPE | integer | No | |
GUIKEY_EXECUTE | integer | No | |
GUIKEY_F | integer | No | |
GUIKEY_F1 | integer | No | |
GUIKEY_F10 | integer | No | |
GUIKEY_F11 | integer | No | |
GUIKEY_F12 | integer | No | |
GUIKEY_F13 | integer | No | |
GUIKEY_F14 | integer | No | |
GUIKEY_F15 | integer | No | |
GUIKEY_F16 | integer | No | |
GUIKEY_F17 | integer | No | |
GUIKEY_F18 | integer | No | |
GUIKEY_F19 | integer | No | |
GUIKEY_F2 | integer | No | |
GUIKEY_F20 | integer | No | |
GUIKEY_F21 | integer | No | |
GUIKEY_F22 | integer | No | |
GUIKEY_F23 | integer | No | |
GUIKEY_F24 | integer | No | |
GUIKEY_F3 | integer | No | |
GUIKEY_F4 | integer | No | |
GUIKEY_F5 | integer | No | |
GUIKEY_F6 | integer | No | |
GUIKEY_F7 | integer | No | |
GUIKEY_F8 | integer | No | |
GUIKEY_F9 | integer | No | |
GUIKEY_G | integer | No | |
GUIKEY_H | integer | No | |
GUIKEY_HELP | integer | No | |
GUIKEY_HOME | integer | No | |
GUIKEY_I | integer | No | |
GUIKEY_INSERT | integer | No | |
GUIKEY_J | integer | No | |
GUIKEY_K | integer | No | |
GUIKEY_L | integer | No | |
GUIKEY_LALT | integer | No | |
GUIKEY_LCONTROL | integer | No | |
GUIKEY_LEFT | integer | No | |
GUIKEY_LMETA | integer | No | |
GUIKEY_LSHIFT | integer | No | |
GUIKEY_M | integer | No | |
GUIKEY_MEDIA_NEXT_TRACK | integer | No | |
GUIKEY_MEDIA_PLAY_PAUSE | integer | No | |
GUIKEY_MEDIA_PREV_TRACK | integer | No | |
GUIKEY_MEDIA_STOP | integer | No | |
GUIKEY_MULTIPLY | integer | No | |
GUIKEY_N | integer | No | |
GUIKEY_NAME | string | Yes | |
GUIKEY_NUMLOCK | integer | No | |
GUIKEY_NUMPAD0 | integer | No | |
GUIKEY_NUMPAD1 | integer | No | |
GUIKEY_NUMPAD2 | integer | No | |
GUIKEY_NUMPAD3 | integer | No | |
GUIKEY_NUMPAD4 | integer | No | |
GUIKEY_NUMPAD5 | integer | No | |
GUIKEY_NUMPAD6 | integer | No | |
GUIKEY_NUMPAD7 | integer | No | |
GUIKEY_NUMPAD8 | integer | No | |
GUIKEY_NUMPAD9 | integer | No | |
GUIKEY_O | integer | No | |
GUIKEY_OEM_1 | integer | No | |
GUIKEY_OEM_102 | integer | No | |
GUIKEY_OEM_2 | integer | No | |
GUIKEY_OEM_3 | integer | No | |
GUIKEY_OEM_4 | integer | No | |
GUIKEY_OEM_5 | integer | No | |
GUIKEY_OEM_6 | integer | No | |
GUIKEY_OEM_7 | integer | No | |
GUIKEY_OEM_8 | integer | No | |
GUIKEY_OEM_AX | integer | No | |
GUIKEY_OEM_COMMA | integer | No | |
GUIKEY_OEM_MINUS | integer | No | |
GUIKEY_OEM_PERIOD | integer | No | |
GUIKEY_OEM_PLUS | integer | No | |
GUIKEY_P | integer | No | |
GUIKEY_PAGEDOWN | integer | No | |
GUIKEY_PAGEUP | integer | No | |
GUIKEY_PAUSE | integer | No | |
GUIKEY_PRINT | integer | No | |
GUIKEY_PRINTSCREEN | integer | No | |
GUIKEY_Q | integer | No | |
GUIKEY_R | integer | No | |
GUIKEY_RALT | integer | No | |
GUIKEY_RCONTROL | integer | No | |
GUIKEY_RETURN | integer | No | |
GUIKEY_RIGHT | integer | No | |
GUIKEY_RMETA | integer | No | |
GUIKEY_RSHIFT | integer | No | |
GUIKEY_S | integer | No | |
GUIKEY_SCROLLLOCK | integer | No | |
GUIKEY_SELECT | integer | No | |
GUIKEY_SEPARATOR | integer | No | |
GUIKEY_SHIFT | integer | No | |
GUIKEY_SLEEP | integer | No | |
GUIKEY_SPACE | integer | No | |
GUIKEY_SUBTRACT | integer | No | |
GUIKEY_T | integer | No | |
GUIKEY_TAB | integer | No | |
GUIKEY_U | integer | No | |
GUIKEY_UP | integer | No | |
GUIKEY_V | integer | No | |
GUIKEY_VOLUME_DOWN | integer | No | |
GUIKEY_VOLUME_MUTE | integer | No | |
GUIKEY_VOLUME_UP | integer | No | |
GUIKEY_W | integer | No | |
GUIKEY_X | integer | No | |
GUIKEY_Y | integer | No | |
GUIKEY_Z | integer | No | |
GUIKeyEvent | real | No | |
GUIKeyEvent_S_BlockRepeat | boolean | No | true |
GUIKeyEvent_S_EnablePlayer | boolean | Yes | |
GUIKeyEvent_System | trigger | No | |
GUIMETAKEY_ALL | integer | No | 15 |
GUIMETAKEY_ALT | integer | No | 4 |
GUIMETAKEY_ALT_META | integer | No | 12 |
GUIMETAKEY_CONTROL | integer | No | 2 |
GUIMETAKEY_CONTROL_ALT | integer | No | 6 |
GUIMETAKEY_CONTROL_ALT_META | integer | No | 14 |
GUIMETAKEY_CONTROL_AND_META | integer | No | 10 |
GUIMETAKEY_META | integer | No | 8 |
GUIMETAKEY_NONE | integer | No | |
GUIMETAKEY_SHIFT | integer | No | 1 |
GUIMETAKEY_SHIFT_ALT | integer | No | 5 |
GUIMETAKEY_SHIFT_ALT_META | integer | No | 13 |
GUIMETAKEY_SHIFT_CONTROL | integer | No | 3 |
GUIMETAKEY_SHIFT_CONTROL_ALT | integer | No | 7 |
GUIMETAKEY_SHIFT_CONTROL_META | integer | No | 11 |
GUIMETAKEY_SHIFT_META | integer | No | 9 |
heal_amount | real | No | |
heal_check | boolean | No | |
HEAL_CHECK_INTERVAL | real | No | |
heal_count | integer | No | |
heal_diff | real | No | |
heal_exitwhen | integer | No | |
heal_indexRef | integer | Yes | |
heal_indices | integer | Yes | |
heal_inSys | boolean | Yes | |
heal_integer | integervar | No | |
heal_lastLife | real | Yes | |
heal_life | real | No | |
heal_regen | real | Yes | |
heal_source | unit | No | |
heal_target | unit | No | |
HEAL_THRESHOLD | real | No | |
heal_timer | timer | No | |
HealEvent | real | No | |
Hero_Attack_Cooldown | real | Yes | |
Hero_Attack_Cooldown_Lvl_Max | real | Yes | |
Hero_Max | integer | No | |
Hero_Number | integer | Yes | |
Hero_Speed | real | Yes | |
Hero_Speed_Lvl_Max | real | Yes | |
Hero_TempStats_Dur | real | No | |
Hero_TempStats_Magnitude | integer | No | |
Hero_TempStats_Stat | integer | No | |
Hero_TempStats_Unit | unit | No | |
Hero_Unit | unit | Yes | |
Hero_Unit_Type | unitcode | Yes | |
HideDamageFrom | boolean | Yes | |
HolyLightBuff | effect | Yes | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
IsDamageSpell_Copy | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
Item_OoC_speed_r | real | No | |
item_unit | unit | No | |
Itm_Atk_Stack | integer | Yes | |
Itm_UseOrder | integer | Yes | |
Itm_UseOrder_u | unit | No | |
K2DOverride | boolean | Yes | |
KillerOfUnit | unit | Yes | |
Kills_First | boolean | No | |
Kills_Int_Spree | integer | Yes | |
Knight_AtkDMG_1 | real | No | |
Knight_AtkDMG_2 | real | No | |
Knight_BoomDMG | real | No | |
Knight_BoomerangRange | integer | No | |
Knight_BoomerangSpeed | integer | No | |
Knight_BoomSpd_ReturnMult | real | No | |
Knight_Def_Mana_Conv | real | No | |
Knight_Def_Parry_Mana_Regen | integer | No | |
Knight_Def_Parry_Stun | integer | No | |
Knight_Def_Parry_Time | integer | No | |
Knight_Def_Spd | real | No | |
Knight_Dodge_Distance | integer | No | |
Knight_Dodge_End_stun | integer | No | |
Knight_Dodge_Iframe | integer | No | |
Knight_Dodge_Speed | integer | No | |
Knight_G1 | group | Yes | |
Knight_Int1 | integer | Yes | |
Knight_Int2 | boolean | Yes | |
KnightSlash_unit1 | unit | Yes | |
Knockback2DAngle | real | No | |
Knockback2DCollision | real | No | |
Knockback2DDistance | real | No | |
Knockback2DFriction | real | No | |
Knockback2DFXRate | real | No | |
Knockback2DGravity | real | No | |
Knockback2DHeight | real | No | |
Knockback2DLoopFX | string | No | |
Knockback2DPause | boolean | No | |
Knockback2DSimple | boolean | No | |
Knockback2DTime | real | No | |
Knockback2DUnit | unit | No | |
LastCreatedShield | integer | No | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
Leaderboard_Blu | leaderboard | No | |
Leaderboard_Red | leaderboard | No | |
Lee_Gates_Int | integer | Yes | |
Lee_Gates_Kick_Real | real | Yes | |
Lee_Gates_Kick_VFX | effect | Yes | |
Lee_Kick_boo | boolean | Yes | |
Lee_Kick_VFX | effect | Yes | |
Lee_Punch_Angle | real | Yes | |
Lee_Punch_boo | boolean | Yes | |
Lee_Punch_VFX | effect | Yes | |
Lee_Punch_VFX_2 | effect | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
Mapshitheroes | unit | Yes | |
MBat_Flip_u | unit | Yes | |
MBat_Tornado_Boo | boolean | Yes | |
MBat_Tornado_vfx | effect | Yes | |
MBat_Tornado_vfx2 | effect | Yes | |
MBat_Ult_dmg | real | Yes | |
MBat_Ult_vfx | effect | Yes | |
Mih_Debuff_Int | integer | Yes | |
Mih_RG_Boo | boolean | Yes | |
Mih_RG_Boo2 | boolean | Yes | |
Missile | integer | No | |
Missile_onBoundaries | trigger | No | |
Missile_onCliff | trigger | No | |
Missile_onDestructable | trigger | No | |
Missile_onFinish | trigger | No | |
Missile_onHit | trigger | No | |
Missile_onItem | trigger | No | |
Missile_onMissile | trigger | No | |
Missile_onPause | trigger | No | |
Missile_onPeriod | trigger | No | |
Missile_onRemove | trigger | No | |
Missile_onResume | trigger | No | |
Missile_onTerrain | trigger | No | |
Missile_onTileset | trigger | No | |
MissileAcceleration | real | No | |
MissileAlpha | integer | No | |
MissileAnimation | integer | No | |
MissileArc | real | No | |
MissileAt | integer | No | |
MissileAttachModel | string | No | |
MissileAttachScale | real | No | |
MissileAttachX | real | No | |
MissileAttachY | real | No | |
MissileAttachZ | real | No | |
MissileBlue | integer | No | |
MissileCollideZ | boolean | No | |
MissileCollision | real | No | |
MissileCurve | real | No | |
MissileDamage | real | No | |
MissileData | integer | No | |
MissileDeflectPosition | location | No | |
MissileDeflectTarget | unit | No | |
MissileDeflectZ | real | No | |
MissileDestroy | boolean | No | |
MissileDetachEffect | effect | No | |
MissileDuration | real | No | |
MissileEvent | integer | No | |
MissileFinish | location | No | |
MissileFinishZ | real | No | |
MissileFlushUnit | unit | No | |
MissileGreen | integer | No | |
MissileGroup | integer | No | |
MissileGroupAddGroup | integer | No | |
MissileGroupCounted | integer | No | |
MissileGroupLocation | location | No | |
MissileGroupPlayer | player | No | |
MissileGroupRange | real | No | |
MissileGroupRect | rect | No | |
MissileGroupRemoveGroup | integer | No | |
MissileGroupSize | integer | No | |
MissileGroupType | integer | No | |
MissileHitDestructable | destructable | No | |
MissileHitItem | item | No | |
MissileHitMissile | integer | No | |
MissileHitted | boolean | No | |
MissileHittedUnit | unit | No | |
MissileHitUnit | unit | No | |
MissileLastPosition | location | No | |
MissileModel | string | No | |
MissileNextPosition | location | No | |
MissileNextZ | real | No | |
MissileOnBoundaries | integer | No | 8 |
MissileOnCliff | integer | No | 12 |
MissileOnDestructable | integer | No | 4 |
MissileOnFinish | integer | No | 7 |
MissileOnHit | integer | No | 2 |
MissileOnItem | integer | No | 5 |
MissileOnMissile | integer | No | 3 |
MissileOnPause | integer | No | 9 |
MissileOnPeriod | integer | No | 1 |
MissileOnRemove | integer | No | 11 |
MissileOnResume | integer | No | 10 |
MissileOnTerrain | integer | No | 6 |
MissileOnTileset | integer | No | 13 |
MissileOwner | player | No | |
MissilePaused | boolean | No | |
MissilePlayerColor | integer | No | |
MissilePosition | location | No | |
MissilePrevZ | real | No | |
MissileRed | integer | No | |
MissileRemoveLocations | boolean | No | true |
MissileRoll | boolean | No | |
MissileScale | real | No | |
MissileSource | unit | No | |
MissileSpeed | real | No | |
MissileStart | location | No | |
MissileStartZ | real | No | |
MissileTarget | unit | No | |
MissileTileset | integer | No | |
MissileTimeScale | real | No | |
MissileTravelled | real | No | |
MissileType | integer | No | |
MissileVelocity | real | No | |
MissileVision | real | No | |
MissileZ | real | No | |
Mob_DmgRes | real | No | |
Mob_Rev_index | integer | No | |
Mob_Rev_loc | location | Yes | |
Mob_Rev_u | unit | Yes | |
Mob_Rev_ut | integer | No | |
Mob_Timer | integer | No | |
Mob_u | unit | Yes | |
Mouse_i | integer | No | |
Mouse_i2 | integer | No | |
MouseClick | boolean | Yes | |
MouseMaxPlayers | integer | No | |
MousePoint | location | No | |
MouseUnit | unit | Yes | |
MouseX | real | Yes | |
MouseX_Cont | real | Yes | |
MouseY | real | Yes | |
MouseY_Cont | real | Yes | |
Mp_i | integer | No | |
Mpell__Caster | unit | Yes | |
Mpell__LevelMultiplier | real | Yes | |
MusicList | string | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
NextDamageType_Copy | integer | No | |
NextDamageWeaponT | integer | No | |
NextHealAmount | real | No | |
NextHealSource | unit | No | |
NextHealTarget | unit | No | |
NoTrigger | trigger | No | |
OutOfCom_Boo | boolean | Yes | true |
OutOfCom_Int | integer | Yes | |
PRD_boo | boolean | No | |
PRD_C | real | Yes | |
PRD_crit_chance_i | real | Yes | |
PRD_crit_N_i | real | Yes | |
PRD_evade_chance_i | real | Yes | |
PRD_evade_N_i | real | Yes | |
PRD_event | integer | No | |
PRD_N | real | No | |
PRD_P | real | No | |
RDFG_CanMove | boolean | Yes | true |
RDFG_CanTurn | boolean | Yes | true |
RDFG_CanWalkAnim | boolean | Yes | true |
RDFG_DOWN_IsPressed | boolean | Yes | |
RDFG_Force | force | No | |
RDFG_IsDoodadsEmpty | boolean | Yes | |
RDFG_IsMoving | boolean | Yes | |
RDFG_LEFT_IsPressed | boolean | Yes | |
RDFG_Move_Speed | real | Yes | |
RDFG_Mult | real | Yes | 1.00 |
RDFG_RIGHT_IsPressed | boolean | Yes | |
RDFG_TempPoint | location | Yes | |
RDFG_TempX | real | No | |
RDFG_TempY | real | No | |
RDFG_Unit | unit | Yes | |
RDFG_UP_IsPressed | boolean | Yes | |
Recall_Int | integer | Yes | |
Recall_IsRecalling | boolean | Yes | |
Recall_SFX | sound | Yes | |
Recall_VFX | effect | Yes | |
regen_buildup | real | Yes | |
REGEN_EVENT_INTERVAL | real | No | |
REGEN_STRENGTH_VALUE | real | No | |
REGEN_THRESHOLD | real | No | |
regen_timeleft | real | Yes | |
Reset_boo | boolean | No | |
Reset_dur | real | Yes | |
Reset_Face_Loc | location | No | |
Reset_Face_u | unit | No | |
Reset_Int | integer | No | |
Reset_LookAt | boolean | Yes | |
Reset_ReturnToStand | boolean | Yes | |
Resi_dur | integer | No | |
Resi_target | integer | No | |
Resi_u | integer | No | |
Respawn_Multiplier | real | No | |
Score_Drop_Multiplier | real | No | |
Score_Goals | unit | Yes | |
Score_Goals_IsVulnerable | boolean | Yes | |
Score_Int | integer | Yes | |
Score_IsScoring | boolean | Yes | |
Score_Multiplier_Boo | boolean | No | |
Score_Multiplier_Real | real | No | |
Score_Per_Player | real | Yes | |
Score_Stack_u | unit | No | |
Score_Total_Blu | real | No | |
Score_Total_Red | real | No | |
ScoS_Loc1_u | location | No | |
ScoS_Loc1_u_rand | location | No | |
ScoS_Loc_Depo | location | No | |
ScoS_score | integer | No | |
ScoS_score_hero_u | unit | No | |
ScoS_score_int1 | integer | No | |
ScoS_score_int5 | integer | No | |
ScoS_score_max | integer | No | |
ScoS_score_max2 | integer | No | |
ScoS_score_new | integer | No | |
ScoS_score_old | integer | No | |
ScoS_score_pl | player | No | |
ScoS_u1_index | integer | No | |
ScoS_u1_indexMax | integer | No | |
ScoS_u5_index | integer | No | |
ScoS_u5_indexMax | integer | No | |
ScoS_u_1score_i | unit | Yes | |
ScoS_u_5score_i | unit | Yes | |
ScoS_u_Dead | unit | No | |
ScoS_u_dur_i | unit | Yes | |
ScoS_u_Get | unit | No | |
ShieldBlockType | trigger | Yes | |
ShieldBreak | trigger | Yes | |
ShieldCaster | unit | Yes | |
ShieldDamaged | trigger | Yes | |
ShieldDuration | real | Yes | |
ShieldedUnit | unit | Yes | |
ShieldEvent | real | No | |
ShieldEventDamagedAmount | real | No | |
ShieldEventOverkillAmount | real | No | |
ShieldExpire | trigger | Yes | |
ShieldFirstOfIDAdded | boolean | No | |
ShieldFunctionInteger | integer | No | |
ShieldFunctionReturnInteger | integer | No | |
ShieldFunctionUnit | unit | No | |
ShieldHealth | real | Yes | |
ShieldHealthMax | real | Yes | |
ShieldIndex | integer | No | |
ShieldIterationTrigger | trigger | No | |
ShieldLastOfIDRemoved | boolean | No | |
ShieldNextDiff | integer | Yes | |
ShieldNextSame | integer | Yes | |
ShieldOldHealth | real | Yes | |
ShieldOldHealthMax | real | Yes | |
ShieldPeriodic | trigger | Yes | |
ShieldPrevDiff | integer | Yes | |
ShieldPrevSame | integer | Yes | |
ShieldRemoved | trigger | Yes | |
ShieldRemoveWhenBroken | boolean | Yes | |
ShieldTable | hashtable | No | |
ShieldTypeID | integer | Yes | |
ShieldUnitDamaged | trigger | Yes | |
ShieldUnitIndex | integer | 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 | |
SpellDamageAbility | abilcode | No | |
str | string | No | |
SummonerOfUnit | unit | Yes | |
SystemShieldedUnits | group | No | |
SystemShieldFlaggedRemove | boolean | Yes | |
SystemShieldFreeIndexCurrent | integer | No | |
SystemShieldFreeIndexes | integer | Yes | |
SystemShieldIterationStop | boolean | No | |
SystemShieldListInUse | integer | No | |
SystemShieldMaxIndex | integer | No | -1 |
SystemShieldPeriodicTimer | timer | No | |
SystemShieldsRemovalQueue | integer | Yes | |
SystemShieldsRemovalQueueIndex | integer | No | 0 |
target_abil_type | abilcode | No | |
target_boo_isPosBuff | boolean | No | |
target_caster | unit | No | |
target_cleanse_u | unit | No | |
target_duration | integer | No | |
target_duration_r | real | No | |
target_heal_magnitude | real | No | |
target_target_u | unit | No | |
Team_Blu | force | No | |
Team_Red | force | No | |
TempBoo | boolean | No | |
TempBoo_2 | boolean | No | |
TempEff | boolean | No | |
TempEffect | effect | No | |
TempG1 | group | No | |
TempG2 | group | No | |
TempGroup | group | No | |
TempInt | integer | Yes | |
TempInt1 | integer | No | |
TempInt2 | integer | No | |
TempInt_Loop1 | integervar | No | |
TempInteger | integer | No | |
TempItem | item | No | |
TempL1 | location | No | |
TempL2 | location | No | |
TempL3 | location | No | |
TempL4 | location | No | |
TempLoc | location | No | |
TempPlayer | player | No | |
TempPlayerForce | force | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
TempR1 | real | No | |
TempR2 | real | No | |
TempReal | real | No | |
TempReal_A | real | Yes | |
TempStrings | string | Yes | |
TempUnit | unit | No | |
TempUnit2 | unit | No | |
TempUnitHeavy | unit | No | |
TempUnitType | unitcode | Yes | |
Timer_1m_before_boss | timer | No | |
Timer_30s | timer | No | |
Timer_5m | timer | No | |
Timer_Begin | timer | No | |
Timer_Begin_Window | timerdialog | No | |
Timer_Game_End | timer | No | |
Timer_Game_Mid | timer | No | |
Timer_Game_Victory | timer | No | |
Timer_Game_Victory_Window | timerdialog | No | |
Timer_VFX | effect | No | |
Timer_VFX_2 | effect | No | |
Timer_Whole_Game | timer | No | |
Timer_Whole_Window | timerdialog | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitDamageRegistered | boolean | Yes | |
UnitFirstShield | integer | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitKey | integer | Yes | |
UnitLastShield | integer | Yes | |
UnitShieldTag | texttag | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
VFX_Dur | real | No | |
vision_aoe | real | No | |
vision_dur | real | No | |
vision_XY | location | 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 | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
XP_Amount | integer | No | |
XP_Comeback_boo | boolean | No | |
Zen_Cut_L | location | Yes | |
Zen_Cut_VFX | effect | Yes | |
Zen_Cut_VFXint | integer | Yes | |
Zen_Slash_Distance | real | No | |
Zen_Slash_G | group | Yes | |
Zen_Slash_L | location | Yes | |
Zen_Slash_R | real | No | |
Zen_Slash_u | unit | Yes | |
Zen_Slash_VFX | effect | Yes | |
Zen_Ult_VFX_c | effect | Yes | |
Zen_Ult_VFX_c2 | effect | Yes | |
Zen_Ult_VFX_u | effect | Yes | |
Zhield_IsUnitScoreBossShielded | boolean | Yes | |
Zhield_IsUnitScoreShielded | boolean | Yes | |
Zhield_IsUnitShielded | boolean | Yes | |
Zhield_Normal_vfx | effect | Yes | |
Zhield_Score_vfx | effect | Yes | |
Zhield_ScoreBoss_vfx | effect | Yes | |
Zhield_ui_dummy_i | unit | Yes | |
Zhield_ui_vfx_i | effect | Yes |
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer id = 0
local unit u
loop
set id = udg_CheckDeathList[id]
exitwhen id == 0
set udg_UDex = id
set u = udg_UDexUnits[id]
if udg_IsUnitNew[id] then
//The unit was just created.
set udg_IsUnitNew[id] = false
set udg_UnitIndexEvent = 1.50 //New event requested by SpellBound to detect when unit fully enters scope.
set udg_UnitIndexEvent = 0.00
elseif udg_IsUnitTransforming[id] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[id] = GetUnitTypeId(u) //Set this afterward as otherwise the user won't know what the previous unittype was.
set udg_IsUnitTransforming[id] = false
call UnitAddAbility(u, udg_DetectTransformAbility)
elseif udg_IsUnitAlive[id] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[id] = true
set udg_IsUnitAlive[id] = false
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
elseif GetUnitTypeId(u) != 0 and not IsUnitType(u, UNIT_TYPE_DEAD) then //with vJass, could just use UnitAlive instead of both of these values.
//Moved this code to fire after a 0 second timer instead.
set udg_IsUnitAlive[id] = true
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[id] = false
endif
set udg_CheckDeathInList[id] = false
endloop
set u = null
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
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
call UnitEventCheckAfterProxy(i) //modified 22 Oct 2022 to ensure the unit is fully revived before firing the event.
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
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.2 - update requires replacing the JASS script.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method getIndex takes trigger t, string eventName, real value returns integer
static method registerTrigger takes trigger whichTrig, string var, real weight returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method operator [] takes code c returns trigger
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = CreateTrigger()
private trigger t2 = CreateTrigger()
private trigger t3 = CreateTrigger() //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfiguration" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
*/
struct DamageTrigger extends array
//Map-makers should comment-out any booleans they will never need to check for.
method checkConfiguration takes nothing returns boolean
if this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif udg_DamageEventAmount > this.damageMin then
return true
endif
return false
endmethod
//The below variables are constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean configured
boolean usingGUI
//The below variables are private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceBuff = udg_DamageFilterSourceB
set this.targetBuff = udg_DamageFilterTargetB
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set udg_DamageFilterAttackT =-1
set udg_DamageFilterDamageT =-1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterMinAmount=0.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if var == "udg_DamageModifierEvent" then
if root >= 4 then
set root= SHIELD //4.00 or higher
else
set root= MOD //Less than 4.00
endif
elseif var == "udg_DamageEvent" then
if root == 2 or root == 0 then
set root= ZERO
else
set root= DAMAGE //Above 0.00 but less than 2.00, generally would just be 1.00
endif
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
local thistype index = getIndex(t, eventName, lbs)
if index == 0 then
return false
endif
set prev.next = index.next
set trigIndexStack[index] = trigIndexStack[0]
set trigIndexStack[0] = index
if reset then
call index.configure()
set index.configured = false
set index = index*FILTER_MAX
call index.toggleAllFilters(false)
endif
return true
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if not this.trigFrozen and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and (not this.configured or this.checkConfiguration()) then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if pierce != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call DamageTrigger.AOE.run()
endif
set udg_DamageEventAOE = 0
set udg_DamageEventLevel = 0
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != 0 then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if udg_DamageEventAmount != 0.00 then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if this.damage != 0.00 then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damage != 0.00 and d.damageType == DAMAGE_TYPE_UNKNOWN)
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
if not DamageTrigger.eventIndex.checkConfiguration() then
return
endif
endif
//! endtextmacro
endlibrary
//===========================================================================
//
// GUIKeyEvent 1.2a (requires patch version 1.32+)
// Author: lolreported
//
// Credits if used are appreciated!
//
//
// Thanks to Tasyen for some information regarding oskey natives
// https://www.hiveworkshop.com/threads/oskey-player-key-event.319903/
//
//===========================================================================
Version 1.31 introduced the possibility to detect when ANY keyboard key is pressed or released,
but this functionality is limited to JASS/Lua users only as Blizzard never
implemented any GUI functionality for this new feature.
I've seen some requests and questions from GUI users wondering how they
can implement this feature, but it's usually difficult as they're not
used to work with code.
GUIKeyEvent changes that and now GUI users can detect whenever ANY key
is pressed or released by a player.
# Features
--- Detect when any keyboard key is pressed or released.
--- Detect if a meta key was pressed with the key
----- Meta keys are Shift, Control, Alt and META (windows-key)
----- So you could, as an example, detect if a player presses "W", while holding the Shift-key.
# Known "Problems"
--- The number of players playing drastically increases the map loading time.
--- The number of variables required is massive, due to enable easy comparisons with if's.
--- I barely know what half of the keys represent, so any questions regarding that may not be answered by me.
# How it Works
--- Every single possible key that can be pressed is registered for every (playing) player in the system event trigger.
--- Whenever a player presses a key, the system detects this and stores the data into GUI variables you can use in your triggers.
--- The system then makes use of the popular GUI event "Game - Value of Real Variable" a lot of other systems use and should be fairly known how to use by now.
# How to Use
--- Use the event "Game - GUIKeyEvent becomes Equal to 1.00" as your trigger event to detect when a key is pressed or released.
--- You can then use 5 variables in your trigger:
----- "_GUIKeyPlayer" = This is the player that pressed the keyboard key.
----- "_GUIKeyTrigger" = This is the keyboard key that was pressed.
-------- Use an "Integer Comparison" in order to detect which key was pressed. Example: "_GUIKeyTrigger Equal to GUIKEY_W"
----- "_GUIKeyMeta" = This holds meta key data for the pressed key. Was Shift, Control, Alt or the Windows key pressed together with the key?
-------- Use an "Integer Comparison" in order to detect which meta key was pressed. Example: "_GUIKeyMeta Equal to GUIMETAKEY_SHIFT". You may also check for multiple at once, like "_GUIKeyMeta Equal to GUIMETAKEY_SHIFT_CONTROL_ALT"
----- "_GUIKeyIsPressed" = Is the keyboard key pressed?
-------- Use a "Boolean Comparison" in order to detect if the key is pressed or not. Example: "_GUIKeyIsPressed Equal to True"
----- "_GUIKeyIsReleased" = Is the keyboard key released?
-------- Use a "Boolean Comparison" in order to detect if the key is pressed or not. Example: "_GUIKeyIsReleased Equal to True"
----- You can turn off the system at any time with the "Trigger - Turn off GUIKeyEvent_System" action and then turn it on with "Trigger - Turn on GUIKeyEvent_System".
# How to Install
--- 1. It's recommended to delete any previous "GUIKeyEvent" folder you may already have installed before installing a new version of GUIKeyEvent.
--- 2. Copy the "GUIKeyEvent" folder.
--- 3. Open your map and paste the folder into the Trigger Editor.
--- 4. Adjust any GUIKeyEvent settings in the "GUIKeyEvent Settings" trigger.
--- 5. (optional) Check the "GUIKeyEvent Demo(s)" folder for some examples of how to use GUIKeyEvent.
--- 6. Done.
# 1.2a
- Added a "Lightweight" version.
--- This version only detect the more common keys and uses 54 less variables.
--- The map loading time is improved as well.
- Added a new string array variable "GUIKEY_NAME" that can be used to get the name of the keys. Could be useful for debugging, etc.
- Fixed an issue that caused the OSKEY_OEM_CLEAR key to not be registered.
# 1.1a:
- The system is now initialized at RunInitializationTriggers in main (in order to not have GUIKeyEvent Settings overwritten by InitGlobals).
- Removed desync prone GetPlayerController/GetPlayerSlotState at map init and instead added GUIKeyEvent_S_EnablePlayer to the GUIKeyEvent Settings trigger that allows the user to manually set players to use.
- "GUIKeyEvent_S_BlockRepeat" setting set to true by default in the GUIKeyEvent Settings trigger.
- Renamed the variable "_GUIKeyIsDown" to "_GUIKeyIsPressed".
- Added a new boolean variable "_GUIKeyIsReleased", that can be used instead of "_GUIKeyIsPressed Equal to False"
# 1.0a:
- Release
//===========================================================================
//
// GUIKeyEvent 1.2a
// Author: lolreported
//
//
// Important Note:
// Do not touch any of the code below, unless you
// know what you're doing. I'll not help debug any errors
// resulting from careless editing.
//
//===========================================================================
library GUIKeyEvent
globals
// If true, static if's causes certain code not to be compiled for Lightweight version.
// Will cause errors if set to false in non-lightweight version as GUI variables is missing.
private constant boolean IS_LIGHTWEIGHT_VERSION = true
// For init
private constant integer CONVERT_OS_KEY_TYPE_INDEX_START = $08
private constant integer CONVERT_OS_KEY_TYPE_INDEX_END = $FE
// Value combined of all possible meta keys.
// MetaKeys are "none"(0), "shift"(1), "control"(2), "alt"(4) and "META"(8) (windows key).
private constant integer META_KEY_MAX = 15
private integer currentKey
// For settings
private integer array playerPrevKey
private boolean array playerKeyWasDown
endglobals
private function OnGUIKeyEvent takes nothing returns boolean
local integer playerId
// Set globals whenever a players press a key
set udg__GUIKeyPlayer = GetTriggerPlayer() // Set player that triggered the oskey event
set udg__GUIKeyTrigger = GetHandleId(BlzGetTriggerPlayerKey()) // Convert oskey to handle in order to be able to compare with GUI key variables
set udg__GUIKeyIsPressed = BlzGetTriggerPlayerIsKeyDown() // Set boolean to if the key was pressed or released
// Ignore new events if the key is held down and udg_GUIKeyEvent_S_BlockRepeat is set to true.
if (udg_GUIKeyEvent_S_BlockRepeat) then
set playerId = GetPlayerId(udg__GUIKeyPlayer)
if (playerKeyWasDown[playerId] == udg__GUIKeyIsPressed and playerPrevKey[playerId] == udg__GUIKeyTrigger) then
return false
endif
set playerPrevKey[playerId] = udg__GUIKeyTrigger
set playerKeyWasDown[playerId] = udg__GUIKeyIsPressed
endif
set udg__GUIKeyMeta = BlzGetTriggerPlayerMetaKey() // Set meta key for pressed key
set udg__GUIKeyIsReleased = not udg__GUIKeyIsPressed
// Trigger events
set udg_GUIKeyEvent = 0.0
set udg_GUIKeyEvent = 1.0
//set udg_GUIKeyEvent = 0.0
return false
endfunction
private function LWKeyCheck takes integer currentKey returns boolean
// Returns false if the key is not a lightweight key
return not (currentKey == $15 or /*
*/ currentKey == $17 or /*
*/ currentKey == $18 or /*
*/ currentKey == $19 or /*
*/ currentKey == $1C or /*
*/ currentKey == $1D or /*
*/ currentKey == $1E or /*
*/ currentKey == $1F or /*
*/ currentKey == $92 or /*
*/ currentKey == $92 or /*
*/ currentKey == $93 or /*
*/ currentKey == $94 or /*
*/ currentKey == $95 or /*
*/ currentKey == $96 or /*
*/ currentKey == $A6 or /*
*/ currentKey == $A7 or /*
*/ currentKey == $A8 or /*
*/ currentKey == $A9 or /*
*/ currentKey == $AA or /*
*/ currentKey == $AB or /*
*/ currentKey == $AC or /*
*/ currentKey == $B4 or /*
*/ currentKey == $B5 or /*
*/ currentKey == $B6 or /*
*/ currentKey == $B7 or /*
*/ currentKey == $E3 or /*
*/ currentKey == $E4 or /*
*/ currentKey == $E5 or /*
*/ currentKey == $E6 or /*
*/ currentKey == $E7 or /*
*/ currentKey == $E9 or /*
*/ currentKey == $EA or /*
*/ currentKey == $EB or /*
*/ currentKey == $EC or /*
*/ currentKey == $ED or /*
*/ currentKey == $EE or /*
*/ currentKey == $EF or /*
*/ currentKey == $F0 or /*
*/ currentKey == $F1 or /*
*/ currentKey == $F2 or /*
*/ currentKey == $F3 or /*
*/ currentKey == $F4 or /*
*/ currentKey == $F5 or /*
*/ currentKey == $F6 or /*
*/ currentKey == $F7 or /*
*/ currentKey == $F8 or /*
*/ currentKey == $F9 or /*
*/ currentKey == $FA or /*
*/ currentKey == $FB or /*
*/ currentKey == $FC or /*
*/ currentKey == $FD or /*
*/ currentKey == $FE)
return true
endfunction
private function RegisterKey takes nothing returns nothing
local integer playerId
local integer metaKey
local oskeytype key
//ConvertOsKeyType starts at index 8 and ends at index 254 ($08 to $FE)
set currentKey = currentKey + 1
if (currentKey > CONVERT_OS_KEY_TYPE_INDEX_END) then
// No more keys to register, finish.
call DestroyTrigger(GetTriggeringTrigger())
return
endif
// If lightweight version, only register certain keys
if (not IS_LIGHTWEIGHT_VERSION or LWKeyCheck(currentKey)) then
// Get the current oskey and register player key events
set key = ConvertOsKeyType(currentKey)
set playerId = 0
loop
// Only register oskey events for players that are active
// Registers both keyDown/keyUp and all metaKey combinations.
if (udg_GUIKeyEvent_S_EnablePlayer[playerId + 1]) then
set metaKey = 0
loop
call BlzTriggerRegisterPlayerKeyEvent(udg_GUIKeyEvent_System, Player(playerId), key, metaKey, false)
call BlzTriggerRegisterPlayerKeyEvent(udg_GUIKeyEvent_System, Player(playerId), key, metaKey, true)
set metaKey = metaKey + 1
exitwhen(metaKey > META_KEY_MAX)
endloop
endif
set playerId = playerId + 1
exitwhen(playerId >= bj_MAX_PLAYERS)
endloop
set key = null
endif
// Run this trigger again, until all keys have been registered
call TriggerEvaluate(GetTriggeringTrigger())
endfunction
private function SetupGUIKeys takes nothing returns nothing
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
// "Lightweight" keys
set udg_GUIKEY_BACKSPACE = GetHandleId(ConvertOsKeyType($08))
set udg_GUIKEY_TAB = GetHandleId(ConvertOsKeyType($09))
set udg_GUIKEY_CLEAR = GetHandleId(ConvertOsKeyType($0C))
set udg_GUIKEY_RETURN = GetHandleId(ConvertOsKeyType($0D))
set udg_GUIKEY_SHIFT = GetHandleId(ConvertOsKeyType($10))
set udg_GUIKEY_CONTROL = GetHandleId(ConvertOsKeyType($11))
set udg_GUIKEY_ALT = GetHandleId(ConvertOsKeyType($12))
set udg_GUIKEY_PAUSE = GetHandleId(ConvertOsKeyType($13))
set udg_GUIKEY_CAPSLOCK = GetHandleId(ConvertOsKeyType($14))
set udg_GUIKEY_ESCAPE = GetHandleId(ConvertOsKeyType($1B))
set udg_GUIKEY_SPACE = GetHandleId(ConvertOsKeyType($20))
set udg_GUIKEY_PAGEUP = GetHandleId(ConvertOsKeyType($21))
set udg_GUIKEY_PAGEDOWN = GetHandleId(ConvertOsKeyType($22))
set udg_GUIKEY_END = GetHandleId(ConvertOsKeyType($23))
set udg_GUIKEY_HOME = GetHandleId(ConvertOsKeyType($24))
set udg_GUIKEY_LEFT = GetHandleId(ConvertOsKeyType($25))
set udg_GUIKEY_UP = GetHandleId(ConvertOsKeyType($26))
set udg_GUIKEY_RIGHT = GetHandleId(ConvertOsKeyType($27))
set udg_GUIKEY_DOWN = GetHandleId(ConvertOsKeyType($28))
set udg_GUIKEY_SELECT = GetHandleId(ConvertOsKeyType($29))
set udg_GUIKEY_PRINT = GetHandleId(ConvertOsKeyType($2A))
set udg_GUIKEY_EXECUTE = GetHandleId(ConvertOsKeyType($2B))
set udg_GUIKEY_PRINTSCREEN = GetHandleId(ConvertOsKeyType($2C))
set udg_GUIKEY_INSERT = GetHandleId(ConvertOsKeyType($2D))
set udg_GUIKEY_DELETE = GetHandleId(ConvertOsKeyType($2E))
set udg_GUIKEY_HELP = GetHandleId(ConvertOsKeyType($2F))
set udg_GUIKEY_0 = GetHandleId(ConvertOsKeyType($30))
set udg_GUIKEY_1 = GetHandleId(ConvertOsKeyType($31))
set udg_GUIKEY_2 = GetHandleId(ConvertOsKeyType($32))
set udg_GUIKEY_3 = GetHandleId(ConvertOsKeyType($33))
set udg_GUIKEY_4 = GetHandleId(ConvertOsKeyType($34))
set udg_GUIKEY_5 = GetHandleId(ConvertOsKeyType($35))
set udg_GUIKEY_6 = GetHandleId(ConvertOsKeyType($36))
set udg_GUIKEY_7 = GetHandleId(ConvertOsKeyType($37))
set udg_GUIKEY_8 = GetHandleId(ConvertOsKeyType($38))
set udg_GUIKEY_9 = GetHandleId(ConvertOsKeyType($39))
set udg_GUIKEY_A = GetHandleId(ConvertOsKeyType($41))
set udg_GUIKEY_B = GetHandleId(ConvertOsKeyType($42))
set udg_GUIKEY_C = GetHandleId(ConvertOsKeyType($43))
set udg_GUIKEY_D = GetHandleId(ConvertOsKeyType($44))
set udg_GUIKEY_E = GetHandleId(ConvertOsKeyType($45))
set udg_GUIKEY_F = GetHandleId(ConvertOsKeyType($46))
set udg_GUIKEY_G = GetHandleId(ConvertOsKeyType($47))
set udg_GUIKEY_H = GetHandleId(ConvertOsKeyType($48))
set udg_GUIKEY_I = GetHandleId(ConvertOsKeyType($49))
set udg_GUIKEY_J = GetHandleId(ConvertOsKeyType($4A))
set udg_GUIKEY_K = GetHandleId(ConvertOsKeyType($4B))
set udg_GUIKEY_L = GetHandleId(ConvertOsKeyType($4C))
set udg_GUIKEY_M = GetHandleId(ConvertOsKeyType($4D))
set udg_GUIKEY_N = GetHandleId(ConvertOsKeyType($4E))
set udg_GUIKEY_O = GetHandleId(ConvertOsKeyType($4F))
set udg_GUIKEY_P = GetHandleId(ConvertOsKeyType($50))
set udg_GUIKEY_Q = GetHandleId(ConvertOsKeyType($51))
set udg_GUIKEY_R = GetHandleId(ConvertOsKeyType($52))
set udg_GUIKEY_S = GetHandleId(ConvertOsKeyType($53))
set udg_GUIKEY_T = GetHandleId(ConvertOsKeyType($54))
set udg_GUIKEY_U = GetHandleId(ConvertOsKeyType($55))
set udg_GUIKEY_V = GetHandleId(ConvertOsKeyType($56))
set udg_GUIKEY_W = GetHandleId(ConvertOsKeyType($57))
set udg_GUIKEY_X = GetHandleId(ConvertOsKeyType($58))
set udg_GUIKEY_Y = GetHandleId(ConvertOsKeyType($59))
set udg_GUIKEY_Z = GetHandleId(ConvertOsKeyType($5A))
set udg_GUIKEY_LMETA = GetHandleId(ConvertOsKeyType($5B))
set udg_GUIKEY_RMETA = GetHandleId(ConvertOsKeyType($5C))
set udg_GUIKEY_APPS = GetHandleId(ConvertOsKeyType($5D))
set udg_GUIKEY_SLEEP = GetHandleId(ConvertOsKeyType($5F))
set udg_GUIKEY_NUMPAD0 = GetHandleId(ConvertOsKeyType($60))
set udg_GUIKEY_NUMPAD1 = GetHandleId(ConvertOsKeyType($61))
set udg_GUIKEY_NUMPAD2 = GetHandleId(ConvertOsKeyType($62))
set udg_GUIKEY_NUMPAD3 = GetHandleId(ConvertOsKeyType($63))
set udg_GUIKEY_NUMPAD4 = GetHandleId(ConvertOsKeyType($64))
set udg_GUIKEY_NUMPAD5 = GetHandleId(ConvertOsKeyType($65))
set udg_GUIKEY_NUMPAD6 = GetHandleId(ConvertOsKeyType($66))
set udg_GUIKEY_NUMPAD7 = GetHandleId(ConvertOsKeyType($67))
set udg_GUIKEY_NUMPAD8 = GetHandleId(ConvertOsKeyType($68))
set udg_GUIKEY_NUMPAD9 = GetHandleId(ConvertOsKeyType($69))
set udg_GUIKEY_MULTIPLY = GetHandleId(ConvertOsKeyType($6A))
set udg_GUIKEY_ADD = GetHandleId(ConvertOsKeyType($6B))
set udg_GUIKEY_SEPARATOR = GetHandleId(ConvertOsKeyType($6C))
set udg_GUIKEY_SUBTRACT = GetHandleId(ConvertOsKeyType($6D))
set udg_GUIKEY_DECIMAL = GetHandleId(ConvertOsKeyType($6E))
set udg_GUIKEY_DIVIDE = GetHandleId(ConvertOsKeyType($6F))
set udg_GUIKEY_F1 = GetHandleId(ConvertOsKeyType($70))
set udg_GUIKEY_F2 = GetHandleId(ConvertOsKeyType($71))
set udg_GUIKEY_F3 = GetHandleId(ConvertOsKeyType($72))
set udg_GUIKEY_F4 = GetHandleId(ConvertOsKeyType($73))
set udg_GUIKEY_F5 = GetHandleId(ConvertOsKeyType($74))
set udg_GUIKEY_F6 = GetHandleId(ConvertOsKeyType($75))
set udg_GUIKEY_F7 = GetHandleId(ConvertOsKeyType($76))
set udg_GUIKEY_F8 = GetHandleId(ConvertOsKeyType($77))
set udg_GUIKEY_F9 = GetHandleId(ConvertOsKeyType($78))
set udg_GUIKEY_F10 = GetHandleId(ConvertOsKeyType($79))
set udg_GUIKEY_F11 = GetHandleId(ConvertOsKeyType($7A))
set udg_GUIKEY_F12 = GetHandleId(ConvertOsKeyType($7B))
set udg_GUIKEY_F13 = GetHandleId(ConvertOsKeyType($7C))
set udg_GUIKEY_F14 = GetHandleId(ConvertOsKeyType($7D))
set udg_GUIKEY_F15 = GetHandleId(ConvertOsKeyType($7E))
set udg_GUIKEY_F16 = GetHandleId(ConvertOsKeyType($7F))
set udg_GUIKEY_F17 = GetHandleId(ConvertOsKeyType($80))
set udg_GUIKEY_F18 = GetHandleId(ConvertOsKeyType($81))
set udg_GUIKEY_F19 = GetHandleId(ConvertOsKeyType($82))
set udg_GUIKEY_F20 = GetHandleId(ConvertOsKeyType($83))
set udg_GUIKEY_F21 = GetHandleId(ConvertOsKeyType($84))
set udg_GUIKEY_F22 = GetHandleId(ConvertOsKeyType($85))
set udg_GUIKEY_F23 = GetHandleId(ConvertOsKeyType($86))
set udg_GUIKEY_F24 = GetHandleId(ConvertOsKeyType($87))
set udg_GUIKEY_NUMLOCK = GetHandleId(ConvertOsKeyType($90))
set udg_GUIKEY_SCROLLLOCK = GetHandleId(ConvertOsKeyType($91))
set udg_GUIKEY_LSHIFT = GetHandleId(ConvertOsKeyType($A0))
set udg_GUIKEY_RSHIFT = GetHandleId(ConvertOsKeyType($A1))
set udg_GUIKEY_LCONTROL = GetHandleId(ConvertOsKeyType($A2))
set udg_GUIKEY_RCONTROL = GetHandleId(ConvertOsKeyType($A3))
set udg_GUIKEY_LALT = GetHandleId(ConvertOsKeyType($A4))
set udg_GUIKEY_RALT = GetHandleId(ConvertOsKeyType($A5))
set udg_GUIKEY_VOLUME_MUTE = GetHandleId(ConvertOsKeyType($AD))
set udg_GUIKEY_VOLUME_DOWN = GetHandleId(ConvertOsKeyType($AE))
set udg_GUIKEY_VOLUME_UP = GetHandleId(ConvertOsKeyType($AF))
set udg_GUIKEY_MEDIA_NEXT_TRACK = GetHandleId(ConvertOsKeyType($B0))
set udg_GUIKEY_MEDIA_PREV_TRACK = GetHandleId(ConvertOsKeyType($B1))
set udg_GUIKEY_MEDIA_STOP = GetHandleId(ConvertOsKeyType($B2))
set udg_GUIKEY_MEDIA_PLAY_PAUSE = GetHandleId(ConvertOsKeyType($B3))
set udg_GUIKEY_OEM_1 = GetHandleId(ConvertOsKeyType($BA))
set udg_GUIKEY_OEM_PLUS = GetHandleId(ConvertOsKeyType($BB))
set udg_GUIKEY_OEM_COMMA = GetHandleId(ConvertOsKeyType($BC))
set udg_GUIKEY_OEM_MINUS = GetHandleId(ConvertOsKeyType($BD))
set udg_GUIKEY_OEM_PERIOD = GetHandleId(ConvertOsKeyType($BE))
set udg_GUIKEY_OEM_2 = GetHandleId(ConvertOsKeyType($BF))
set udg_GUIKEY_OEM_3 = GetHandleId(ConvertOsKeyType($C0))
set udg_GUIKEY_OEM_4 = GetHandleId(ConvertOsKeyType($DB))
set udg_GUIKEY_OEM_5 = GetHandleId(ConvertOsKeyType($DC))
set udg_GUIKEY_OEM_6 = GetHandleId(ConvertOsKeyType($DD))
set udg_GUIKEY_OEM_7 = GetHandleId(ConvertOsKeyType($DE))
set udg_GUIKEY_OEM_8 = GetHandleId(ConvertOsKeyType($DF))
set udg_GUIKEY_OEM_AX = GetHandleId(ConvertOsKeyType($E1))
set udg_GUIKEY_OEM_102 = GetHandleId(ConvertOsKeyType($E2))
// Non "Lightweight" keys
static if not IS_LIGHTWEIGHT_VERSION then
set udg_GUIKEY_KANA = GetHandleId(ConvertOsKeyType($15))
set udg_GUIKEY_HANGUL = GetHandleId(ConvertOsKeyType($15))
set udg_GUIKEY_JUNJA = GetHandleId(ConvertOsKeyType($17))
set udg_GUIKEY_FINAL = GetHandleId(ConvertOsKeyType($18))
set udg_GUIKEY_HANJA = GetHandleId(ConvertOsKeyType($19))
set udg_GUIKEY_KANJI = GetHandleId(ConvertOsKeyType($19))
set udg_GUIKEY_CONVERT = GetHandleId(ConvertOsKeyType($1C))
set udg_GUIKEY_NONCONVERT = GetHandleId(ConvertOsKeyType($1D))
set udg_GUIKEY_ACCEPT = GetHandleId(ConvertOsKeyType($1E))
set udg_GUIKEY_MODECHANGE = GetHandleId(ConvertOsKeyType($1F))
set udg_GUIKEY_OEM_NEC_EQUAL = GetHandleId(ConvertOsKeyType($92))
set udg_GUIKEY_OEM_FJ_JISHO = GetHandleId(ConvertOsKeyType($92))
set udg_GUIKEY_OEM_FJ_MASSHOU = GetHandleId(ConvertOsKeyType($93))
set udg_GUIKEY_OEM_FJ_TOUROKU = GetHandleId(ConvertOsKeyType($94))
set udg_GUIKEY_OEM_FJ_LOYA = GetHandleId(ConvertOsKeyType($95))
set udg_GUIKEY_OEM_FJ_ROYA = GetHandleId(ConvertOsKeyType($96))
set udg_GUIKEY_BROWSER_BACK = GetHandleId(ConvertOsKeyType($A6))
set udg_GUIKEY_BROWSER_FORWARD = GetHandleId(ConvertOsKeyType($A7))
set udg_GUIKEY_BROWSER_REFRESH = GetHandleId(ConvertOsKeyType($A8))
set udg_GUIKEY_BROWSER_STOP = GetHandleId(ConvertOsKeyType($A9))
set udg_GUIKEY_BROWSER_SEARCH = GetHandleId(ConvertOsKeyType($AA))
set udg_GUIKEY_BROWSER_FAVORITES = GetHandleId(ConvertOsKeyType($AB))
set udg_GUIKEY_BROWSER_HOME = GetHandleId(ConvertOsKeyType($AC))
set udg_GUIKEY_LAUNCH_MAIL = GetHandleId(ConvertOsKeyType($B4))
set udg_GUIKEY_LAUNCH_MEDIA_SELECT = GetHandleId(ConvertOsKeyType($B5))
set udg_GUIKEY_LAUNCH_APP1 = GetHandleId(ConvertOsKeyType($B6))
set udg_GUIKEY_LAUNCH_APP2 = GetHandleId(ConvertOsKeyType($B7))
set udg_GUIKEY_ICO_HELP = GetHandleId(ConvertOsKeyType($E3))
set udg_GUIKEY_ICO_00 = GetHandleId(ConvertOsKeyType($E4))
set udg_GUIKEY_PROCESSKEY = GetHandleId(ConvertOsKeyType($E5))
set udg_GUIKEY_ICO_CLEAR = GetHandleId(ConvertOsKeyType($E6))
set udg_GUIKEY_PACKET = GetHandleId(ConvertOsKeyType($E7))
set udg_GUIKEY_OEM_RESET = GetHandleId(ConvertOsKeyType($E9))
set udg_GUIKEY_OEM_JUMP = GetHandleId(ConvertOsKeyType($EA))
set udg_GUIKEY_OEM_PA1 = GetHandleId(ConvertOsKeyType($EB))
set udg_GUIKEY_OEM_PA2 = GetHandleId(ConvertOsKeyType($EC))
set udg_GUIKEY_OEM_PA3 = GetHandleId(ConvertOsKeyType($ED))
set udg_GUIKEY_OEM_WSCTRL = GetHandleId(ConvertOsKeyType($EE))
set udg_GUIKEY_OEM_CUSEL = GetHandleId(ConvertOsKeyType($EF))
set udg_GUIKEY_OEM_ATTN = GetHandleId(ConvertOsKeyType($F0))
set udg_GUIKEY_OEM_FINISH = GetHandleId(ConvertOsKeyType($F1))
set udg_GUIKEY_OEM_COPY = GetHandleId(ConvertOsKeyType($F2))
set udg_GUIKEY_OEM_AUTO = GetHandleId(ConvertOsKeyType($F3))
set udg_GUIKEY_OEM_ENLW = GetHandleId(ConvertOsKeyType($F4))
set udg_GUIKEY_OEM_BACKTAB = GetHandleId(ConvertOsKeyType($F5))
set udg_GUIKEY_ATTN = GetHandleId(ConvertOsKeyType($F6))
set udg_GUIKEY_CRSEL = GetHandleId(ConvertOsKeyType($F7))
set udg_GUIKEY_EXSEL = GetHandleId(ConvertOsKeyType($F8))
set udg_GUIKEY_EREOF = GetHandleId(ConvertOsKeyType($F9))
set udg_GUIKEY_PLAY = GetHandleId(ConvertOsKeyType($FA))
set udg_GUIKEY_ZOOM = GetHandleId(ConvertOsKeyType($FB))
set udg_GUIKEY_NONAME = GetHandleId(ConvertOsKeyType($FC))
set udg_GUIKEY_PA1 = GetHandleId(ConvertOsKeyType($FD))
set udg_GUIKEY_OEM_CLEAR = GetHandleId(ConvertOsKeyType($FE))
endif
// "Lightweight" Key names to string
set udg_GUIKEY_NAME[udg_GUIKEY_BACKSPACE] = "BACKSPACE"
set udg_GUIKEY_NAME[udg_GUIKEY_TAB] = "TAB"
set udg_GUIKEY_NAME[udg_GUIKEY_CLEAR] = "CLEAR"
set udg_GUIKEY_NAME[udg_GUIKEY_RETURN] = "RETURN"
set udg_GUIKEY_NAME[udg_GUIKEY_SHIFT] = "SHIFT"
set udg_GUIKEY_NAME[udg_GUIKEY_CONTROL] = "CONTROL"
set udg_GUIKEY_NAME[udg_GUIKEY_ALT] = "ALT"
set udg_GUIKEY_NAME[udg_GUIKEY_PAUSE] = "PAUSE"
set udg_GUIKEY_NAME[udg_GUIKEY_CAPSLOCK] = "CAPSLOCK"
set udg_GUIKEY_NAME[udg_GUIKEY_ESCAPE] = "ESCAPE"
set udg_GUIKEY_NAME[udg_GUIKEY_SPACE] = "SPACE"
set udg_GUIKEY_NAME[udg_GUIKEY_PAGEUP] = "PAGEUP"
set udg_GUIKEY_NAME[udg_GUIKEY_PAGEDOWN] = "PAGEDOWN"
set udg_GUIKEY_NAME[udg_GUIKEY_END] = "END"
set udg_GUIKEY_NAME[udg_GUIKEY_HOME] = "HOME"
set udg_GUIKEY_NAME[udg_GUIKEY_LEFT] = "LEFT"
set udg_GUIKEY_NAME[udg_GUIKEY_UP] = "UP"
set udg_GUIKEY_NAME[udg_GUIKEY_RIGHT] = "RIGHT"
set udg_GUIKEY_NAME[udg_GUIKEY_DOWN] = "DOWN"
set udg_GUIKEY_NAME[udg_GUIKEY_SELECT] = "SELECT"
set udg_GUIKEY_NAME[udg_GUIKEY_PRINT] = "PRINT"
set udg_GUIKEY_NAME[udg_GUIKEY_EXECUTE] = "EXECUTE"
set udg_GUIKEY_NAME[udg_GUIKEY_PRINTSCREEN] = "PRINTSCREEN"
set udg_GUIKEY_NAME[udg_GUIKEY_INSERT] = "INSERT"
set udg_GUIKEY_NAME[udg_GUIKEY_DELETE] = "DELETE"
set udg_GUIKEY_NAME[udg_GUIKEY_HELP] = "HELP"
set udg_GUIKEY_NAME[udg_GUIKEY_0] = "0"
set udg_GUIKEY_NAME[udg_GUIKEY_1] = "1"
set udg_GUIKEY_NAME[udg_GUIKEY_2] = "2"
set udg_GUIKEY_NAME[udg_GUIKEY_3] = "3"
set udg_GUIKEY_NAME[udg_GUIKEY_4] = "4"
set udg_GUIKEY_NAME[udg_GUIKEY_5] = "5"
set udg_GUIKEY_NAME[udg_GUIKEY_6] = "6"
set udg_GUIKEY_NAME[udg_GUIKEY_7] = "7"
set udg_GUIKEY_NAME[udg_GUIKEY_8] = "8"
set udg_GUIKEY_NAME[udg_GUIKEY_9] = "9"
set udg_GUIKEY_NAME[udg_GUIKEY_A] = "A"
set udg_GUIKEY_NAME[udg_GUIKEY_B] = "B"
set udg_GUIKEY_NAME[udg_GUIKEY_C] = "C"
set udg_GUIKEY_NAME[udg_GUIKEY_D] = "D"
set udg_GUIKEY_NAME[udg_GUIKEY_E] = "E"
set udg_GUIKEY_NAME[udg_GUIKEY_F] = "F"
set udg_GUIKEY_NAME[udg_GUIKEY_G] = "G"
set udg_GUIKEY_NAME[udg_GUIKEY_H] = "H"
set udg_GUIKEY_NAME[udg_GUIKEY_I] = "I"
set udg_GUIKEY_NAME[udg_GUIKEY_J] = "J"
set udg_GUIKEY_NAME[udg_GUIKEY_K] = "K"
set udg_GUIKEY_NAME[udg_GUIKEY_L] = "L"
set udg_GUIKEY_NAME[udg_GUIKEY_M] = "M"
set udg_GUIKEY_NAME[udg_GUIKEY_N] = "N"
set udg_GUIKEY_NAME[udg_GUIKEY_O] = "O"
set udg_GUIKEY_NAME[udg_GUIKEY_P] = "P"
set udg_GUIKEY_NAME[udg_GUIKEY_Q] = "Q"
set udg_GUIKEY_NAME[udg_GUIKEY_R] = "R"
set udg_GUIKEY_NAME[udg_GUIKEY_S] = "S"
set udg_GUIKEY_NAME[udg_GUIKEY_T] = "T"
set udg_GUIKEY_NAME[udg_GUIKEY_U] = "U"
set udg_GUIKEY_NAME[udg_GUIKEY_V] = "V"
set udg_GUIKEY_NAME[udg_GUIKEY_W] = "W"
set udg_GUIKEY_NAME[udg_GUIKEY_X] = "X"
set udg_GUIKEY_NAME[udg_GUIKEY_Y] = "Y"
set udg_GUIKEY_NAME[udg_GUIKEY_Z] = "Z"
set udg_GUIKEY_NAME[udg_GUIKEY_LMETA] = "LMETA"
set udg_GUIKEY_NAME[udg_GUIKEY_RMETA] = "RMETA"
set udg_GUIKEY_NAME[udg_GUIKEY_APPS] = "APPS"
set udg_GUIKEY_NAME[udg_GUIKEY_SLEEP] = "SLEEP"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD0] = "NUMPAD0"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD1] = "NUMPAD1"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD2] = "NUMPAD2"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD3] = "NUMPAD3"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD4] = "NUMPAD4"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD5] = "NUMPAD5"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD6] = "NUMPAD6"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD7] = "NUMPAD7"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD8] = "NUMPAD8"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMPAD9] = "NUMPAD9"
set udg_GUIKEY_NAME[udg_GUIKEY_MULTIPLY] = "MULTIPLY"
set udg_GUIKEY_NAME[udg_GUIKEY_ADD] = "ADD"
set udg_GUIKEY_NAME[udg_GUIKEY_SEPARATOR] = "SEPARATOR"
set udg_GUIKEY_NAME[udg_GUIKEY_SUBTRACT] = "SUBTRACT"
set udg_GUIKEY_NAME[udg_GUIKEY_DECIMAL] = "DECIMAL"
set udg_GUIKEY_NAME[udg_GUIKEY_DIVIDE] = "DIVIDE"
set udg_GUIKEY_NAME[udg_GUIKEY_F1] = "F1"
set udg_GUIKEY_NAME[udg_GUIKEY_F2] = "F2"
set udg_GUIKEY_NAME[udg_GUIKEY_F3] = "F3"
set udg_GUIKEY_NAME[udg_GUIKEY_F4] = "F4"
set udg_GUIKEY_NAME[udg_GUIKEY_F5] = "F5"
set udg_GUIKEY_NAME[udg_GUIKEY_F6] = "F6"
set udg_GUIKEY_NAME[udg_GUIKEY_F7] = "F7"
set udg_GUIKEY_NAME[udg_GUIKEY_F8] = "F8"
set udg_GUIKEY_NAME[udg_GUIKEY_F9] = "F9"
set udg_GUIKEY_NAME[udg_GUIKEY_F10] = "F10"
set udg_GUIKEY_NAME[udg_GUIKEY_F11] = "F11"
set udg_GUIKEY_NAME[udg_GUIKEY_F12] = "F12"
set udg_GUIKEY_NAME[udg_GUIKEY_F13] = "F13"
set udg_GUIKEY_NAME[udg_GUIKEY_F14] = "F14"
set udg_GUIKEY_NAME[udg_GUIKEY_F15] = "F15"
set udg_GUIKEY_NAME[udg_GUIKEY_F16] = "F16"
set udg_GUIKEY_NAME[udg_GUIKEY_F17] = "F17"
set udg_GUIKEY_NAME[udg_GUIKEY_F18] = "F18"
set udg_GUIKEY_NAME[udg_GUIKEY_F19] = "F19"
set udg_GUIKEY_NAME[udg_GUIKEY_F20] = "F20"
set udg_GUIKEY_NAME[udg_GUIKEY_F21] = "F21"
set udg_GUIKEY_NAME[udg_GUIKEY_F22] = "F22"
set udg_GUIKEY_NAME[udg_GUIKEY_F23] = "F23"
set udg_GUIKEY_NAME[udg_GUIKEY_F24] = "F24"
set udg_GUIKEY_NAME[udg_GUIKEY_NUMLOCK] = "NUMLOCK"
set udg_GUIKEY_NAME[udg_GUIKEY_SCROLLLOCK] = "SCROLLLOCK"
set udg_GUIKEY_NAME[udg_GUIKEY_LSHIFT] = "LSHIFT"
set udg_GUIKEY_NAME[udg_GUIKEY_RSHIFT] = "RSHIFT"
set udg_GUIKEY_NAME[udg_GUIKEY_LCONTROL] = "LCONTROL"
set udg_GUIKEY_NAME[udg_GUIKEY_RCONTROL] = "RCONTROL"
set udg_GUIKEY_NAME[udg_GUIKEY_LALT] = "LALT"
set udg_GUIKEY_NAME[udg_GUIKEY_RALT] = "RALT"
set udg_GUIKEY_NAME[udg_GUIKEY_VOLUME_MUTE] = "VOLUME_MUTE"
set udg_GUIKEY_NAME[udg_GUIKEY_VOLUME_DOWN] = "VOLUME_DOWN"
set udg_GUIKEY_NAME[udg_GUIKEY_VOLUME_UP] = "VOLUME_UP"
set udg_GUIKEY_NAME[udg_GUIKEY_MEDIA_NEXT_TRACK] = "MEDIA_NEXT_TRACK"
set udg_GUIKEY_NAME[udg_GUIKEY_MEDIA_PREV_TRACK] = "MEDIA_PREV_TRACK"
set udg_GUIKEY_NAME[udg_GUIKEY_MEDIA_STOP] = "MEDIA_STOP"
set udg_GUIKEY_NAME[udg_GUIKEY_MEDIA_PLAY_PAUSE] = "MEDIA_PLAY_PAUSE"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_1] = "OEM_1"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_PLUS] = "OEM_PLUS"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_COMMA] = "OEM_COMMA"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_MINUS] = "OEM_MINUS"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_PERIOD] = "OEM_PERIOD"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_2] = "OEM_2"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_3] = "OEM_3"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_4] = "OEM_4"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_5] = "OEM_5"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_6] = "OEM_6"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_7] = "OEM_7"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_8] = "OEM_8"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_AX] = "OEM_AX"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_102] = "OEM_102"
// Non "Lightweight" Key names to string
static if not IS_LIGHTWEIGHT_VERSION then
set udg_GUIKEY_NAME[udg_GUIKEY_KANA] = "KANA"
set udg_GUIKEY_NAME[udg_GUIKEY_HANGUL] = "HANGUL"
set udg_GUIKEY_NAME[udg_GUIKEY_JUNJA] = "JUNJA"
set udg_GUIKEY_NAME[udg_GUIKEY_FINAL] = "FINAL"
set udg_GUIKEY_NAME[udg_GUIKEY_HANJA] = "HANJA"
set udg_GUIKEY_NAME[udg_GUIKEY_KANJI] = "KANJI"
set udg_GUIKEY_NAME[udg_GUIKEY_CONVERT] = "CONVERT"
set udg_GUIKEY_NAME[udg_GUIKEY_NONCONVERT] = "NONCONVERT"
set udg_GUIKEY_NAME[udg_GUIKEY_ACCEPT] = "ACCEPT"
set udg_GUIKEY_NAME[udg_GUIKEY_MODECHANGE] = "MODECHANGE"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_NEC_EQUAL]= "OEM_NEC_EQUAL"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FJ_JISHO] = "OEM_FJ_JISHO"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FJ_MASSHOU] = "OEM_FJ_MASSHOU"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FJ_TOUROKU] = "OEM_FJ_TOUROKU"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FJ_LOYA] = "OEM_FJ_LOYA"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FJ_ROYA] = "OEM_FJ_ROYA"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_BACK] = "BROWSER_BACK"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_FORWARD] = "BROWSER_FORWARD"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_REFRESH] = "BROWSER_REFRESH"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_STOP] = "BROWSER_STOP"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_SEARCH] = "BROWSER_SEARCH"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_FAVORITES] = "BROWSER_FAVORITES"
set udg_GUIKEY_NAME[udg_GUIKEY_BROWSER_HOME] = "BROWSER_HOME"
set udg_GUIKEY_NAME[udg_GUIKEY_LAUNCH_MAIL] = "LAUNCH_MAIL"
set udg_GUIKEY_NAME[udg_GUIKEY_LAUNCH_MEDIA_SELECT] = "LAUNCH_MEDIA_SELECT"
set udg_GUIKEY_NAME[udg_GUIKEY_LAUNCH_APP1] = "LAUNCH_APP1"
set udg_GUIKEY_NAME[udg_GUIKEY_LAUNCH_APP2] = "LAUNCH_APP2"
set udg_GUIKEY_NAME[udg_GUIKEY_ICO_HELP] = "ICO_HELP"
set udg_GUIKEY_NAME[udg_GUIKEY_ICO_00] = "ICO_00"
set udg_GUIKEY_NAME[udg_GUIKEY_PROCESSKEY] = "PROCESSKEY"
set udg_GUIKEY_NAME[udg_GUIKEY_ICO_CLEAR] = "ICO_CLEAR"
set udg_GUIKEY_NAME[udg_GUIKEY_PACKET] = "PACKET"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_RESET] = "OEM_RESET"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_JUMP] = "OEM_JUMP"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_PA1] = "OEM_PA1"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_PA2] = "OEM_PA2"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_PA3] = "OEM_PA3"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_WSCTRL] = "OEM_WSCTRL"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_CUSEL] = "OEM_CUSEL"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_ATTN] = "OEM_ATTN"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_FINISH] = "OEM_FINISH"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_COPY] = "OEM_COPY"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_AUTO] = "OEM_AUTO"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_ENLW] = "OEM_ENLW"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_BACKTAB] = "OEM_BACKTAB"
set udg_GUIKEY_NAME[udg_GUIKEY_ATTN] = "ATTN"
set udg_GUIKEY_NAME[udg_GUIKEY_CRSEL] = "CRSEL"
set udg_GUIKEY_NAME[udg_GUIKEY_EXSEL] = "EXSEL"
set udg_GUIKEY_NAME[udg_GUIKEY_EREOF] = "EREOF"
set udg_GUIKEY_NAME[udg_GUIKEY_PLAY] = "PLAY"
set udg_GUIKEY_NAME[udg_GUIKEY_ZOOM] = "ZOOM"
set udg_GUIKEY_NAME[udg_GUIKEY_NONAME] = "NONAME"
set udg_GUIKEY_NAME[udg_GUIKEY_PA1] = "PA1"
set udg_GUIKEY_NAME[udg_GUIKEY_OEM_CLEAR] = "OEM_CLEAR"
endif
endfunction
public function GUIKeyEventInit takes nothing returns nothing
local trigger t
// Create the trigger that handles oskey input
set udg_GUIKeyEvent_System = CreateTrigger()
call TriggerAddCondition(udg_GUIKeyEvent_System, Condition(function OnGUIKeyEvent))
// Register oskey events for players
// Run each key as a new thread to avoid op-limit (but shouldn't be an issue most likely anyway).
// Results in ~100k operations for 24 players
set currentKey = CONVERT_OS_KEY_TYPE_INDEX_START - 1
set t = CreateTrigger()
call TriggerAddCondition(t, Condition(function RegisterKey))
call TriggerEvaluate(t)
set t = null
//Setup the GUI key variables after a short delay. If called at map init GetHandleId(ConvertOsKeyType(xx)) returns 0
call TimerStart(CreateTimer(), .0, false, function SetupGUIKeys)
endfunction
endlibrary
//=====================================================================================
// Easy Item Stack 'n Split v2.7.4
// by Dangerb0y
//=====================================================================================
library EasyItemStacknSplit initializer onInit
//=====================================================================================
//
// This system adds some much needed item stacking, item splitting, and full inventory
// functionality to Warcraft III.
//
// A couple of useful functions are also included...
//
// - UnitInventoryFull( unit )
// Returns true if all of a unit's inventory slots are occupied, else false.
//
// - UnitStackItem( unit, item )
// Works like UnitAddItem(), but will try to stack items even if inventory is full.
// If excess items from an item stack are dropped, returns the item, else null.
//
//=====================================================================================
// SYSTEM PARAMETERS
//=====================================================================================
globals
// Allow item splitting with double right-click?
private boolean SPLIT = false
// Amount to split from stack... (0 = half)
private integer SPLIT_SIZE = 1
// Allow consecutively split items to stack together?
private boolean SPLIT_STACK = true
private real SPLIT_STACK_DELAY = 2.00
// Allow split items to be dropped if no inventory slots are open?
private boolean SPLIT_DROP = true
// Use item levels to determine stack limit? (false = unlimited stacks)
private boolean USE_ITEM_LEVEL = true
// Full inventory error sound filename... (null = disabled)
private string ERROR_SOUND = "Sound\\Interface\\Error.wav"
endglobals
//=====================================================================================
// DO NOT EDIT BELOW THIS LINE
//=====================================================================================
globals
private unit array tu
private unit array su
private item array ti
private item array si
private item array sii
private real array sc
private integer tt = 0
private integer st = 0
private timer t = CreateTimer()
endglobals
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// PUBLIC FUNCTION : UnitInventoryFull( unit )
// Checks if all the inventory slots of a unit are occupied.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function UnitInventoryFull takes unit u returns boolean
local integer is = UnitInventorySize( u )
local integer s = 0
loop
exitwhen s >= is
if UnitItemInSlot(u, s) == null then
return false
endif
set s = s + 1
endloop
return true
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// PUBLIC FUNCTION : UnitStackItem( unit, item )
// Works like UnitAddItem() with full inventory functionality.
// Returns true if excess items are dropped. Otherwise false.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function UnitStackItem takes unit u, item i returns boolean
local integer ic = GetItemCharges( i )
local integer is
local integer il
local integer it
local item ii
local integer iic
local integer s = 0
local real px
local real py
local real ua
// Check if the item is a powerup
if IsItemPowerup(i) then
return false
endif
// Make sure the item has charges
if ic <= 0 then
// If not we just give it to the unit
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, i )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
else
// Set vars
set is = UnitInventorySize( u )
set il = GetItemLevel( i )
set it = GetItemTypeId( i )
// We can remove the item, we have all the data we need from it
call RemoveItem( i )
// Look for items of the same type and try stack onto them
loop
set ii = UnitItemInSlot( u, s )
set iic = GetItemCharges( ii )
if ii != null and (not USE_ITEM_LEVEL or il == 0 or iic < il) and GetItemTypeId(ii) == it then
if USE_ITEM_LEVEL and il > 0 and iic + ic > il then
call SetItemCharges( ii, il )
set ic = iic + ic - il
else
call SetItemCharges( ii, iic + ic )
set ic = 0
endif
endif
set s = s + 1
exitwhen ic <= 0 or s >= is
endloop
// If there are any charges left over, look for open slots
if ic > 0 then
set px = GetUnitX( u )
set py = GetUnitY( u )
set s = 0
loop
set ii = UnitItemInSlot( u, s )
if ii == null then
set ii = CreateItem( it, px, py )
if USE_ITEM_LEVEL and il > 0 and ic > il then
call SetItemCharges( ii, il )
set ic = ic - il
else
call SetItemCharges( ii, ic )
set ic = 0
endif
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, ii )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
endif
set s = s + 1
exitwhen ic <= 0 or s >= is
endloop
// If there are still charges left over, drop them on the ground
if ic > 0 then
set ua = GetUnitFacing( u )
set px = GetUnitX( u ) + 100 * Cos( ua * bj_DEGTORAD )
set py = GetUnitY( u ) + 100 * Sin( ua * bj_DEGTORAD )
loop
if ic > il then
set iic = il
set ic = ic - il
else
set iic = ic
set ic = 0
endif
set ii = CreateItem( it, px, py )
call SetItemCharges( ii, iic )
exitwhen ic <= 0
endloop
return true
endif
endif
endif
// Nothing dropped
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// TEXTMACRO : EasyItemStacknSplit_PLAYITEMSOUND( soundname, unitvar )
// Plays item sound for player if the triggering unit is nearby.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! textmacro EasyItemStacknSplit_PLAYITEMSOUND takes FILENAME
set str = "Sound\\Interface\\$FILENAME$.wav"
if GetLocalPlayer() != p then
set str = ""
endif
set snd = CreateSound( str, false, true, false, 12700, 12700, "" )
call AttachSoundToUnit( snd, u )
call SetSoundVolume( snd, 75 )
call SetSoundDistances( snd, 600.0, 1024.0 )
call SetSoundDistanceCutoff( snd, 1536.0 )
call StartSound( snd )
call KillSoundWhenDone( snd )
//! endtextmacro
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : TimerController
// EVENTS : Global Timer (t) expires (periodically, 0.05)
// Runs through full-stack and split-stack queues, and works its magic.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function TimerController takes nothing returns nothing
local unit u
local item i
local item ii
local integer x = 0
local integer o
local real px
local real py
local player p
local string str
local sound snd
// Run through full-stack queue
if tt > 0 then
loop
set u = tu[x]
set i = ti[x]
if u != null and i != null and not IsItemOwned(i) and GetWidgetLife(i) > 0 and GetWidgetLife(u) > 0 then
set o = GetUnitCurrentOrder( u )
set px = GetItemX( i ) - GetUnitX( u )
set py = GetItemY( i ) - GetUnitY( u )
if px * px + py * py <= 22500 or o != 851986 then
if o == 851986 then
set p = GetOwningPlayer( u )
// Play the "Item Get" sound
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "PickUpItem" )
call IssueImmediateOrder( u, "stop" )
call SetUnitFacing( u, bj_RADTODEG * Atan2(GetItemY(i) - GetUnitY(u), GetItemX(i) - GetUnitX(u)) )
if UnitStackItem(u, i) then
// Play the "Item Drop" sound
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "HeroDropItem1" )
endif
endif
set tt = tt - 1
if tt > 0 then
set tu[x] = tu[tt]
set ti[x] = ti[tt]
set x = x - 1
endif
endif
elseif u != null or i != null then
call IssueImmediateOrder( u, "stop" )
set tt = tt - 1
if tt > 0 then
set tu[x] = tu[tt]
set ti[x] = ti[tt]
set x = x - 1
endif
endif
set x = x + 1
exitwhen x >= tt
endloop
endif
// Run through split-stack queue
if SPLIT_STACK and st > 0 then
set x = 0
loop
set u = su[x]
set i = si[x]
set ii = sii[x]
set px = sc[x]
if u != null and i != null and ii != null and px > 0 and UnitHasItem(u, i) and UnitHasItem(u, ii) then
set sc[x] = px - 0.05
else
set st = st - 1
if st > 0 then
set su[x] = su[st]
set si[x] = si[st]
set sii[x] = sii[st]
set sc[x] = sc[st]
set x = x - 1
endif
endif
set x = x + 1
exitwhen x >= st
endloop
endif
// Pause timer if not needed
if tt <= 0 and (not SPLIT_STACK or st <= 0) then
call PauseTimer( t )
endif
set u = null
set i = null
set p = null
set snd = null
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : CancelController
// EVENTS : Unit Targets Point
// Flushes trigger-unit and target-item from timer queue.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function CancelController takes nothing returns boolean
local integer x = 0
if tt > 0 then
loop
if tu[x] == GetTriggerUnit() and (GetOrderPointX() != GetItemX(ti[x]) or GetOrderPointY() != GetItemY(ti[x])) then
set tt = tt - 1
if tt > 0 then
set tu[x] = tu[tt]
set ti[x] = ti[tt]
set x = x - 1
elseif not SPLIT_STACK or st <= 0 then
call PauseTimer( t )
endif
endif
set x = x + 1
exitwhen x >= tt
endloop
endif
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : ActionController
// EVENTS : Unit Acquires Item, Unit Targets Object
// Main system controller. Determines unit order and runs actions accordingly.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function ActionController takes nothing returns boolean
local item i = GetOrderTargetItem()
local integer o = GetIssuedOrderId()
local unit u
local player p
local item ii
local integer is
local integer iis
local integer s
local integer ss
local boolean full
local real ua
local string str
local sound snd
if i == null then
set i = GetManipulatedItem()
endif
set s = GetItemCharges( i )
if i != null and (o == 851971 or (s > 0 and (o == 0 or (o > 852001 and o < 852008)))) then
set u = GetTriggerUnit()
set is = UnitInventorySize( u )
if is > 0 then
if o > 852001 and o < 852008 then
// The item is being moved to another inventory slot
if UnitHasItem(u, i) then
set o = o - 852002
set ii = UnitItemInSlot( u, o )
if GetItemTypeId(ii) == GetItemTypeId(i) then
if ii == i then
// Split items
if SPLIT then
set full = UnitInventoryFull( u )
if s > 1 and (SPLIT_DROP or not full) then
if SPLIT_SIZE > 0 then
if SPLIT_SIZE >= s then
set ss = s - 1
else
set ss = SPLIT_SIZE
endif
else
set ss = s / 2
endif
call SetItemCharges( i, s - ss )
if SPLIT_STACK then
set ii = null
if st > 0 then
set o = 0
loop
if u == su[o] then
set ii = sii[o]
set iis = GetItemCharges( ii )
set s = GetItemLevel( ii )
exitwhen true
endif
set o = o + 1
exitwhen o >= st
endloop
endif
endif
if SPLIT_STACK and ii != null and ii != i and si[o] == i and (not USE_ITEM_LEVEL or s == 0 or iis < s) and UnitHasItem(u, ii) and GetItemTypeId(ii) == GetItemTypeId(i) then
call SetItemCharges( ii, iis + ss )
set sc[o] = SPLIT_STACK_DELAY
else
set ua = GetUnitFacing( u )
set ii = CreateItem( GetItemTypeId(i), GetUnitX(u) + 100 * Cos(ua * bj_DEGTORAD), GetUnitY(u) + 100 * Sin(ua * bj_DEGTORAD) )
call SetItemCharges( ii, ss )
if not full then
call DisableTrigger( gg_trg_EasyItemStacknSplit )
call UnitAddItem( u, ii )
call EnableTrigger( gg_trg_EasyItemStacknSplit )
if SPLIT_STACK then
set o = 0
if st > 0 then
loop
if su[o] == u then
set si[o] = i
set sii[o] = ii
set sc[o] = SPLIT_STACK_DELAY
set o = -1
else
set o = o + 1
endif
exitwhen o >= st or o == -1
endloop
endif
if o >= 0 then
if st == 0 then
call TimerStart( t, 0.05, true, function TimerController )
endif
set su[st] = u
set si[st] = i
set sii[st] = ii
set sc[st] = SPLIT_STACK_DELAY
set st = st + 1
endif
endif
else
// Play the "Item Drop" sound
set p = GetOwningPlayer( u )
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "HeroDropItem1" )
endif
endif
endif
endif
else
// Stack items
set is = GetItemLevel( i )
set iis = GetItemCharges( ii )
if USE_ITEM_LEVEL and is > 0 and iis + s > is then
if o < is and iis < GetItemLevel(ii) then
call SetItemCharges( ii, iis + s - is )
call SetItemCharges( i, is )
endif
else
call SetItemCharges( ii, iis + s )
call RemoveItem( i )
endif
endif
endif
endif
elseif o == 851971 then
if UnitInventoryFull(u) then
// The item is being targeted with a full inventory so we add it to the timer queue
set o = GetItemLevel( i )
set iis = GetItemTypeId( i )
set s = 0
loop
set ii = UnitItemInSlot( u, s )
if ii != i and GetItemTypeId(ii) == iis and (not USE_ITEM_LEVEL or o == 0 or GetItemCharges(ii) < o) then
set s = is + 1
else
set s = s + 1
endif
exitwhen s >= is
endloop
if s > is and GetItemCharges(i) > 0 then
set s = 0
if tt > 0 then
loop
if tu[s] == u then
set ti[s] = i
set s = -1
else
set s = s + 1
endif
exitwhen s >= tt or s == -1
endloop
endif
if s >= 0 then
if tt == 0 then
call TimerStart( t, 0.05, true, function TimerController )
endif
set tu[tt] = u
set ti[tt] = i
set tt = tt + 1
endif
call IssuePointOrder( u, "move", GetItemX(i), GetItemY(i) )
else
// Full inventory error
call IssueImmediateOrder( u, "stop" )
set p = GetOwningPlayer( u )
// Play error sound
if ERROR_SOUND != null and ERROR_SOUND != "" then
set str = ERROR_SOUND
if GetLocalPlayer() != p then
set str = ""
endif
set snd = CreateSound( str, false, false, false, 12700, 12700, "" )
call SetSoundVolume( snd, 127 )
call StartSound( snd )
call KillSoundWhenDone( snd )
endif
endif
endif
else
// The item is being acquired so we stack it
if UnitStackItem(u, i) then
// Play the "Item Drop" sound
set p = GetOwningPlayer( u )
//! runtextmacro EasyItemStacknSplit_PLAYITEMSOUND( "Sound\\Interface\\HeroDropItem1.wav" )
endif
endif
endif
endif
set u = null
set p = null
set i = null
set ii = null
set snd = null
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// CONTROLLER : PreloadController
// EVENTS : Game Time Elapsed = 0.00
// Preloads sound files so that they play the first time around.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function PreloadController takes nothing returns boolean
local string array str
local sound snd
local integer x = 0
set str[0] = "Sound\\Interface\\PickUpItem.wav"
set str[1] = "Sound\\Interface\\HeroDropItem1.wav"
if ERROR_SOUND != null and ERROR_SOUND != "" then
set str[2] = ERROR_SOUND
endif
loop
exitwhen str[x] == null
set snd = CreateSound( str[x], false, false, false, 12700, 12700, "" )
call SetSoundVolume( snd, 0 )
call StartSound( snd )
call KillSoundWhenDone( snd )
set x = x + 1
endloop
set snd = null
call DestroyTrigger( GetTriggeringTrigger() )
return false
endfunction
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// TRIGGER INITIALIZER
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private function onInit takes nothing returns nothing
local trigger CancelTrigger = CreateTrigger()
local trigger PreloadTrigger = CreateTrigger()
local integer x = 0
set gg_trg_EasyItemStacknSplit = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent( gg_trg_EasyItemStacknSplit, Player(x), EVENT_PLAYER_UNIT_PICKUP_ITEM, null )
call TriggerRegisterPlayerUnitEvent( gg_trg_EasyItemStacknSplit, Player(x), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null )
call TriggerRegisterPlayerUnitEvent( CancelTrigger, Player(x), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null )
set x = x + 1
exitwhen x >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerRegisterTimerEvent( PreloadTrigger, 0.00, false )
call TriggerAddCondition( gg_trg_EasyItemStacknSplit, function ActionController )
call TriggerAddCondition( CancelTrigger, function CancelController )
call TriggerAddCondition( PreloadTrigger, function PreloadController )
endfunction
endlibrary
library NewBonus requires optional DamageInterface, optional Evasion, optional CriticalStrike, optional SpellPower, optional LifeSteal, optional SpellVamp, optional CooldownReduction
/* ----------------------- NewBonus v2.3 by Chopinski ----------------------- */
//! novjass
Since ObjectMerger is broken and we still have no means to edit
bonus values (green values) i decided to create a light weight
Bonus library that works in the same way that the original Bonus Mod
by Earth Fury did. NewBonus requires patch 1.30+.
Credits to Earth Fury for the original Bonus idea
How to Import?
Importing bonus mod is really simple. Just copy the 9 abilities with the
prefix "NewBonus" from the Object Editor into your map and match their new raw
code to the bonus types in the global block below. Then create a trigger called
NewBonus, convert it to custom text and paste this code there. You done!
//! endnovjass
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// If true will use the extended version of the system.
// Make sure you have the DamageInterface and Cooldown Reduction libraries
public constant boolean EXTENDED = true
// This is the maximum recursion limit allowed by the system.
// It's value must be greater than or equal to 0. When equal to 0
// no recursion is allowed. Values too big can cause screen freezes.
private constant integer RECURSION_LIMIT = 8
//The bonus types
constant integer BONUS_DAMAGE = 1
constant integer BONUS_ARMOR = 2
constant integer BONUS_AGILITY = 3
constant integer BONUS_STRENGTH = 4
constant integer BONUS_INTELLIGENCE = 5
constant integer BONUS_HEALTH = 6
constant integer BONUS_MANA = 7
constant integer BONUS_MOVEMENT_SPEED = 8
constant integer BONUS_SIGHT_RANGE = 9
constant integer BONUS_HEALTH_REGEN = 10
constant integer BONUS_MANA_REGEN = 11
constant integer BONUS_ATTACK_SPEED = 12
constant integer BONUS_MAGIC_RESISTANCE = 13
constant integer BONUS_EVASION_CHANCE = 14
constant integer BONUS_CRITICAL_DAMAGE = 15
constant integer BONUS_CRITICAL_CHANCE = 16
constant integer BONUS_LIFE_STEAL = 17
constant integer BONUS_MISS_CHANCE = 18
constant integer BONUS_SPELL_POWER_FLAT = 19
constant integer BONUS_SPELL_POWER_PERCENT = 20
constant integer BONUS_SPELL_VAMP = 21
constant integer BONUS_COOLDOWN_REDUCTION = 22
constant integer BONUS_COOLDOWN_REDUCTION_FLAT = 23
constant integer BONUS_COOLDOWN_OFFSET = 24
//The abilities codes for each bonus
//When pasting the abilities over to your map
//their raw code should match the bonus here
private constant integer DAMAGE_ABILITY = 'Z001'
private constant integer ARMOR_ABILITY = 'Z002'
private constant integer STATS_ABILITY = 'Z003'
private constant integer HEALTH_ABILITY = 'Z004'
private constant integer MANA_ABILITY = 'Z005'
private constant integer HEALTHREGEN_ABILITY = 'Z006'
private constant integer MANAREGEN_ABILITY = 'Z007'
private constant integer ATTACKSPEED_ABILITY = 'Z008'
private constant integer MOVEMENTSPEED_ABILITY = 'Z009'
private constant integer SIGHT_RANGE_ABILITY = 'Z00A'
private constant integer MAGIC_RESISTANCE_ABILITY = 'Z00B'
private constant integer CRITICAL_STRIKE_ABILITY = 'Z00C'
private constant integer EVASION_ABILITY = 'Z00D'
private constant integer LIFE_STEAL_ABILITY = 'Z00E'
//The abilities fields that are modified. For the sake of readability
private constant abilityintegerlevelfield DAMAGE_FIELD = ABILITY_ILF_ATTACK_BONUS
private constant abilityintegerlevelfield ARMOR_FIELD = ABILITY_ILF_DEFENSE_BONUS_IDEF
private constant abilityintegerlevelfield AGILITY_FIELD = ABILITY_ILF_AGILITY_BONUS
private constant abilityintegerlevelfield STRENGTH_FIELD = ABILITY_ILF_STRENGTH_BONUS_ISTR
private constant abilityintegerlevelfield INTELLIGENCE_FIELD = ABILITY_ILF_INTELLIGENCE_BONUS
private constant abilityintegerlevelfield HEALTH_FIELD = ABILITY_ILF_MAX_LIFE_GAINED
private constant abilityintegerlevelfield MANA_FIELD = ABILITY_ILF_MAX_MANA_GAINED
private constant abilityintegerlevelfield MOVEMENTSPEED_FIELD = ABILITY_ILF_MOVEMENT_SPEED_BONUS
private constant abilityintegerlevelfield SIGHT_RANGE_FIELD = ABILITY_ILF_SIGHT_RANGE_BONUS
private constant abilityreallevelfield HEALTHREGEN_FIELD = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
private constant abilityreallevelfield MANAREGEN_FIELD = ABILITY_RLF_AMOUNT_REGENERATED
private constant abilityreallevelfield ATTACKSPEED_FIELD = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
private constant abilityreallevelfield MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
private constant abilityreallevelfield CRITICAL_CHANCE_FIELD = ABILITY_RLF_CHANCE_TO_CRITICAL_STRIKE
private constant abilityreallevelfield CRITICAL_DAMAGE_FIELD = ABILITY_RLF_DAMAGE_MULTIPLIER_OCR2
private constant abilityreallevelfield EVASION_FIELD = ABILITY_RLF_CHANCE_TO_EVADE_EEV1
private constant abilityreallevelfield LIFE_STEAL_FIELD = ABILITY_RLF_LIFE_STOLEN_PER_ATTACK
endglobals
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct NewBonus
private static trigger trigger = CreateTrigger()
readonly static integer event = -1
private static trigger array array
readonly static unit array unit
readonly static integer last
readonly static integer linkType
static integer array type
static real array real
private static method checkOverflow takes real current, real amount returns real
if amount > 0 and current > 2147483647 - amount then
return 2147483647 - current
elseif amount < 0 and current < -2147483648 - amount then
return -2147483648 - current
else
return amount
endif
endmethod
private static method onEvent takes integer bonus, integer i returns nothing
if real[event] != 0 then
if event - last < RECURSION_LIMIT then
if array[bonus] != null then
call TriggerEvaluate(array[type[i]])
endif
if type[i] != bonus and array[type[i]] != null then
call TriggerEvaluate(array[type[i]])
endif
call TriggerEvaluate(trigger)
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 5, "[NewBonus] Recursion limit reached: " + I2S(RECURSION_LIMIT))
endif
endif
set event = i
endmethod
private static method setAbilityI takes unit source, integer id, abilityintegerlevelfield field, real amount, boolean adding returns real
if GetUnitAbilityLevel(source, id) == 0 then
call UnitAddAbility(source, id)
call UnitMakeAbilityPermanent(source, true, id)
endif
if adding then
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0, BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0) + R2I(amount)) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
else
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0, R2I(amount)) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
endif
set linkType = type[event]
if event > -1 then
set event = event - 1
endif
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0))
endmethod
private static method setAbilityR takes unit source, integer id, abilityreallevelfield field, real amount returns real
if GetUnitAbilityLevel(source, id) == 0 then
call UnitAddAbility(source, id)
call UnitMakeAbilityPermanent(source, true, id)
endif
if BlzSetAbilityRealLevelField(BlzGetUnitAbility(source, id), field, 0, amount) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
set linkType = type[event]
if event > -1 then
set event = event - 1
endif
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, id), field, 0)
endmethod
static method get takes unit source, integer bonus returns real
if bonus == BONUS_DAMAGE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, DAMAGE_ABILITY), DAMAGE_FIELD, 0))
elseif bonus == BONUS_ARMOR then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, ARMOR_ABILITY), ARMOR_FIELD, 0))
elseif bonus == BONUS_HEALTH then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, HEALTH_ABILITY), HEALTH_FIELD, 0))
elseif bonus == BONUS_MANA then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, MANA_ABILITY), MANA_FIELD, 0))
elseif bonus == BONUS_AGILITY then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), AGILITY_FIELD, 0))
elseif bonus == BONUS_STRENGTH then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), STRENGTH_FIELD, 0))
elseif bonus == BONUS_INTELLIGENCE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), INTELLIGENCE_FIELD, 0))
elseif bonus == BONUS_MOVEMENT_SPEED then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, MOVEMENTSPEED_ABILITY), MOVEMENTSPEED_FIELD, 0))
elseif bonus == BONUS_SIGHT_RANGE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, SIGHT_RANGE_ABILITY), SIGHT_RANGE_FIELD, 0))
elseif bonus == BONUS_HEALTH_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, HEALTHREGEN_ABILITY), HEALTHREGEN_FIELD, 0)
elseif bonus == BONUS_MANA_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, MANAREGEN_ABILITY), MANAREGEN_FIELD, 0)
elseif bonus == BONUS_ATTACK_SPEED then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ATTACKSPEED_ABILITY), ATTACKSPEED_FIELD, 0)
elseif bonus == BONUS_MAGIC_RESISTANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, MAGIC_RESISTANCE_ABILITY), MAGIC_RESISTANCE_FIELD, 0)
elseif bonus >= BONUS_EVASION_CHANCE and bonus <= last then
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp then
if bonus == BONUS_EVASION_CHANCE then
return GetUnitEvasionChance(source)
elseif bonus == BONUS_MISS_CHANCE then
return GetUnitMissChance(source)
elseif bonus == BONUS_CRITICAL_CHANCE then
return GetUnitCriticalChance(source)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return GetUnitCriticalMultiplier(source)
elseif bonus == BONUS_SPELL_POWER_FLAT then
return GetUnitSpellPowerFlat(source)
elseif bonus == BONUS_SPELL_POWER_PERCENT then
return GetUnitSpellPowerPercent(source)
elseif bonus == BONUS_LIFE_STEAL then
return GetUnitLifeSteal(source)
elseif bonus == BONUS_SPELL_VAMP then
return GetUnitSpellVamp(source)
elseif bonus == BONUS_COOLDOWN_REDUCTION then
return GetUnitCooldownReduction(source)
elseif bonus == BONUS_COOLDOWN_REDUCTION_FLAT then
return GetUnitCooldownReductionFlat(source)
elseif bonus == BONUS_COOLDOWN_OFFSET then
return GetUnitCooldownOffset(source)
endif
else
if bonus == BONUS_CRITICAL_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, CRITICAL_STRIKE_ABILITY), CRITICAL_CHANCE_FIELD, 0)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, CRITICAL_STRIKE_ABILITY), CRITICAL_DAMAGE_FIELD, 0)
elseif bonus == BONUS_EVASION_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, EVASION_ABILITY), EVASION_FIELD, 0)
elseif bonus == BONUS_LIFE_STEAL then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, LIFE_STEAL_ABILITY), LIFE_STEAL_FIELD, 0)
endif
endif
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
endif
return -1.
endmethod
static method Set takes unit source, integer bonus, real amount, boolean adding returns real
local real p
local real r
if not adding then
set event = event + 1
set unit[event] = source
set type[event] = bonus
set real[event] = amount
call onEvent(bonus, event)
if real[event] != amount then
set amount = real[event]
endif
if type[event] != bonus then
return Set(unit[event], type[event], real[event], not adding)
endif
else
set unit[event] = source
set type[event] = bonus
set real[event] = amount
endif
if bonus == BONUS_DAMAGE then
return setAbilityI(source, DAMAGE_ABILITY, DAMAGE_FIELD, amount, adding)
elseif bonus == BONUS_ARMOR then
return setAbilityI(source, ARMOR_ABILITY, ARMOR_FIELD, amount, adding)
elseif bonus == BONUS_HEALTH then
set p = GetUnitLifePercent(source)
if amount == 0 and not adding then
call BlzSetUnitMaxHP(source, R2I(BlzGetUnitMaxHP(source) - get(source, bonus)))
else
call BlzSetUnitMaxHP(source, R2I(BlzGetUnitMaxHP(source) + amount))
endif
call setAbilityI(source, HEALTH_ABILITY, HEALTH_FIELD, amount, adding)
call SetUnitLifePercentBJ(source, p)
return amount
elseif bonus == BONUS_MANA then
set p = GetUnitManaPercent(source)
if amount == 0 and not adding then
call BlzSetUnitMaxMana(source, R2I(BlzGetUnitMaxMana(source) - get(source, bonus)))
else
call BlzSetUnitMaxMana(source, R2I(BlzGetUnitMaxMana(source) + amount))
endif
call setAbilityI(source, MANA_ABILITY, MANA_FIELD, amount, adding)
call SetUnitManaPercentBJ(source, p)
return amount
elseif bonus == BONUS_AGILITY then
return setAbilityI(source, STATS_ABILITY, AGILITY_FIELD, amount, adding)
elseif bonus == BONUS_STRENGTH then
return setAbilityI(source, STATS_ABILITY, STRENGTH_FIELD, amount, adding)
elseif bonus == BONUS_INTELLIGENCE then
return setAbilityI(source, STATS_ABILITY, INTELLIGENCE_FIELD, amount, adding)
elseif bonus == BONUS_MOVEMENT_SPEED then
return setAbilityI(source, MOVEMENTSPEED_ABILITY, MOVEMENTSPEED_FIELD, amount, adding)
elseif bonus == BONUS_SIGHT_RANGE then
if amount == 0 and not adding then
call BlzSetUnitRealField(source, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(source, UNIT_RF_SIGHT_RADIUS) - get(source, bonus)))
else
call BlzSetUnitRealField(source, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(source, UNIT_RF_SIGHT_RADIUS) + amount))
endif
call setAbilityI(source, SIGHT_RANGE_ABILITY, SIGHT_RANGE_FIELD, amount, adding)
return amount
elseif bonus == BONUS_HEALTH_REGEN then
return setAbilityR(source, HEALTHREGEN_ABILITY, HEALTHREGEN_FIELD, amount)
elseif bonus == BONUS_MANA_REGEN then
return setAbilityR(source, MANAREGEN_ABILITY, MANAREGEN_FIELD, amount)
elseif bonus == BONUS_ATTACK_SPEED then
return setAbilityR(source, ATTACKSPEED_ABILITY, ATTACKSPEED_FIELD, amount)
elseif bonus == BONUS_MAGIC_RESISTANCE then
return setAbilityR(source, MAGIC_RESISTANCE_ABILITY, MAGIC_RESISTANCE_FIELD, amount)
elseif bonus >= BONUS_EVASION_CHANCE and bonus <= last then
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp then
if bonus == BONUS_EVASION_CHANCE then
call SetUnitEvasionChance(source, amount)
elseif bonus == BONUS_MISS_CHANCE then
call SetUnitMissChance(source, amount)
elseif bonus == BONUS_CRITICAL_CHANCE then
call SetUnitCriticalChance(source, amount)
elseif bonus == BONUS_CRITICAL_DAMAGE then
call SetUnitCriticalMultiplier(source, amount)
elseif bonus == BONUS_SPELL_POWER_FLAT then
call SetUnitSpellPowerFlat(source, amount)
elseif bonus == BONUS_SPELL_POWER_PERCENT then
call SetUnitSpellPowerPercent(source, amount)
elseif bonus == BONUS_LIFE_STEAL then
call SetUnitLifeSteal(source, amount)
elseif bonus == BONUS_SPELL_VAMP then
call SetUnitSpellVamp(source, amount)
elseif bonus == BONUS_COOLDOWN_REDUCTION then
if adding then
call UnitAddCooldownReduction(source, amount)
else
call SetUnitCooldownReduction(source, amount)
endif
elseif bonus == BONUS_COOLDOWN_REDUCTION_FLAT then
call SetUnitCooldownReductionFlat(source, amount)
elseif bonus == BONUS_COOLDOWN_OFFSET then
call SetUnitCooldownOffset(source, amount)
endif
set linkType = bonus
if event > -1 then
set event = event - 1
endif
return amount
else
if bonus == BONUS_CRITICAL_CHANCE then
return setAbilityR(source, CRITICAL_STRIKE_ABILITY, CRITICAL_CHANCE_FIELD, amount)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return setAbilityR(source, CRITICAL_STRIKE_ABILITY, CRITICAL_DAMAGE_FIELD, amount)
elseif bonus == BONUS_EVASION_CHANCE then
return setAbilityR(source, EVASION_ABILITY, EVASION_FIELD, amount)
elseif bonus == BONUS_LIFE_STEAL then
return setAbilityR(source, LIFE_STEAL_ABILITY, LIFE_STEAL_FIELD, amount)
endif
endif
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
endif
return -1.
endmethod
static method add takes unit source, integer bonus, real amount returns real
local real current
local real value
if bonus <= BONUS_SIGHT_RANGE then
set amount = I2R(R2I(amount))
set event = event + 1
set unit[event] = source
set type[event] = bonus
set real[event] = checkOverflow(get(source, bonus), amount)
call onEvent(bonus, event)
if type[event] <= BONUS_SIGHT_RANGE then
set real[event] = checkOverflow(get(unit[event], type[event]), real[event])
set value = real[event]
call Set(unit[event], type[event], real[event], true)
return value
else
return add(unit[event], type[event], real[event])
endif
elseif bonus >= BONUS_HEALTH_REGEN and bonus <= last then
set event = event + 1
set unit[event] = source
set type[event] = bonus
set real[event] = amount
call onEvent(bonus, event)
if type[event] >= BONUS_HEALTH_REGEN then
set value = real[event]
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp then
if type[event] == BONUS_COOLDOWN_REDUCTION then
call Set(unit[event], type[event], real[event], true)
else
call Set(unit[event], type[event], get(unit[event], type[event]) + real[event], true)
endif
else
call Set(unit[event], type[event], get(unit[event], type[event]) + real[event], true)
endif
return value
else
return add(unit[event], type[event], real[event])
endif
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
endif
return -1.
endmethod
static method register takes code c, integer bonus returns nothing
if bonus >= BONUS_DAMAGE and bonus <= last then
if array[bonus] == null then
set array[bonus] = CreateTrigger()
endif
call TriggerAddCondition(array[bonus], Filter(c))
else
call TriggerAddCondition(trigger, Filter(c))
endif
endmethod
private static method onInit takes nothing returns nothing
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp then
set last = BONUS_COOLDOWN_OFFSET
else
set last = BONUS_LIFE_STEAL
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function GetUnitBonus takes unit source, integer bonus returns real
return NewBonus.get(source, bonus)
endfunction
function SetUnitBonus takes unit source, integer bonus, real amount returns real
return NewBonus.Set(source, bonus, amount, false)
endfunction
function RemoveUnitBonus takes unit source, integer bonus returns nothing
if bonus == BONUS_CRITICAL_DAMAGE then
call NewBonus.Set(source, bonus, 1, false)
else
call NewBonus.Set(source, bonus, 0, false)
endif
if bonus == BONUS_LIFE_STEAL then
call UnitRemoveAbility(source, LIFE_STEAL_ABILITY)
endif
endfunction
function AddUnitBonus takes unit source, integer bonus, real amount returns real
return NewBonus.add(source, bonus, amount)
endfunction
function RegisterBonusEvent takes code c returns nothing
call NewBonus.register(c, 0)
endfunction
function RegisterBonusTypeEvent takes integer bonus, code c returns nothing
call NewBonus.register(c, bonus)
endfunction
function GetBonusUnit takes nothing returns unit
return NewBonus.unit[NewBonus.event]
endfunction
function GetBonusType takes nothing returns integer
return NewBonus.type[NewBonus.event]
endfunction
function SetBonusType takes integer bonus returns nothing
if bonus >= BONUS_DAMAGE and bonus <= NewBonus.last then
set NewBonus.type[NewBonus.event] = bonus
endif
endfunction
function GetBonusAmount takes nothing returns real
return NewBonus.real[NewBonus.event]
endfunction
function SetBonusAmount takes real amount returns nothing
set NewBonus.real[NewBonus.event] = amount
endfunction
endlibrary
library NewBonusUtils requires NewBonus, RegisterPlayerUnitEvent
/* ----------------------- NewBonusUtils v2.3 by Chopinski ----------------------- */
//! novjass
Required Library: RegisterPlayerUnitEvent -> www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
API:
function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
-> Add the specified amount for the specified bonus type for unit for a duration
-> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)
function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
-> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
-> the ability represented by the parameter buffId the bonus is not removed.
-> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
-> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
-> Note that it will work for items with the same id, because it takes as parameter the item object.
-> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())
function UnitCopyBonuses takes unit source, unit target returns nothing
-> Copy the source unit bonuses using the Add functionality to the target unit
-> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())
function UnitMirrorBonuses takes unit source, unit target returns nothing
-> Copy the source unit bonuses using the Set functionality to the target unit
-> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
//! endnovjass
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct NewBonusUtils extends NewBonus
static constant real period = 0.03125000
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
static integer k = -1
static thistype array items
unit source
item item
real duration
integer bonus_t
integer buff
real amount
boolean link
method remove takes integer i, boolean isItem returns integer
static if NewBonus_EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp then
if bonus_t == BONUS_COOLDOWN_REDUCTION then
call UnitRemoveCooldownReduction(source, amount)
else
call AddUnitBonus(source, bonus_t, -amount)
endif
else
call AddUnitBonus(source, bonus_t, -amount)
endif
if isItem then
set items[i] = items[k]
set k = k - 1
else
set array[i] = array[key]
set key = key - 1
if key == -1 then
call PauseTimer(timer)
endif
endif
set source = null
set item = null
call deallocate()
return i - 1
endmethod
static method onDrop takes nothing returns nothing
local item itm = GetManipulatedItem()
local integer i = 0
local thistype this
loop
exitwhen i > k
set this = items[i]
if item == itm then
set i = remove(i, true)
endif
set i = i + 1
endloop
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if link then
if duration <= 0 then
set i = remove(i, false)
endif
set duration = duration - period
else
if GetUnitAbilityLevel(source, buff) == 0 then
set i = remove(i, false)
endif
endif
set i = i + 1
endloop
endmethod
static method linkTimed takes unit source, integer bonus, real amount, real duration, boolean link returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.duration = duration
set this.link = link
set this.amount = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set key = key + 1
set array[key] = this
if key == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endmethod
static method linkBuff takes unit source, integer bonus, real amount, integer id, boolean link returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.buff = id
set this.link = link
set this.amount = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set key = key + 1
set array[key] = this
if key == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endmethod
static method linkItem takes unit source, integer bonus, real amount, item i returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.item = i
set this.amount = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set k = k + 1
set items[k] = this
endmethod
static method copy takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > last
if GetUnitBonus(source, i) != 0 then
call AddUnitBonus(target, i, GetUnitBonus(source, i))
endif
set i = i + 1
endloop
endmethod
static method mirror takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > last
call SetUnitBonus(target, i, GetUnitBonus(source, i))
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function AddUnitBonusTimed takes unit source, integer bonus, real amount, real duration returns nothing
call NewBonusUtils.linkTimed(source, bonus, amount, duration, true)
endfunction
function LinkBonusToBuff takes unit source, integer bonus, real amount, integer id returns nothing
call NewBonusUtils.linkBuff(source, bonus, amount, id, false)
endfunction
function LinkBonusToItem takes unit source, integer bonus, real amount, item i returns nothing
call NewBonusUtils.linkItem(source, bonus, amount, i)
endfunction
function UnitCopyBonuses takes unit source, unit target returns nothing
call NewBonusUtils.copy(source, target)
endfunction
function UnitMirrorBonuses takes unit source, unit target returns nothing
call NewBonusUtils.mirror(source, target)
endfunction
endlibrary
library CooldownReduction requires RegisterPlayerUnitEvent, Table, Alloc, Indexer
/* ------------------ Cooldown Reduction v1.9 by Chopinski ------------------ */
// Intro
// This library intension in to introduce to warcraft an easy way to
// manipulate abilities cooldowns based on a cooldown reduction value that
// is unique for each unit.
// How it Works?
// When casting an ability, its "new" cooldown is calculated based on the
// amount of cooldown reduction of the casting unit. the formula for
// calculation is:
// Cooldown = (Default Cooldown - Cooldown Offset) * [(1 - source1)*(1 - source2)*...] * (1 - Cooldown Reduction Flat)
// The system also allow negative values for CDR, resulting in increased
// ability cooldown.
// It does not acumulate because the abilities are registered automatically
// on the first cast, saving its base cooldown (Object Editor values) and
// always using this base value for calculation, so you can still edit
// the ability via the editor and the system takes care of the rest.
// How to Import
// simply copy the CooldownReduction folder over to your map, and start
// use the API functions
// Requirements
// CooldownReduction requires RegisterPlayerUnitEvent, Alloc and a Unit Indexer.
// Credits to Magtheridon96 for RegisterPlayerUnitEvent and to Bribe for
// the UnitIndexer. It also requires patch 1.31+.
// RegisterPlayerUnitEvent: www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
// UnitIndexer: www.hiveworkshop.com/threads/gui-unit-indexer-1-4-0-0.197329/#resource-45899
// Alloc: www.hiveworkshop.com/threads/snippet-alloc.192348/
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
// Use this function to filter out units you dont want to have abilities registered.
// By default dummy units do not trigger the system.
private function UnitFilter takes unit source returns boolean
return GetUnitAbilityLevel(source, 'Aloc') == 0
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module List
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method push takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct AbilityList extends array
implement Alloc
implement List
unit unit
ability ability
Table defaults
integer id
integer levels
method destroy takes nothing returns nothing
local thistype node = this.next
loop
exitwhen node == this
set node.ability = null
call node.defaults.destroy()
call node.pop()
call node.deallocate()
set node = node.next
endloop
call deallocate()
set unit = null
endmethod
method insert takes integer id returns thistype
local thistype node = push(allocate())
local integer i = 0
set node.id = id
set node.ability = BlzGetUnitAbility(unit, id)
set node.levels = BlzGetAbilityIntegerField(node.ability, ABILITY_IF_LEVELS)
set node.defaults = Table.create()
loop
exitwhen i >= node.levels
set node.defaults.real[i] = BlzGetAbilityRealLevelField(node.ability, ABILITY_RLF_COOLDOWN, i)
set i = i + 1
endloop
return node
endmethod
method update takes integer count, real normal, real flat, real offset returns nothing
local thistype node = this.next
local real cooldown
local integer i
loop
exitwhen node == this
set i = 0
loop
exitwhen i >= node.levels
if count > 0 then
set cooldown = ((node.defaults.real[i] - offset) * normal * (1 - flat))
else
set cooldown = ((node.defaults.real[i] - offset) * (1 - flat))
endif
call BlzSetAbilityRealLevelField(node.ability, ABILITY_RLF_COOLDOWN, i, cooldown)
call IncUnitAbilityLevel(unit, node.id)
call DecUnitAbilityLevel(unit, node.id)
set i = i + 1
endloop
set node = node.next
endloop
endmethod
method calculate takes integer id, integer level, real cooldown, integer count, real normal, real flat, real offset returns nothing
if count > 0 then
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(unit, id), ABILITY_RLF_COOLDOWN, level, ((cooldown - offset) * normal * (1 - flat)))
else
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(unit, id), ABILITY_RLF_COOLDOWN, level, ((cooldown - offset) * (1 - flat)))
endif
call IncUnitAbilityLevel(unit, id)
call DecUnitAbilityLevel(unit, id)
endmethod
method simulate takes real cooldown, integer count, real normal, real flat, real offset returns real
local real cd
if count > 0 then
set cd = ((cooldown - offset) * normal * (1 - flat))
else
set cd = ((cooldown - offset) * (1 - flat))
endif
return cd
endmethod
static method create takes unit source returns thistype
local thistype this = thistype(allocate()).init()
set unit = source
return this
endmethod
endstruct
struct CDR
readonly static hashtable hashtable = InitHashtable()
private static AbilityList array n
private static integer array count
readonly static real array normal
readonly static real array flat
readonly static real array offset
private static method getInstance takes unit source returns AbilityList
local integer i = GetUnitUserData(source)
if n[i] == 0 then
set n[i] = AbilityList.create(source)
endif
return n[i]
endmethod
private static method update takes unit u returns nothing
local integer id = GetUnitUserData(u)
local AbilityList list = getInstance(u)
call list.update(count[id], normal[id], flat[id], offset[id])
endmethod
private static method calculate takes unit u returns real
local integer idx = GetUnitUserData(u)
local integer id = GetHandleId(u)
local integer i = 0
local real cdr = 0
local real aux
loop
exitwhen i > count[idx]
set aux = LoadReal(hashtable, id, i)
if i > 0 then
set cdr = cdr * (1 - aux)
else
set cdr = 1 - aux
endif
set i = i + 1
endloop
return cdr
endmethod
static method get takes unit u, integer types returns real
if types == 0 then
return normal[GetUnitUserData(u)]
elseif types == 1 then
return flat[GetUnitUserData(u)]
else
return offset[GetUnitUserData(u)]
endif
endmethod
static method Set takes unit u, real value, integer types returns nothing
if types == 0 then
set normal[GetUnitUserData(u)] = value
elseif types == 1 then
set flat[GetUnitUserData(u)] = value
else
set offset[GetUnitUserData(u)] = value
endif
call update(u)
endmethod
static method add takes unit u, real amount returns nothing
local integer i = GetUnitUserData(u)
if amount != 0 then
call SaveReal(hashtable, GetHandleId(u), count[i], amount)
set normal[i] = calculate(u)
set count[i] = count[i] + 1
call update(u)
endif
endmethod
static method remove takes unit u, real amount returns nothing
local integer idx = GetUnitUserData(u)
local integer id = GetHandleId(u)
local integer i = 0
local real aux
if amount == 0 then
return
endif
loop
exitwhen i > count[idx] - 1
set aux = LoadReal(hashtable, id, i)
if aux == amount then
call RemoveSavedReal(hashtable, id, i)
if i != count[idx] - 1 then
set aux = LoadReal(hashtable, id, count[idx] - 1)
call SaveReal(hashtable, id, i, aux)
call RemoveSavedReal(hashtable, id, count[idx] - 1)
endif
set count[idx] = count[idx] - 1
set normal[idx] = calculate(u)
set i = count[idx] + 1
call update(u)
else
set i = i + 1
endif
endloop
endmethod
static method calculateCooldown takes unit u, integer id, integer level, real cooldown returns nothing
local integer i = GetUnitUserData(u)
local AbilityList list = getInstance(u)
call list.calculate(id, level - 1, cooldown, count[i], normal[i], flat[i], offset[i])
endmethod
static method simulateCooldown takes unit u, real cooldown returns real
local integer i = GetUnitUserData(u)
local AbilityList list = getInstance(u)
return list.simulate(cooldown, count[i], normal[i], flat[i], offset[i])
endmethod
static method register takes unit u, integer id returns nothing
local AbilityList list
local integer i
if UnitFilter(u) then
set list = getInstance(u)
set i = GetUnitUserData(u)
if not LoadBoolean(hashtable, list, id) then
call list.insert(id)
call SaveBoolean(hashtable, list, id, true)
if count[i] > 0 or normal[i] != 0 or flat[i] != 0 or offset[i] != 0 then
call update(u)
endif
endif
endif
endmethod
private static method onCast takes nothing returns nothing
call register(GetTriggerUnit(), GetSpellAbilityId())
endmethod
private static method onLevel takes nothing returns nothing
call register(GetTriggerUnit(), GetLearnedSkill())
endmethod
private static method onDeindex takes nothing returns nothing
local unit source = GetIndexUnit()
local integer i = GetUnitUserData(source)
local AbilityList list = getInstance(source)
set n[i] = 0
set normal[i] = 0
set flat[i] = 0
set offset[i] = 0
set count[i] = 0
if list != 0 then
call list.destroy()
call FlushChildHashtable(hashtable, list)
endif
call FlushChildHashtable(hashtable, GetHandleId(source))
endmethod
private static method onInit takes nothing returns nothing
call RegisterUnitDeindexEvent(function thistype.onDeindex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLevel)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function GetUnitCooldownReduction takes unit u returns real
return 1 - CDR.get(u, 0)
endfunction
function GetUnitCooldownReductionFlat takes unit u returns real
return CDR.get(u, 1)
endfunction
function GetUnitCooldownOffset takes unit u returns real
return CDR.get(u, 2)
endfunction
function SetUnitCooldownReduction takes unit u, real value returns nothing
call CDR.Set(u, value, 0)
endfunction
function SetUnitCooldownReductionFlat takes unit u, real value returns nothing
call CDR.Set(u, value, 1)
endfunction
function SetUnitCooldownOffset takes unit u, real value returns nothing
call CDR.Set(u, value, 2)
endfunction
function UnitAddCooldownReduction takes unit u, real value returns nothing
call CDR.add(u, value)
endfunction
function UnitAddCooldownReductionFlat takes unit u, real value returns nothing
call CDR.Set(u, CDR.get(u, 1) + value, 1)
endfunction
function UnitAddCooldownOffset takes unit u, real value returns nothing
call CDR.Set(u, CDR.get(u, 2) + value, 2)
endfunction
function UnitRemoveCooldownReduction takes unit u, real value returns nothing
call CDR.remove(u, value)
endfunction
function CalculateAbilityCooldown takes unit u, integer id, integer level, real cooldown returns nothing
call CDR.calculateCooldown(u, id, level, cooldown)
endfunction
function SimulateAbilityCooldown takes unit u, real cooldown returns real
return CDR.simulateCooldown(u, cooldown)
endfunction
function RegisterAbility takes unit u, integer id returns nothing
call CDR.register(u, id)
endfunction
endlibrary
library CooldownReductionUtils requires CooldownReduction
/* --------------- Cooldown Reduction Utils v1.9 by Chopinski --------------- */
// Intro
// Utility Library that include a few extra functions to deal with
// Cooldown Reduction
// JASS API
// function UnitAddCooldownReductionTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr of a unit for a given duration. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function UnitAddCooldownReductionFlatTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr flat of a unit for a given period. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function UnitAddCooldownOffsetTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr offset of a unit for a given period. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function GetUnitCooldownReductionEx takes unit u returns string
// -> Returns the amount of cdr a unit has as a string factored by 100
// -> example of return: 10.50 -> 0.105 internally.
// function GetUnitCooldownReductionFlatEx takes unit u returns string
// -> Returns the amount of cdr flat a unit has as a string factored by 100
// -> example of return: 10.50 -> 0.105 internally.
// function GetUnitCooldownOffsetEx takes unit u returns string
// -> Returns the amount of cdr offset a unit has as a string
// function GetAbilityTable takes nothing returns hashtable
// -> Returns the hashtable that holds the units default cooldown reduction values.
// -> Use with caution! you might break stuff
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct CDRUtils extends CDR
static timer t = CreateTimer()
//----------------------------------------------
static integer didx = -1
static thistype array data
//----------------------------------------------
unit u
real ticks
real amount
integer tipo
method destroy takes nothing returns nothing
if didx == -1 then
call PauseTimer(t)
endif
set .u = null
set .ticks = 0
call .deallocate()
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
set .ticks = .ticks - 1
if .ticks <= 0 then
if .tipo == 0 then
call remove(.u, .amount)
elseif .tipo == 1 then
call Set(.u, get(.u, 1) - .amount, 1)
else
call Set(.u, get(.u, 2) - .amount, 2)
endif
set data[i] = data[didx]
set didx = didx - 1
set i = i - 1
call .destroy()
endif
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration, integer tipo returns nothing
local thistype this = thistype.allocate()
set .u = u
set .amount = amount
set .tipo = tipo
set .ticks = duration/0.03125000
set didx = didx + 1
set data[didx] = this
if tipo == 0 then
call add(u, amount)
elseif tipo == 1 then
call Set(u, get(u, 1) + amount, 1)
else
call Set(u, get(u, 2) + amount, 2)
endif
if didx == 0 then
call TimerStart(t, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function UnitAddCooldownReductionTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 0)
endfunction
function UnitAddCooldownReductionFlatTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 1)
endfunction
function UnitAddCooldownOffsetTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 2)
endfunction
function GetUnitCooldownReductionEx takes unit u returns string
return R2SW(CDRUtils.get(u, 0)*100, 1, 2)
endfunction
function GetUnitCooldownReductionFlatEx takes unit u returns string
return R2SW(CDRUtils.get(u, 1)*100, 1, 2)
endfunction
function GetUnitCooldownOffsetEx takes unit u returns string
return R2SW(CDRUtils.get(u, 2), 1, 2)
endfunction
function GetAbilityTable takes nothing returns hashtable
return CDR.hashtable
endfunction
endlibrary
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Alloc ~~ By Sevion ~~ Version 1.09 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Alloc?
// - Alloc implements an intuitive allocation method for array structs
//
// =Pros=
// - Efficient.
// - Simple.
// - Less overhead than regular structs.
//
// =Cons=
// - Must use array structs (hardly a con).
// - Must manually call OnDestroy.
// - Must use Delegates for inheritance.
// - No default values for variables (use onInit instead).
// - No array members (use another Alloc struct as a linked list or type declaration).
//
// Methods:
// - struct.allocate()
// - struct.deallocate()
//
// These methods are used just as they should be used in regular structs.
//
// Modules:
// - Alloc
// Implements the most basic form of Alloc. Includes only create and destroy
// methods.
//
// Details:
// - Less overhead than regular structs
//
// - Use array structs when using Alloc. Put the implement at the top of the struct.
//
// - Alloc operates almost exactly the same as default structs in debug mode with the exception of onDestroy.
//
// How to import:
// - Create a trigger named Alloc.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Nestharus for the method of allocation and suggestions on further merging.
// - Bribe for suggestions like the static if and method names.
// - PurgeandFire111 for some suggestions like the merging of Alloc and AllocX as well as OnDestroy stuff.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Alloc
module Alloc
private static integer instanceCount = 0
private thistype recycle
static method allocate takes nothing returns thistype
local thistype this
if (thistype(0).recycle == 0) then
debug if (instanceCount == JASS_MAX_ARRAY_SIZE) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to allocate too many instances!")
debug return 0
debug endif
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = thistype(0).recycle
set thistype(0).recycle = thistype(0).recycle.recycle
endif
debug set this.recycle = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug if (this.recycle != -1) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to deallocate an invalid instance at [" + I2S(this) + "]!")
debug return
debug endif
set this.recycle = thistype(0).recycle
set thistype(0).recycle = this
endmethod
endmodule
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library Utilities requires TimerUtils, Missiles
/* ------------------------ Utilities functions v1.6 ------------------------ */
// How to Import:
// 1 - Copy this library into your map
// 2 - Copy the Stun, Silence and Slow abilities and match them below and the Slow Buff
// 3 - Copy the TimerUtils and Missiles libraries into your map and follow their import instructions
/* ------------------------------ By Chopinski ------------------------------ */
globals
// The raw code of the ability used to silence an unit
public constant integer SILENCE = 'U000'
// The raw code of the ability used to stun an unit
public constant integer STUN = 'U001'
// The raw code of the ability used to slow an unit
public constant integer SLOW = 'U003'
// The dummy caster unit id
public constant integer DUMMY = 'dumi'
// Update period
private constant real PERIOD = 0.031250000
// location z
private location LOCZ = Location(0,0)
// One hashtable to rule them all
private hashtable table = InitHashtable()
// Closest Unit
private unit bj_closestUnitGroup
endglobals
// Only one declaration per map required
native UnitAlive takes unit id returns boolean
// Returns the terrain Z value (Desync safe)
function GetLocZ takes real x, real y returns real
call MoveLocation(LOCZ, x, y)
return GetLocationZ(LOCZ)
endfunction
// Similar to GetUnitX and GetUnitY but for Z axis
function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
// Similar to SetUnitX and SetUnitY but for Z axis
function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
// Anlge between 2D points
function AngleBetweenCoordinates takes real x, real y, real x2, real y2 returns real
return Atan2(y2 - y, x2 - x)
endfunction
// Similar to AddSpecialEffect but scales the effect and considers z and return it
function AddSpecialEffectEx takes string model, real x, real y, real z, real scale returns effect
set bj_lastCreatedEffect = AddSpecialEffect(model, x, y)
if z != 0 then
call BlzSetSpecialEffectZ(bj_lastCreatedEffect, z + GetLocZ(x, y))
endif
call BlzSetSpecialEffectScale(bj_lastCreatedEffect, scale)
return bj_lastCreatedEffect
endfunction
// Returns a group of enemy units of the specified player within the specified AOE of x and y
function GetEnemyUnitsInRange takes player enemyOf, real x, real y, real aoe, boolean structures, boolean magicImmune returns group
local group g = CreateGroup()
local group h = CreateGroup()
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
if structures and magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if IsUnitEnemy(w, enemyOf) and UnitAlive(w) then
call GroupAddUnit(g, w)
endif
call GroupRemoveUnit(h, w)
endloop
elseif structures and not magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) then
call GroupAddUnit(g, w)
endif
call GroupRemoveUnit(h, w)
endloop
elseif magicImmune and not structures then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) then
call GroupAddUnit(g, w)
endif
call GroupRemoveUnit(h, w)
endloop
else
loop
set w = FirstOfGroup(h)
exitwhen w == null
if IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) then
call GroupAddUnit(g, w)
endif
call GroupRemoveUnit(h, w)
endloop
endif
call DestroyGroup(h)
set h = null
return g
endfunction
// Returns the closest unit in a unit group with center at x and y
function GetClosestUnitGroup takes real x, real y, group g returns unit
local unit u
local real dx
local real dy
local real md = 100000
local integer i = 0
local integer size = BlzGroupGetSize(g)
set bj_closestUnitGroup = null
loop
exitwhen i == size
set u = BlzGroupUnitAt(g, i)
if UnitAlive(u) then
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
if (dx*dx + dy*dy)/100000 < md then
set bj_closestUnitGroup = u
set md = (dx*dx + dy*dy)/100000
endif
endif
set i = i + 1
endloop
return bj_closestUnitGroup
endfunction
/* -------------------------------------------------------------------------- */
/* Reset Ability Cooldown */
/* -------------------------------------------------------------------------- */
private struct ResetCooldown
timer timer
unit unit
integer ability
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call BlzEndUnitAbilityCooldown(unit, ability)
call ReleaseTimer(timer)
call deallocate()
set unit = null
set timer = null
endmethod
static method reset takes unit u, integer id returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = u
set ability = id
call TimerStart(timer, 0.01, false, function thistype.onExpire)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Knockback */
/* -------------------------------------------------------------------------- */
private struct Knockback extends Missiles
private static integer array knocked
boolean cliff
boolean destructable
boolean unit
boolean isPaused
integer key
effect attachment
static method isUnitKnocked takes unit u returns boolean
return knocked[GetUnitUserData(u)] > 0
endmethod
/*method onPeriod takes nothing returns boolean
if UnitAlive(source) then
call SetUnitX(source, prevX)
call SetUnitY(source, prevY)
return false
else
return true
endif
endmethod
method onHit takes unit u returns boolean
if unit then
if UnitAlive(u) then
return true
else
return false
endif
else
return false
endif
endmethod
method onDestructable takes destructable d returns boolean
if destructable then
if GetDestructableLife(d) > 0 then
return true
else
return false
endif
else
return false
endif
endmethod
method onCliff takes nothing returns boolean
return cliff
endmethod
method onPause takes nothing returns boolean
call pause(false)
return false
endmethod
method onRemove takes nothing returns nothing
call DestroyEffect(attachment)
set knocked[key] = knocked[key] - 1
if isPaused and knocked[key] == 0 then
call BlzPauseUnitEx(source, false)
endif
set attachment = null
endmethod
static method start takes unit whichUnit, real angle, real distance, real duration, string model, string point, boolean onCliff, boolean onDestructable, boolean onUnit, boolean isPaused returns nothing
local real x = GetUnitX(whichUnit)
local real y = GetUnitY(whichUnit)
local thistype this = thistype.create(x, y, 0, x + distance*Cos(angle), y + distance*Sin(angle), 0)
set .source = whichUnit
set .duration = duration
set .collision = 2*BlzGetUnitCollisionSize(whichUnit)
set .cliff = onCliff
set .destructable = onDestructable
set .unit = onUnit
set .isPaused = isPaused
set .key = GetUnitUserData(whichUnit)
set knocked[key] = knocked[key] + 1
if model != null and point != null then
set .attachment = AddSpecialEffectTarget(model, whichUnit, point)
endif
if isPaused and knocked[key] == 1 then
call BlzPauseUnitEx(whichUnit, true)
endif
call launch()
endmethod*/
endstruct
/* -------------------------------------------------------------------------- */
/* Timed Ability */
/* -------------------------------------------------------------------------- */
private struct TimedAbility
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
unit unit
integer ability
real duration
method remove takes integer i returns integer
call UnitRemoveAbility(unit, ability)
call RemoveSavedInteger(table, GetHandleId(unit), ability)
set array[i] = array[key]
set key = key - 1
set unit = null
if key == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if duration <= 0 then
set i = remove(i)
endif
set duration = duration - 0.1
set i = i + 1
endloop
endmethod
static method add takes unit u, integer id, real duration, integer level, boolean hide returns nothing
local thistype this = LoadInteger(table, GetHandleId(u), id)
if this == 0 then
set this = thistype.allocate()
set unit = u
set ability = id
set key = key + 1
set array[key] = this
call SaveInteger(table, GetHandleId(unit), ability, this)
if key == 0 then
call TimerStart(timer, 0.1, true, function thistype.onPeriod)
endif
endif
if GetUnitAbilityLevel(unit, ability) != level then
call UnitAddAbility(unit, ability)
call SetUnitAbilityLevel(unit, ability, level)
call UnitMakeAbilityPermanent(unit, true, ability)
call BlzUnitHideAbility(unit, ability, hide)
endif
set .duration = duration
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Fear System */
/* -------------------------------------------------------------------------- */
private struct Fear
static constant real PERIOD = 1./5.
static constant integer DIRECTION_CHANGE = 5
static constant real MAX_CHANGE = 200.
static integer key = -1
static thistype array array
static integer array struct
static boolean array flag
static real array x
static real array y
static timer timer = CreateTimer()
unit unit
effect effect
integer id
real duration
integer change
boolean selected
static method feared takes unit target returns boolean
return struct[GetUnitUserData(target)] != 0
endmethod
method remove takes integer i returns integer
set flag[id] = true
call IssueImmediateOrder(unit, "stop")
call DestroyEffect(effect)
call UnitRemoveAbility(unit, 'Abun')
if selected then
call SelectUnitAddForPlayer(unit, GetOwningPlayer(unit))
endif
set struct[id] = 0
set unit = null
set effect = null
set array[i] = array[key]
set key = key - 1
call deallocate()
if key == -1 then
call PauseTimer(timer)
endif
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if duration > 0 and UnitAlive(unit) then
set duration = duration - PERIOD
set change = change + 1
if change >= DIRECTION_CHANGE then
set change = 0
set flag[id] = true
set x[id] = GetRandomReal(GetUnitX(unit) - MAX_CHANGE, GetUnitX(unit) + MAX_CHANGE)
set y[id] = GetRandomReal(GetUnitY(unit) - MAX_CHANGE, GetUnitY(unit) + MAX_CHANGE)
call IssuePointOrder(unit, "move", x[id], y[id])
endif
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
static method apply takes unit target, real duration, string fxpath, string attachment returns nothing
local integer id = GetUnitUserData(target)
local thistype this
if struct[id] != 0 then
set this = struct[id]
else
set this = thistype.allocate()
set .id = id
set unit = target
set change = 0
set selected = IsUnitSelected(target, GetOwningPlayer(target))
set key = key + 1
set array[key] = this
set struct[id] = this
call UnitAddAbility(target, 'Abun')
if selected then
call SelectUnit(target, false)
endif
if fxpath != "" and attachment != "" then
set effect = AddSpecialEffectTarget(fxpath, target, attachment)
endif
if key == 0 then
call TimerStart(timer, PERIOD, true, function thistype.onPeriod)
endif
endif
set .duration = duration
set flag[id] = true
set x[id] = GetRandomReal(GetUnitX(target) - MAX_CHANGE, GetUnitX(target) + MAX_CHANGE)
set y[id] = GetRandomReal(GetUnitY(target) - MAX_CHANGE, GetUnitY(target) + MAX_CHANGE)
call IssuePointOrder(target, "move", x[id], y[id])
endmethod
private static method onOrder takes nothing returns nothing
local unit source = GetOrderedUnit()
local integer id
if feared(source) then
set id = GetUnitUserData(source)
if not flag[id] then
set flag[id] = true
call IssuePointOrder(source, "move", x[id], y[id])
else
set flag[id] = false
endif
endif
set source = null
endmethod
private static method onSelect takes nothing returns nothing
local unit source = GetTriggerUnit()
if feared(source) then
if IsUnitSelected(source, GetOwningPlayer(source)) then
call SelectUnit(source, false)
endif
endif
set source = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function thistype.onSelect)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Effect Spam */
/* -------------------------------------------------------------------------- */
struct EffectSpam
timer timer
unit unit
integer i
string effect
string point
real scale
real x
real y
real z
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if i > 0 then
if unit == null then
call DestroyEffect(AddSpecialEffectEx(effect, x, y, z, scale))
else
call DestroyEffect(AddSpecialEffectTarget(effect, unit, point))
endif
else
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endif
set i = i - 1
endmethod
static method spam takes unit target, string model, string attach, real x, real y, real z, real scale, real interval, integer count returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = target
set i = count
set effect = model
set .x = x
set .y = y
set .z = z
set .scale = scale
set point = attach
call TimerStart(timer, interval, true, function thistype.onPeriod)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Chain Lightning */
/* -------------------------------------------------------------------------- */
struct ChainLightning
timer timer
unit unit
unit prev
unit self
unit next
group group
group damaged
player player
real damage
real range
real duration
integer bounces
attacktype attacktype
damagetype damagetype
string lightning
string effect
string attach
boolean rebounce
private method destroy takes nothing returns nothing
call DestroyGroup(group)
call ReleaseTimer(timer)
call DestroyGroup(damaged)
set prev = null
set self = null
set next = null
set unit = null
set group = null
set timer = null
set player = null
set damaged = null
set attacktype = null
set damagetype = null
call deallocate()
endmethod
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call DestroyGroup(group)
if bounces > 0 then
set group = GetEnemyUnitsInRange(player, GetUnitX(self), GetUnitY(self), range, false, false)
call GroupRemoveUnit(group, self)
if not rebounce then
call BlzGroupRemoveGroupFast(damaged, group)
endif
if BlzGroupGetSize(group) == 0 then
call destroy()
else
set next = GetClosestUnitGroup(GetUnitX(self), GetUnitY(self), group)
if next == prev and BlzGroupGetSize(group) > 1 then
call GroupRemoveUnit(group, prev)
set next = GetClosestUnitGroup(GetUnitX(self), GetUnitY(self), group)
endif
if next != null then
call DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(self), GetUnitY(self), GetUnitZ(self) + 60.0, GetUnitX(next), GetUnitY(next), GetUnitZ(next) + 60.0), duration)
call DestroyEffect(AddSpecialEffectTarget(effect, next, attach))
call GroupAddUnit(damaged, next)
call UnitDamageTarget(unit, next, damage, false, false, attacktype, damagetype, null)
call DestroyGroup(group)
set prev = self
set self = next
set next = null
else
call destroy()
endif
endif
else
call destroy()
endif
set bounces = bounces - 1
endmethod
static method create takes unit source, unit target, real dmg, real aoe, real dur, real interval, integer bounceCount, attacktype attackType, damagetype damageType, string lightningType, string sfx, string attachPoint, boolean canRebounce returns thistype
local group g
local thistype this
set g = GetEnemyUnitsInRange(GetOwningPlayer(source), GetUnitX(target), GetUnitY(target), aoe, false, false)
if BlzGroupGetSize(g) == 1 then
call DestroyLightningTimed(AddLightningEx(lightningType, true, GetUnitX(source), GetUnitY(source), BlzGetUnitZ(source) + 60.0, GetUnitX(target), GetUnitY(target), BlzGetUnitZ(target) + 60.0), dur)
call DestroyEffect(AddSpecialEffectTarget(sfx, target, attachPoint))
call UnitDamageTarget(source, target, dmg, false, false, attackType, damageType, null)
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set prev = null
set self = target
set next = null
set unit = source
set player = GetOwningPlayer(source)
set damage = dmg
set range = aoe
set duration = dur
set bounces = bounceCount
set attacktype = attackType
set damagetype = damageType
set lightning = lightningType
set effect = sfx
set attach = attachPoint
set rebounce = canRebounce
set damaged = CreateGroup()
call GroupRemoveUnit(g, target)
call GroupAddUnit(damaged, target)
call DestroyEffect(AddSpecialEffectTarget(sfx, target, attachPoint))
call UnitDamageTarget(source, target, damage, false, false, attacktype, damagetype, null)
call TimerStart(timer, interval, true, function thistype.onPeriod)
endif
call DestroyGroup(g)
set g = null
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Knockup */
/* -------------------------------------------------------------------------- */
struct Knockup
timer timer
unit unit
real rate
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call SetUnitFlyHeight(unit, GetUnitDefaultFlyHeight(unit), rate)
call BlzPauseUnitEx(unit, false)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method create takes unit whichUnit, real airTime, real maxHeight returns thistype
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = whichUnit
set rate = maxHeight/airTime
call UnitAddAbility(whichUnit, 'Amrf')
call UnitRemoveAbility(whichUnit, 'Amrf')
call BlzPauseUnitEx(whichUnit, true)
call SetUnitFlyHeight(whichUnit, (GetUnitDefaultFlyHeight(whichUnit) + maxHeight), rate)
call TimerStart(timer, airTime/2, false, function thistype.onPeriod)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Dummy Pool */
/* -------------------------------------------------------------------------- */
struct DummyPool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call ShowUnit(dummy, false)
call BlzPauseUnitEx(dummy, true)
endif
endmethod
static method retrieve takes player owner, real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call BlzPauseUnitEx(bj_lastCreatedUnit, false)
call ShowUnit(bj_lastCreatedUnit, true)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face*bj_RADTODEG)
call SetUnitOwner(bj_lastCreatedUnit, owner, false)
else
set bj_lastCreatedUnit = CreateUnit(owner, DUMMY, x, y, face*bj_RADTODEG)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 20
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call BlzPauseUnitEx(u, false)
call GroupAddUnit(group, u)
set i = i + 1
endloop
set u = null
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Effect Link */
/* -------------------------------------------------------------------------- */
struct EffectLink
static timer timer = CreateTimer()
//Dynamic Indexing for buff and timed
static integer didx = -1
static thistype array data
//Dynamic Indexing for items
static integer ditem = -1
static thistype array items
unit unit
effect effect
item item
integer buff
method remove takes integer i, boolean isItem returns integer
call DestroyEffect(effect)
if isItem then
set items[i] = items[ditem]
set ditem = ditem - 1
else
set data[i] = data[didx]
set didx = didx - 1
if didx == -1 then
call PauseTimer(timer)
endif
endif
set unit = null
set item = null
set effect = null
call deallocate()
return i - 1
endmethod
static method onDrop takes nothing returns nothing
local item j = GetManipulatedItem()
local integer i = 0
local thistype this
loop
exitwhen i > ditem
set this = items[i]
if item == j then
set i = remove(i, true)
endif
set i = i + 1
endloop
set j = null
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if GetUnitAbilityLevel(unit, buff) == 0 then
set i = remove(i, false)
endif
set i = i + 1
endloop
endmethod
static method BuffLink takes unit target, integer id, string model, string attach returns nothing
local thistype this = thistype.allocate()
set unit = target
set buff = id
set effect = AddSpecialEffectTarget(model, target, attach)
set didx = didx + 1
set data[didx] = this
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
static method ItemLink takes unit target, item i, string model, string attach returns nothing
local thistype this = thistype.allocate()
set item = i
set effect = AddSpecialEffectTarget(model, target, attach)
set ditem = ditem + 1
set items[ditem] = this
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Disarm */
/* -------------------------------------------------------------------------- */
struct Disarm
static constant integer ability = 'Abun'
static constant real period = 0.03125000
static timer timer = CreateTimer()
static integer didx = -1
static thistype array data
static thistype array n
readonly static integer array count
unit unit
integer index
integer ticks
static method disarmed takes unit target returns boolean
return GetUnitAbilityLevel(target, ability) > 0
endmethod
private method remove takes integer i returns integer
call apply(unit, false)
set n[index] = 0
set unit = null
set data[i] = data[didx]
set didx = didx - 1
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method timed takes unit target, real duration returns nothing
local integer i = GetUnitUserData(target)
local thistype this
if n[i] != 0 then
set this = n[i]
else
set this = thistype.allocate()
set unit = target
set index = i
set didx = didx + 1
set data[didx] = this
set n[i] = this
call apply(target, true)
if didx == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endif
set ticks = R2I(duration/period)
endmethod
static method apply takes unit target, boolean flag returns nothing
local integer i = GetUnitUserData(target)
if flag then
set count[i] = count[i] + 1
if count[i] > 0 then
call UnitAddAbility(target, ability)
endif
else
set count[i] = count[i] - 1
if count[i] <= 0 then
call UnitRemoveAbility(target, ability)
endif
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Start Ability Cooldown */
/* -------------------------------------------------------------------------- */
struct AbilityCooldown
timer timer
unit unit
integer ability
real newCd
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call BlzStartUnitAbilityCooldown(unit, ability, newCd)
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endmethod
static method start takes unit source, integer abilCode, real cooldown returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = source
set ability = abilCode
set newCd = cooldown
call TimerStart(timer, 0.01, false, function thistype.onExpire)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Remove Destructable Timed */
/* -------------------------------------------------------------------------- */
struct TimedDestructable
private static constant real period = 0.03125000
private static timer timer = CreateTimer()
private static integer id = -1
private static thistype array array
destructable destructable
real duration
private method remove takes integer i returns integer
call RemoveDestructable(destructable)
set destructable = null
set array[i] = array[id]
set id = id - 1
if id == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > id
set this = array[i]
if duration <= 0 then
set i = remove(i)
endif
set duration = duration - period
set i = i + 1
endloop
endmethod
static method create takes destructable dest, real timeout returns thistype
local thistype this = thistype.allocate()
set destructable = dest
set duration = timeout
set id = id + 1
set array[id] = this
if id == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Timed Pause */
/* -------------------------------------------------------------------------- */
private struct TimedPause
static integer array array
timer timer
unit unit
integer key
boolean flag
static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set array[key] = array[key] - 1
if array[key] == 0 then
call BlzPauseUnitEx(unit, not flag)
endif
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endmethod
static method create takes unit u, real duration, boolean pause returns thistype
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = u
set flag = pause
set key = GetUnitUserData(u)
if array[key] == 0 then
call BlzPauseUnitEx(u, pause)
endif
set array[key] = array[key] + 1
call TimerStart(timer, duration, false, function thistype.onExpire)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Public JASS API */
/* -------------------------------------------------------------------------- */
// Removes a destructable after a period of time
function RemoveDestructableTimed takes destructable dest, real timeout returns nothing
call TimedDestructable.create(dest, timeout)
endfunction
// Returns true if a unit is disarmed
function IsUnitDisarmed takes unit target returns boolean
return Disarm.disarmed(target)
endfunction
// Disarms an unit for a duration
function DisarmUnitTimed takes unit target, real duration returns nothing
call Disarm.timed(target, duration)
endfunction
// Disarms an unit if flag is true
function DisarmUnit takes unit target, boolean flag returns nothing
call Disarm.apply(target, flag)
endfunction
// Link an effect to a unit buff or ability
function LinkEffectToBuff takes unit target, integer buffId, string model, string attach returns nothing
call EffectLink.BuffLink(target, buffId, model, attach)
endfunction
// Link an effect to an unit item.
function LinkEffectToItem takes unit target, item i, string model, string attach returns nothing
call EffectLink.ItemLink(target, i, model, attach)
endfunction
// Pretty obvious.
function R2I2S takes real r returns string
return I2S(R2I(r))
endfunction
// Spams the specified effect model at a location with the given interval for the number of times count
function SpamEffect takes string model, real x, real y, real z, real scale, real interval, integer count returns nothing
call EffectSpam.spam(null, model, "", x, y, z, scale, interval, count)
endfunction
// Spams the specified effect model attached to a unit for the given interval for the number of times count
function SpamEffectUnit takes unit target, string model, string attach, real interval, integer count returns nothing
call EffectSpam.spam(target, model, attach, 0, 0, 0, 0, interval, count)
endfunction
// Applys Fear to the specified unit for the given duration
function UnitApplyFear takes unit whichUnit, real duration, string targetEffect, string attchPoint returns nothing
call Fear.apply(whichUnit, duration, targetEffect, attchPoint)
endfunction
// Returns true if the specified unit is currently under the effect of fear effect
function IsUnitFeared takes unit whichUnit returns boolean
return Fear.feared(whichUnit)
endfunction
// Add the specified ability to the specified unit for the given duration. Use hide to show or not the ability button.
function UnitAddAbilityTimed takes unit whichUnit, integer abilityId, real duration, integer level, boolean hide returns nothing
call TimedAbility.add(whichUnit, abilityId, duration, level, hide)
endfunction
// Resets the specified unit ability cooldown
function ResetUnitAbilityCooldown takes unit whichUnit, integer abilCode returns nothing
call ResetCooldown.reset(whichUnit, abilCode)
endfunction
// Knockback the target unit given the angle (Rad) and a distance. Set model and point to attach an effect. Set onCliff to true to make the knockback stop when hitting a cliff, same for the others.
function KnockbackUnit takes unit whichUnit, real angle, real distance, real duration, string model, string point, boolean onCliff, boolean onDestructable, boolean onUnit, boolean pause returns nothing
//call Knockback.start(whichUnit, angle, distance, duration, model, point, onCliff, onDestructable, onUnit, pause)
endfunction
// Returns true if a unit is currently being knocked back
function IsUnitKnockedBack takes unit whichUnit returns boolean
return Knockback.isUnitKnocked(whichUnit)
endfunction
// Returns the distance between 2 coordinates in Warcraft III units
function DistanceBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
local real dx = (x2 - x1)
local real dy = (y2 - y1)
return SquareRoot(dx*dx + dy*dy)
endfunction
// Makes the specified source damage an area respecting some basic unit filters
function UnitDamageArea takes unit source, real x, real y, real aoe, real damage, attacktype atkType, damagetype dmgType, boolean structures, boolean magicImmune, boolean allies returns nothing
local group h = CreateGroup()
local player enemyOf = GetOwningPlayer(source)
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
if allies then
if structures and magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and w != source) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif structures and not magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and w != source) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif magicImmune and not structures then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and w != source) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
else
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and w != source) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
endif
else
if structures and magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif structures and not magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif magicImmune and not structures then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
else
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
endif
endif
call DestroyGroup(h)
set h = null
set enemyOf = null
endfunction
// Makes the specified source damage a group. Creates a special effect if specified
function UnitDamageGroup takes unit u, group g, real damage, attacktype atk_type, damagetype dmg_type, string sfx, string atch_point, boolean destroy returns group
local unit v
local integer i = 0
local integer t = BlzGroupGetSize(g)
loop
exitwhen i == t
set v = BlzGroupUnitAt(g, i)
call UnitDamageTarget(u, v, damage, true, false, atk_type, dmg_type, null)
if sfx != "" and atch_point != "" then
call DestroyEffect(AddSpecialEffectTarget(sfx, v, atch_point))
endif
set i = i + 1
endloop
if destroy then
call DestroyGroup(g)
endif
return g
endfunction
// Returns a random range given a max value
function GetRandomRange takes real radius returns real
local real r = GetRandomReal(0, 1) + GetRandomReal(0, 1)
if r > 1 then
return (2 - r)*radius
endif
return r*radius
endfunction
// Returns a random value in the x/y coordinates depending on the value of boolean x
function GetRandomCoordInRange takes real center, real radius, boolean x returns real
local real theta = 2*bj_PI*GetRandomReal(0, 1)
local real r
if x then
set r = center + radius*Cos(theta)
else
set r = center + radius*Sin(theta)
endif
return r
endfunction
// Clones the items in the source unit inventory to the target unit
function CloneItems takes unit source, unit target returns nothing
local integer i = 0
local integer j
local item k
loop
exitwhen i > bj_MAX_INVENTORY
set k = UnitItemInSlot(source, i)
set j = GetItemCharges(k)
set k = CreateItem(GetItemTypeId(k), GetUnitX(target), GetUnitY(target))
call SetItemCharges(k, j)
call UnitAddItem(target, k)
set i = i + 1
endloop
set k = null
endfunction
// Add the mount for he unit mana pool
function AddUnitMana takes unit whichUnit, real amount returns nothing
call SetUnitState(whichUnit, UNIT_STATE_MANA, (GetUnitState(whichUnit, UNIT_STATE_MANA) + amount))
endfunction
// Add the specified amounts to a hero str/agi/int base amount
function UnitAddStat takes unit whichUnit, integer strength, integer agility, integer intelligence returns nothing
if strength != 0 then
call SetHeroStr(whichUnit, GetHeroStr(whichUnit, false) + strength, true)
endif
if agility != 0 then
call SetHeroAgi(whichUnit, GetHeroAgi(whichUnit, false) + agility, true)
endif
if intelligence != 0 then
call SetHeroInt(whichUnit, GetHeroInt(whichUnit, false) + intelligence, true)
endif
endfunction
// Returns the closest unit from the x and y coordinates in the map
function GetClosestUnit takes real x, real y, boolexpr e returns unit
local real md = 100000
local group g = CreateGroup()
local unit u
local real dx
local real dy
set bj_closestUnitGroup = null
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, e)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if UnitAlive(u) then
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
if (dx*dx + dy*dy)/100000 < md then
set bj_closestUnitGroup = u
set md = (dx*dx + dy*dy)/100000
endif
endif
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
call DestroyBoolExpr(e)
set g = null
return bj_closestUnitGroup
endfunction
// Creates a chain lightning with the specified ligihtning effect with the amount of bounces
function CreateChainLightning takes unit source, unit target, real damage, real aoe, real duration, real interval, integer bounceCount, attacktype attackType, damagetype damageType, string lightningType, string sfx, string attachPoint, boolean canRebounce returns nothing
call ChainLightning.create(source, target, damage, aoe, duration, interval, bounceCount, attackType, damageType, lightningType, sfx, attachPoint, canRebounce)
endfunction
// Add the specified amount to the specified player gold amount
function AddPlayerGold takes player whichPlayer, integer amount returns nothing
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD) + amount)
endfunction
// Unit Knockup
function KnockupUnit takes unit whichUnit, real airTime, real maxHeight returns nothing
call Knockup.create(whichUnit, airTime, maxHeight)
endfunction
// Creates a text tag in an unit position for a duration
function CreateTextOnUnit takes unit whichUnit, string text, real duration, integer red, integer green, integer blue, integer alpha returns nothing
local texttag tx = CreateTextTag()
call SetTextTagText(tx, text, 0.015)
call SetTextTagPosUnit(tx, whichUnit, 0)
call SetTextTagColor(tx, red, green, blue, alpha)
call SetTextTagLifespan(tx, duration)
call SetTextTagVelocity(tx, 0.0, 0.0355)
call SetTextTagPermanent(tx, false)
set tx = null
endfunction
// Add health regeneration to the unit base value
function UnitAddHealthRegen takes unit whichUnit, real regen returns nothing
call BlzSetUnitRealField(whichUnit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, BlzGetUnitRealField(whichUnit, UNIT_RF_HIT_POINTS_REGENERATION_RATE) + regen)
endfunction
// Retrieves a dummy from the pool. Facing angle in radians
function DummyRetrieve takes player owner, real x, real y, real z, real face returns unit
return DummyPool.retrieve(owner, x, y, z, face)
endfunction
// Recycles a dummy unit type, putting it back into the pool.
function DummyRecycle takes unit dummy returns nothing
call DummyPool.recycle(dummy)
endfunction
// Recycles a dummy with a delay.
function DummyRecycleTimed takes unit dummy, real delay returns nothing
call DummyPool.recycleTimed(dummy, delay)
endfunction
// Casts an ability in the target unit. Must have no casting time
function CastAbilityTarget takes unit target, integer id, string order, integer level returns nothing
local unit dummy = DummyRetrieve(GetOwningPlayer(target), 0, 0, 0, 0)
call UnitAddAbility(dummy, id)
call SetUnitAbilityLevel(dummy, id, level)
call IssueTargetOrder(dummy, order, target)
call UnitRemoveAbility(dummy, id)
call DummyRecycle(dummy)
set dummy = null
endfunction
// Silences the specified unit for the given duration
function SilenceUnit takes unit whichUnit, real duration returns nothing
local unit dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(whichUnit), GetUnitY(whichUnit), GetUnitFlyHeight(whichUnit), 0)
local ability a
call UnitAddAbility(dummy, SILENCE)
set a = BlzGetUnitAbility(dummy, SILENCE)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, SILENCE)
call DecUnitAbilityLevel(dummy, SILENCE)
call IssueTargetOrder(dummy, "drunkenhaze", whichUnit)
call UnitRemoveAbility(dummy, SILENCE)
call DummyRecycle(dummy)
set dummy = null
set a = null
endfunction
// Silences a group of units for the given duration
function SilenceGroup takes group whichGroup, real duration returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(whichGroup)
local unit u
local unit dummy
local ability a
if size > 0 then
set u = BlzGroupUnitAt(whichGroup, i)
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), 0)
call UnitAddAbility(dummy, SILENCE)
set a = BlzGetUnitAbility(dummy, SILENCE)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, SILENCE)
call DecUnitAbilityLevel(dummy, SILENCE)
loop
exitwhen i == size
set u = BlzGroupUnitAt(whichGroup, i)
if UnitAlive(u) then
call IssueTargetOrder(dummy, "drunkenhaze", u)
endif
set i = i + 1
endloop
call UnitRemoveAbility(dummy, SILENCE)
call DummyRecycle(dummy)
endif
set u = null
set a = null
set dummy = null
endfunction
// Silences all units within the specified AOE with the center at x and y for the given duration
function SilenceArea takes real x, real y, real aoe, real duration returns nothing
local group g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, aoe, null)
call SilenceGroup(g, duration)
call DestroyGroup(g)
set g = null
endfunction
// Stuns the specified unit for the given duration
function StunUnit takes unit whichUnit, real duration returns nothing
local unit dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(whichUnit), GetUnitY(whichUnit), GetUnitFlyHeight(whichUnit), 0)
local ability a
call UnitAddAbility(dummy, STUN)
set a = BlzGetUnitAbility(dummy, STUN)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, STUN)
call DecUnitAbilityLevel(dummy, STUN)
call IssueTargetOrder(dummy, "thunderbolt", whichUnit)
call UnitRemoveAbility(dummy, STUN)
call DummyRecycle(dummy)
set dummy = null
set a = null
endfunction
// Stuns a group of units for the given duration
function StunGroup takes group whichGroup, real duration returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(whichGroup)
local unit u
local unit dummy
local ability a
if size > 0 then
set u = BlzGroupUnitAt(whichGroup, i)
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), 0)
call UnitAddAbility(dummy, STUN)
set a = BlzGetUnitAbility(dummy, STUN)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, STUN)
call DecUnitAbilityLevel(dummy, STUN)
loop
exitwhen i == size
set u = BlzGroupUnitAt(whichGroup, i)
if UnitAlive(u) then
call IssueTargetOrder(dummy, "thunderbolt", u)
endif
set i = i + 1
endloop
call UnitRemoveAbility(dummy, STUN)
call DummyRecycle(dummy)
endif
set u = null
set a = null
set dummy = null
endfunction
// Stuns all units within the specified AOE with the center at x and y for the given duration
function StunArea takes real x, real y, real aoe, real duration returns nothing
local group g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, aoe, null)
call StunGroup(g, duration)
call DestroyGroup(g)
set g = null
endfunction
// Slows the specified unit for the given duration
function SlowUnit takes unit whichUnit, real amount, real duration returns nothing
local unit dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(whichUnit), GetUnitY(whichUnit), GetUnitFlyHeight(whichUnit), 0)
local ability a
call UnitAddAbility(dummy, SLOW)
set a = BlzGetUnitAbility(dummy, SLOW)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_MOVEMENT_SPEED_REDUCTION_PERCENT_CRI1, 0, amount)
call IncUnitAbilityLevel(dummy, SLOW)
call DecUnitAbilityLevel(dummy, SLOW)
call IssueTargetOrder(dummy, "cripple", whichUnit)
call UnitRemoveAbility(dummy, SLOW)
call DummyRecycle(dummy)
set dummy = null
set a = null
endfunction
// Slows a group of units for the given duration
function SlowGroup takes group whichGroup, real amount, real duration returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(whichGroup)
local unit u
local unit dummy
local ability a
if size > 0 then
set u = BlzGroupUnitAt(whichGroup, i)
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), 0)
call UnitAddAbility(dummy, SLOW)
set a = BlzGetUnitAbility(dummy, SLOW)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_DURATION_HERO, 0, duration)
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_MOVEMENT_SPEED_FACTOR_SLO1, 0, amount)
call IncUnitAbilityLevel(dummy, SLOW)
call DecUnitAbilityLevel(dummy, SLOW)
loop
exitwhen i == size
set u = BlzGroupUnitAt(whichGroup, i)
if UnitAlive(u) then
call IssueTargetOrder(dummy, "slow", u)
endif
set i = i + 1
endloop
call UnitRemoveAbility(dummy, SLOW)
call DummyRecycle(dummy)
endif
set u = null
set a = null
set dummy = null
endfunction
// Slows all units within the specified AOE with the center at x and y for the given duration
function SlowArea takes real x, real y, real aoe, real amount, real duration returns nothing
local group g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, aoe, null)
call SlowGroup(g, amount, duration)
call DestroyGroup(g)
set g = null
endfunction
// Returns a random unit within a group
function GroupPickRandomUnitEx takes group g returns unit
if BlzGroupGetSize(g) > 0 then
return BlzGroupUnitAt(g, GetRandomInt(0, BlzGroupGetSize(g) - 1))
else
return null
endif
endfunction
// Returns true if a unit is within a cone given a facing and fov angle in degrees (Less precise)
function IsUnitInConeEx takes unit u, real x, real y, real face, real fov returns boolean
return Acos(Cos((Atan2(GetUnitY(u) - y, GetUnitX(u) - x)) - face*bj_DEGTORAD)) < fov*bj_DEGTORAD/2
endfunction
// Returns true if a unit is within a cone given a facing, fov angle and a range in degrees (takes collision into consideration). Credits to AGD.
function IsUnitInCone takes unit u, real x, real y, real range, real face, real fov returns boolean
if IsUnitInRangeXY(u, x, y, range) then
set x = GetUnitX(u) - x
set y = GetUnitY(u) - y
set range = x*x + y*y
if range > 0. then
set face = face*bj_DEGTORAD - Atan2(y, x)
set fov = fov*bj_DEGTORAD/2 + Asin(BlzGetUnitCollisionSize(u)/SquareRoot(range))
return RAbsBJ(face) <= fov or RAbsBJ(face - 2.00*bj_PI) <= fov
endif
return true
endif
return false
endfunction
// Makes the source unit damage enemy unit in a cone given a direction, foy and range
function UnitDamageCone takes unit source, real x, real y, real face, real fov, real aoe, real damage, attacktype atkType, damagetype dmgType, boolean structures, boolean magicImmune, boolean allies returns nothing
local group h = CreateGroup()
local player enemyOf = GetOwningPlayer(source)
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
if allies then
if structures and magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and w != source and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif structures and not magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and w != source and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif magicImmune and not structures then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and w != source and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
else
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and w != source and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
endif
else
if structures and magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif structures and not magicImmune then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
elseif magicImmune and not structures then
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
else
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (IsUnitEnemy(w, enemyOf) and UnitAlive(w) and not IsUnitType(w, UNIT_TYPE_STRUCTURE) and not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitInCone(w, x, y, aoe, face, fov)) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
endif
endif
call DestroyGroup(h)
set h = null
set enemyOf = null
endfunction
// Heals all allied units of specified player in an area
function HealArea takes player alliesOf, real x, real y, real aoe, real amount, string fxpath, string attchPoint returns nothing
local group g = CreateGroup()
local unit v
call GroupEnumUnitsInRange(g, x, y, aoe, null)
loop
set v = FirstOfGroup(g)
exitwhen v == null
if IsUnitAlly(v, alliesOf) and UnitAlive(v) and not IsUnitType(v, UNIT_TYPE_STRUCTURE) then
call SetWidgetLife(v, GetWidgetLife(v) + amount)
if fxpath != "" then
if attchPoint != "" then
call DestroyEffect(AddSpecialEffectTarget(fxpath, v, attchPoint))
else
call DestroyEffect(AddSpecialEffect(fxpath, GetUnitX(v), GetUnitY(v)))
endif
endif
endif
call GroupRemoveUnit(g, v)
endloop
call DestroyGroup(g)
set g = null
endfunction
// Returns an ability real level field as a string. Usefull for toolltip manipulation.
function AbilityRealField takes unit u, integer abilityId, abilityreallevelfield field, integer level, integer multiplier, boolean asInteger returns string
if asInteger then
return R2I2S(BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilityId), field, level)*multiplier)
else
return R2SW(BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilityId), field, level)*multiplier,1,1)
endif
endfunction
// Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModified takes player whichPlayer, location loc, real duration returns nothing
local real tx = GetLocationX(loc)
local real ty = GetLocationY(loc)
local real dx = tx - GetCameraTargetPositionX()
local real dy = ty - GetCameraTargetPositionY()
local real dist = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == whichPlayer) then
if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
call PanCameraToTimed(tx, ty, duration)
// Far away = snap camera immediately to point
elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
call PanCameraToTimed(tx, ty, duration)
// Moderately close = pan camera over duration
else
// User is close, don't move camera
endif
endif
endfunction
// Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModifiedXY takes player whichPlayer, real x, real y, real duration returns nothing
local real dx = x - GetCameraTargetPositionX()
local real dy = y - GetCameraTargetPositionY()
local real dist = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == whichPlayer) then
if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
call PanCameraToTimed(x, y, duration)
// Far away = snap camera immediately to point
elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
call PanCameraToTimed(x, y, duration)
// Moderately close = pan camera over duration
else
// User is close, don't move camera
endif
endif
endfunction
// Start the cooldown for the source unit unit the new value
function StartUnitAbilityCooldown takes unit source, integer abilCode, real cooldown returns nothing
call AbilityCooldown.start(source, abilCode, cooldown)
endfunction
// Pauses or Unpauses a unit after a delay. If flag = true than the unit will be paused and unpaused after the duration. If flag = false than the unit will be unpaused and paused after the duration.
function PauseUnitTimed takes unit u, real duration, boolean flag returns nothing
call TimedPause.create(u, duration, flag)
endfunction
endlibrary
library Indexer
/* ------------------------ Indexer v1.1 by Chopinski ----------------------- */
// Simple unit indexer for version 1.31+
// Simply copy and paste to import
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Indexer
private static integer ability = 'Adef'
private static integer array array
private static integer key = -1
private static integer id = -1
readonly static unit unit
readonly static trigger onIndex = CreateTrigger()
readonly static trigger onDeindex = CreateTrigger()
private static method index takes unit source returns nothing
if GetUnitUserData(source) == 0 then
set unit = source
if key > - 1 then
set id = array[key]
set array[key] = 0
set key = key - 1
else
set id = id + 1
endif
if GetUnitAbilityLevel(unit, ability) == 0 then
call UnitAddAbility(unit, ability)
call UnitMakeAbilityPermanent(unit, true, ability)
call BlzUnitDisableAbility(unit, ability, true, true)
endif
call SetUnitUserData(unit, id)
call TriggerEvaluate(onIndex)
set unit = null
endif
endmethod
private static method onOrder takes nothing returns nothing
if GetIssuedOrderId() == 852056 then
if GetUnitAbilityLevel(GetTriggerUnit(), ability) == 0 then
set unit = GetTriggerUnit()
call TriggerEvaluate(onDeindex)
set key = key + 1
set array[key] = GetUnitUserData(unit)
set unit = null
endif
endif
endmethod
private static method onEnter takes nothing returns nothing
call index(GetFilterUnit())
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local region r = CreateRegion()
local rect map = GetWorldBounds()
local integer i = 0
call RegionAddRect(r, map)
call RemoveRect(map)
call TriggerRegisterEnterRegion(CreateTrigger(), r, Filter(function thistype.onEnter))
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), null)
loop
set unit = FirstOfGroup(bj_lastCreatedGroup)
exitwhen unit == null
call index(unit)
call GroupRemoveUnit(bj_lastCreatedGroup, unit)
endloop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function thistype.onOrder))
set r = null
set map = null
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function RegisterUnitIndexEvent takes code c returns nothing
call TriggerAddCondition(Indexer.onIndex, Filter(c))
endfunction
function RegisterUnitDeindexEvent takes code c returns nothing
call TriggerAddCondition(Indexer.onDeindex, Filter(c))
endfunction
function GetIndexUnit takes nothing returns unit
return Indexer.unit
endfunction
endlibrary
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
library MouseUtils
/*
-------------------
MouseUtils
- MyPad
1.0.2.2
-------------------
----------------------------------------------------------------------------
A simple snippet that allows one to
conveniently use the mouse natives
as they were meant to be...
-------------------
| API |
-------------------
struct UserMouse extends array
static method operator [] (player p) -> thistype
- Returns the player's id + 1
static method getCurEventType() -> integer
- Returns the custom event that got executed.
method operator player -> player
- Returns Player(this - 1)
readonly real mouseX
readonly real mouseY
- Returns the current mouse coordinates.
readonly method operator isMouseClicked -> boolean
- Determines whether any mouse key has been clicked,
and will return true on the first mouse key.
method isMouseButtonClicked(mousebuttontype mouseButton)
- Returns true if the mouse button hasn't been
released yet.
method setMousePos(real x, y) (introduced in 1.0.2.2)
- Sets the mouse position for a given player.
static method registerCode(code c, integer ev) -> triggercondition
- Lets code run upon the execution of a certain event.
- Returns a triggercondition that can be removed later.
static method unregisterCallback(triggercondition trgHndl, integer ev)
- Removes a generated triggercondition from the trigger.
functions:
GetPlayerMouseX(player p) -> real
GetPlayerMouseY(player p) -> real
- Returns the coordinates of the mouse of the player.
OnMouseEvent(code func, integer eventId) -> triggercondition
- See UserMouse.registerCode
GetMouseEventType() -> integer
- See UserMouse.getCurEventType
UnregisterMouseCallback(triggercondition t, integer eventId)
- See UserMouse.unregisterCallback
SetUserMousePos(player p, real x, real y)
- See UserMouse.setMousePos
Unique Global Constants:
IMPL_LOCK (Introduced in v.1.0.2.2)
- Enables or disables the lock option
-------------------
| Credits |
-------------------
- Pyrogasm for pointing out a comparison logic flaw
in operator isMouseClicked.
- Illidan(Evil)X for the useful enum handles that
grant more functionality to this snippet.
- TriggerHappy for the suggestion to include
associated events and callbacks to this snippet.
- Quilnez for pointing out a bug related to the
method isMouseButtonClicked not working as intended
in certain situations.
----------------------------------------------------------------------------
*/
// Arbitrary constants
globals
constant integer EVENT_MOUSE_UP = 1024
constant integer EVENT_MOUSE_DOWN = 2048
constant integer EVENT_MOUSE_MOVE = 3072
private constant boolean IMPL_LOCK = false
endglobals
private module Init
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
struct UserMouse extends array
static if IMPL_LOCK then
// Determines the minimum interval that a mouse move event detector
// will be deactivated. (Globally-based)
// You can configure it to any amount you like.
private static constant real INTERVAL = 0.031250000
// Determines how many times a mouse move event detector can fire
// before being deactivated. (locally-based)
// You can configure this to any integer value. (Preferably positive)
private static constant integer MOUSE_COUNT_MAX = 16
// Determines the amount to be deducted from mouseEventCount
// per INTERVAL. Runs independently of resetTimer
private static constant integer MOUSE_COUNT_LOSS = 8
private static constant boolean IS_INSTANT = INTERVAL <= 0.
endif
private static integer currentEventType = 0
private static integer updateCount = 0
private static trigger stateDetector = null
static if IMPL_LOCK and not IS_INSTANT then
private static timer resetTimer = null
endif
private static trigger array evTrigger
private static integer array mouseButtonStack
static if IMPL_LOCK and not IS_INSTANT then
private integer mouseEventCount
private timer mouseEventReductor
endif
private thistype next
private thistype prev
private thistype resetNext
private thistype resetPrev
private trigger posDetector
private integer mouseClickCount
readonly real mouseX
readonly real mouseY
// Converts the enum type mousebuttontype into an integer
private static method toIndex takes mousebuttontype mouseButton returns integer
return GetHandleId(mouseButton)
endmethod
static method getCurEventType takes nothing returns integer
return currentEventType
endmethod
static method operator [] takes player p returns thistype
if thistype(GetPlayerId(p) + 1).posDetector != null then
return GetPlayerId(p) + 1
endif
return 0
endmethod
method operator player takes nothing returns player
return Player(this - 1)
endmethod
method operator isMouseClicked takes nothing returns boolean
return .mouseClickCount > 0
endmethod
method isMouseButtonClicked takes mousebuttontype mouseButton returns boolean
return UserMouse.mouseButtonStack[(this - 1)*3 + UserMouse.toIndex(mouseButton)] > 0
endmethod
method setMousePos takes integer x, integer y returns nothing
if GetLocalPlayer() == this.player then
call BlzSetMousePos(x, y)
endif
endmethod
static if IMPL_LOCK then
private static method getMouseEventReductor takes timer t returns thistype
local thistype this = thistype(0).next
loop
exitwhen this.mouseEventReductor == t or this == 0
set this = this.next
endloop
return this
endmethod
private static method onMouseUpdateListener takes nothing returns nothing
local thistype this = thistype(0).resetNext
set updateCount = 0
loop
exitwhen this == 0
set updateCount = updateCount + 1
set this.mouseEventCount = 0
call EnableTrigger(this.posDetector)
set this.resetNext.resetPrev = this.resetPrev
set this.resetPrev.resetNext = this.resetNext
set this = this.resetNext
endloop
if updateCount > 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
else
call onMouseUpdateListener()
endif
else
static if not IS_INSTANT then
call TimerStart(resetTimer, 0.00, false, null)
call PauseTimer(resetTimer)
endif
endif
endmethod
private static method onMouseReductListener takes nothing returns nothing
local thistype this = getMouseEventReductor(GetExpiredTimer())
if this.mouseEventCount <= 0 then
call PauseTimer(this.mouseEventReductor)
else
set this.mouseEventCount = IMaxBJ(this.mouseEventCount - MOUSE_COUNT_LOSS, 0)
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endmethod
endif
private static method onMouseUpOrDown takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local integer index = (this - 1)*3 + UserMouse.toIndex(BlzGetTriggerPlayerMouseButton())
local boolean releaseFlag = false
if GetTriggerEventId() == EVENT_PLAYER_MOUSE_DOWN then
set this.mouseClickCount = IMinBJ(this.mouseClickCount + 1, 3)
set releaseFlag = UserMouse.mouseButtonStack[index] <= 0
set UserMouse.mouseButtonStack[index] = IMinBJ(UserMouse.mouseButtonStack[index] + 1, 1)
if releaseFlag then
set currentEventType = EVENT_MOUSE_DOWN
call TriggerEvaluate(evTrigger[EVENT_MOUSE_DOWN])
endif
else
set this.mouseClickCount = IMaxBJ(this.mouseClickCount - 1, 0)
set releaseFlag = UserMouse.mouseButtonStack[index] > 0
set UserMouse.mouseButtonStack[index] = IMaxBJ(UserMouse.mouseButtonStack[index] - 1, 0)
if releaseFlag then
set currentEventType = EVENT_MOUSE_UP
call TriggerEvaluate(evTrigger[EVENT_MOUSE_UP])
endif
endif
endmethod
private static method onMouseMove takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local boolean started = false
set this.mouseX = BlzGetTriggerPlayerMouseX()
set this.mouseY = BlzGetTriggerPlayerMouseY()
static if IMPL_LOCK then
set this.mouseEventCount = this.mouseEventCount + 1
if this.mouseEventCount <= 1 then
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endif
set currentEventType = EVENT_MOUSE_MOVE
call TriggerEvaluate(evTrigger[EVENT_MOUSE_MOVE])
static if IMPL_LOCK then
if this.mouseEventCount >= thistype.MOUSE_COUNT_MAX then
call DisableTrigger(this.posDetector)
if thistype(0).resetNext == 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
// Mouse event reductor should be paused
else
set started = true
endif
call PauseTimer(this.mouseEventReductor)
endif
set this.resetNext = 0
set this.resetPrev = this.resetNext.resetPrev
set this.resetPrev.resetNext = this
set this.resetNext.resetPrev = this
if started then
call onMouseUpdateListener()
endif
endif
endif
endmethod
private static method init takes nothing returns nothing
local thistype this = 1
local player p = this.player
static if IMPL_LOCK and not IS_INSTANT then
set resetTimer = CreateTimer()
endif
set stateDetector = CreateTrigger()
set evTrigger[EVENT_MOUSE_UP] = CreateTrigger()
set evTrigger[EVENT_MOUSE_DOWN] = CreateTrigger()
set evTrigger[EVENT_MOUSE_MOVE] = CreateTrigger()
call TriggerAddCondition( stateDetector, Condition(function thistype.onMouseUpOrDown))
loop
exitwhen integer(this) > bj_MAX_PLAYER_SLOTS
if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
set this.next = 0
set this.prev = thistype(0).prev
set thistype(0).prev.next = this
set thistype(0).prev = this
set this.posDetector = CreateTrigger()
static if IMPL_LOCK and not IS_INSTANT then
set this.mouseEventReductor = CreateTimer()
endif
call TriggerRegisterPlayerEvent( this.posDetector, p, EVENT_PLAYER_MOUSE_MOVE )
call TriggerAddCondition( this.posDetector, Condition(function thistype.onMouseMove))
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_UP )
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_DOWN )
endif
set this = this + 1
set p = this.player
endloop
endmethod
static method registerCode takes code handlerFunc, integer eventId returns triggercondition
return TriggerAddCondition(evTrigger[eventId], Condition(handlerFunc))
endmethod
static method unregisterCallback takes triggercondition whichHandler, integer eventId returns nothing
call TriggerRemoveCondition(evTrigger[eventId], whichHandler)
endmethod
implement Init
endstruct
function GetPlayerMouseX takes player p returns real
return UserMouse[p].mouseX
endfunction
function GetPlayerMouseY takes player p returns real
return UserMouse[p].mouseY
endfunction
function OnMouseEvent takes code func, integer eventId returns triggercondition
return UserMouse.registerCode(func, eventId)
endfunction
function GetMouseEventType takes nothing returns integer
return UserMouse.getCurEventType()
endfunction
function UnregisterMouseCallback takes triggercondition whichHandler, integer eventId returns nothing
call UserMouse.unregisterCallback(whichHandler, eventId)
endfunction
function SetUserMousePos takes player p, integer x, integer y returns nothing
call UserMouse[p].setMousePos(x, y)
endfunction
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world = GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set playMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set playMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set playMinX = GetRectMinX(bj_mapInitialPlayableArea)
set playMinY = GetRectMinY(bj_mapInitialPlayableArea)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
readonly static real playMaxX
readonly static real playMaxY
readonly static real playMinX
readonly static real playMinY
implement WorldBoundInit
endstruct
endlibrary
library TimedHandles uses optional TimerUtils
/**************************************************************
*
* v1.0.5 by TriggerHappy
* ----------------------
*
* Use this to destroy a handle after X amount seconds.
*
* It's useful for things like effects where you may
* want it to be temporary, but not have to worry
* about the cleaning memory leak. By default it supports
* effects, lightning, weathereffect, items, ubersplats, and units.
*
* If you want to add your own handle types copy a textmacro line
* at the bottom and add whichever handle you want along with it's destructor.
*
* Example: //! runtextmacro TIMEDHANDLES("handle", "DestroyHandle")
*
* Installation
----------------------
* 1. Copy this script and over to your map inside a blank trigger.
* 2. If you want more efficiency copy TimerUtils over as well.
*
* API
* ----------------------
* call DestroyEffectTimed(AddSpecialEffect("effect.mdx", 0, 0), 5)
* call DestroyLightningTimed(AddLightning("CLPB", true, 0, 0, 100, 100), 5)
*
* Credits to Vexorian for TimerUtils and his help on the script.
*
**************************************************************/
globals
// If you don't want a timer to be ran each instance
// set this to true.
private constant boolean SINGLE_TIMER = true
// If you chose a single timer then this will be the speed
// at which the timer will update
private constant real UPDATE_PERIOD = 0.05
endglobals
// here you may add or remove handle types
//! runtextmacro TIMEDHANDLES("effect", "DestroyEffect")
//! runtextmacro TIMEDHANDLES("lightning", "DestroyLightning")
//! runtextmacro TIMEDHANDLES("weathereffect", "RemoveWeatherEffect")
//! runtextmacro TIMEDHANDLES("item", "RemoveItem")
//! runtextmacro TIMEDHANDLES("unit", "RemoveUnit")
//! runtextmacro TIMEDHANDLES("ubersplat", "DestroyUbersplat")
// Do not edit below this line
//! textmacro TIMEDHANDLES takes HANDLE,DESTROY
struct $HANDLE$Timed
$HANDLE$ $HANDLE$_var
static integer index = -1
static thistype array instance
static real REAL=UPDATE_PERIOD
static if SINGLE_TIMER then
static timer timer = CreateTimer()
real duration
real elapsed = 0
else static if not LIBRARY.TimerUtils then
static hashtable table = InitHashtable()
endif
method destroy takes nothing returns nothing
call $DESTROY$(this.$HANDLE$_var)
set this.$HANDLE$_var = null
static if SINGLE_TIMER then
set this.elapsed = 0
endif
call this.deallocate()
endmethod
private static method remove takes nothing returns nothing
static if SINGLE_TIMER then
local integer i = 0
local thistype this
loop
exitwhen i > thistype.index
set this = instance[i]
set this.elapsed = this.elapsed + UPDATE_PERIOD
if (this.elapsed >= this.duration) then
set instance[i] = instance[index]
set i = i - 1
set index = index - 1
call this.destroy()
if (index == -1) then
call PauseTimer(thistype.timer)
endif
endif
set i = i + 1
endloop
else
local timer t = GetExpiredTimer()
static if LIBRARY.TimerUtils then
local $HANDLE$Timed this = GetTimerData(t)
call ReleaseTimer(t)
call this.destroy()
else
local $HANDLE$Timed this = LoadInteger(table, 0, GetHandleId(t))
call DestroyTimer(t)
set t = null
call this.destroy()
endif
endif
endmethod
static method create takes $HANDLE$ h, real timeout returns $HANDLE$Timed
local $HANDLE$Timed this = $HANDLE$Timed.allocate()
static if SINGLE_TIMER then
set index = index + 1
set instance[index] = this
if (index == 0) then
call TimerStart(thistype.timer, UPDATE_PERIOD, true, function thistype.remove)
endif
set this.duration = timeout
else
static if LIBRARY.TimerUtils then
call TimerStart(NewTimerEx(this), timeout, false, function $HANDLE$timed.remove)
else
local timer t = CreateTimer()
call SaveInteger(thistype.table, 0, GetHandleId(t), this)
call TimerStart(t, timeout, false, function $HANDLE$Timed.remove)
set t = null
endif
endif
set this.$HANDLE$_var = h
return this
endmethod
endstruct
function $DESTROY$Timed takes $HANDLE$ h, real duration returns $HANDLE$Timed
return $HANDLE$Timed.create(h, duration)
endfunction
//! endtextmacro
endlibrary
library PluginSpellEffect requires RegisterPlayerUnitEvent
/* ------------------- SpellEffectPlugin v1.1 by Chopinski ------------------ */
// Simple plugin for the SpellEffectEvent library by Bribe to cache some usefull
// values.
// Credits to Bribe and Magtheridon96
/* ----------------------------------- END ---------------------------------- */
private struct SUnit
unit unit
player player
integer handle
boolean isHero
boolean isStructure
integer id
real x
real y
real z
static method create takes nothing returns thistype
return thistype.allocate()
endmethod
endstruct
private module Event
readonly static location location = Location(0, 0)
readonly static SUnit source
readonly static SUnit target
readonly static ability ability
readonly static integer level
readonly static integer id
readonly static real x
readonly static real y
readonly static real z
private static method GetUnitZ takes unit u returns real
call MoveLocation(location, GetUnitX(u), GetUnitY(u))
return GetUnitFlyHeight(u) + GetLocationZ(location)
endmethod
private static method GetSpellTargetZ takes nothing returns real
call MoveLocation(location, x, y)
if target.unit != null then
return GetUnitZ(target.unit)
else
return GetLocationZ(location)
endif
endmethod
private static method onCast takes nothing returns nothing
set source.unit = GetTriggerUnit()
set source.player = GetOwningPlayer(source.unit)
set source.handle = GetHandleId(source.unit)
set source.id = GetUnitUserData(source.unit)
set source.x = GetUnitX(source.unit)
set source.y = GetUnitY(source.unit)
set source.z = GetUnitZ(source.unit)
set source.isHero = IsUnitType(source.unit, UNIT_TYPE_HERO)
set source.isStructure = IsUnitType(source.unit, UNIT_TYPE_STRUCTURE)
set target.unit = GetSpellTargetUnit()
set target.player = GetOwningPlayer(target.unit)
set target.handle = GetHandleId(target.unit)
set target.id = GetUnitUserData(target.unit)
set target.x = GetUnitX(target.unit)
set target.y = GetUnitY(target.unit)
set target.z = GetUnitZ(target.unit)
set target.isHero = IsUnitType(target.unit, UNIT_TYPE_HERO)
set target.isStructure = IsUnitType(target.unit, UNIT_TYPE_STRUCTURE)
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set z = GetSpellTargetZ()
set id = GetSpellAbilityId()
set level = GetUnitAbilityLevel(source.unit, id)
set ability = BlzGetUnitAbility(source.unit, id)
endmethod
private static method onInit takes nothing returns nothing
set source = SUnit.create()
set target = SUnit.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
struct Spell extends array
implement Event
endstruct
endlibrary
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
// Arcing Text Tag v1.0.0.3 by Maker
// with added API by Bribe with features proposed by Ugabunda and Kusanagi Kuro
//
//
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.015 // Minimum size of text
private constant real SIZE_BONUS = 0.010 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 50 // Height above unit
private constant real Z_OFFSET_BON = 50 // How much extra height the text gains
private constant real VELOCITY = 2 // How fast the text move in x/y plane
private constant real ANGLE = bj_PI/2 // Movement angle of the text. Does not apply if
// RANDOM is true
private constant boolean RANDOM = true // Is the angle random or fixed
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private real scale
private real timeScale
public static thistype lastCreated = 0
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*(.t / timeScale))
set .t = .t - 0.03125
set .x = .x + .ac
set .y = .y + .as
call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON*p)
call SetTextTagText(.tt, .s, (SIZE_MIN + SIZE_BONUS*p)*.scale)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method createEx takes string s, unit u, real duration, real size, player p, boolean boo, real angle returns thistype
local thistype this = rn[0]
local real a
if boo == true then
set a = GetRandomReal(0, 2*bj_PI)
else
set a = angle
endif
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .scale = size
set .timeScale = RMaxBJ(duration, 0.001)
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .s = s
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .t = TIME_LIFE
set .as = Sin(a)*VELOCITY
set .ac = Cos(a)*VELOCITY
if IsUnitVisible(u, p) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE*duration)
call SetTextTagFadepoint(.tt, TIME_FADE*duration)
call SetTextTagText(.tt, s, SIZE_MIN*size)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
else
set .tt = null
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
set .lastCreated = this
return this
endmethod
public static method create takes string s, unit u returns thistype
return thistype.createEx(s, u, TIME_LIFE, 1.00, GetLocalPlayer(), RANDOM, ANGLE )
endmethod
public static method createS takes string s, unit u, real size returns thistype
return thistype.createEx(s, u, TIME_LIFE, size, GetLocalPlayer(), RANDOM, ANGLE )
endmethod
endstruct
endlibrary
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
library MissileEffect requires WorldBounds, Alloc
/* -------------------- Missile Effect v2.6 by Chopinski -------------------- */
// This is a simple helper library for the Relativistic Missiles system.
// Credits:
// Sevion for the Alloc module
// - www.hiveworkshop.com/threads/snippet-alloc.192348/
// Nestharus for World Bounds Library
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module LinkedList
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method pushBack takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pushFront takes thistype node returns thistype
set node.prev = this
set node.next = next
set next.prev = node
set next = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct Effect extends array
implement LinkedList
implement Alloc
real x
real y
real z
real size
real yaw
real pitch
real roll
string path
effect effect
method remove takes nothing returns nothing
call DestroyEffect(effect)
call pop()
call deallocate()
set effect = null
endmethod
method insert takes string fxpath, real x, real y, real z, real scale returns thistype
local thistype node = pushBack(allocate())
set node.x = x
set node.y = y
set node.z = z
set node.yaw = 0.
set node.pitch = 0.
set node.roll = 0.
set node.path = fxpath
set node.size = scale
set node.effect = AddSpecialEffect(fxpath, x, y)
call BlzSetSpecialEffectZ(node.effect, z)
call BlzSetSpecialEffectScale(node.effect, scale)
return node
endmethod
static method create takes nothing returns thistype
return thistype(allocate()).init()
endmethod
endstruct
struct MissileEffect
real size
real yaw
real pitch
real roll
real time
integer transparency
integer animtype
integer playercolor
string path
effect effect
Effect attachments
/* -------------------------------- Operators ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set time = newTimeScale
call BlzSetSpecialEffectTimeScale(effect, time)
endmethod
method operator timeScale takes nothing returns real
return time
endmethod
method operator alpha= takes integer newAlpha returns nothing
set transparency = newAlpha
call BlzSetSpecialEffectAlpha(effect, transparency)
endmethod
method operator alpha takes nothing returns integer
return transparency
endmethod
method operator playerColor= takes integer playerId returns nothing
set playercolor = playerId
call BlzSetSpecialEffectColorByPlayer(effect, Player(playerId))
endmethod
method operator playerColor takes nothing returns integer
return playercolor
endmethod
method operator animation= takes integer animType returns nothing
set animtype = animType
call BlzPlaySpecialEffect(effect, ConvertAnimType(animtype))
endmethod
method operator animation takes nothing returns integer
return animtype
endmethod
/* --------------------------------- Methods -------------------------------- */
method scale takes effect sfx, real scale returns nothing
set size = scale
call BlzSetSpecialEffectScale(sfx, scale)
endmethod
method orient takes real yaw, real pitch, real roll returns nothing
local Effect node = attachments.next
set .yaw = yaw
set .pitch = pitch
set .roll = roll
call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)
loop
exitwhen node == attachments
set node.yaw = yaw
set node.pitch = pitch
set node.roll = roll
call BlzSetSpecialEffectOrientation(node.effect, yaw, pitch, roll)
set node = node.next
endloop
endmethod
method move takes real x, real y, real z returns boolean
local Effect node = attachments.next
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
call BlzSetSpecialEffectPosition(effect, x, y, z)
loop
exitwhen node == attachments
call BlzSetSpecialEffectPosition(node.effect, x - node.x, y - node.y, z - node.z)
set node = node.next
endloop
return true
endif
return false
endmethod
method attach takes string fxpath, real dx, real dy, real dz, real scale returns effect
local Effect node = attachments.insert(fxpath, dx, dy, dz, scale)
call BlzSetSpecialEffectPosition(node.effect, BlzGetLocalSpecialEffectX(effect) - dx, BlzGetLocalSpecialEffectY(effect) - dy, BlzGetLocalSpecialEffectZ(effect) - dz)
return node.effect
endmethod
method detach takes effect sfx returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
if GetHandleId(node.effect) == GetHandleId(sfx) then
call node.remove()
exitwhen true
endif
set node = node.next
endloop
endmethod
method setColor takes integer red, integer green, integer blue returns nothing
call BlzSetSpecialEffectColor(effect, red, green, blue)
endmethod
/* -------------------------- Contructor/Destructor ------------------------- */
method destroy takes nothing returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
call node.remove()
set node = node.next
endloop
call DestroyEffect(effect)
call attachments.deallocate()
set effect = null
set path = null
set size = 1.
call deallocate()
endmethod
static method create takes real x, real y, real z returns thistype
local thistype this = thistype.allocate()
set effect = AddSpecialEffect("", x, y)
set path = ""
set size = 1
set time = 0
set transparency = 0
set animtype = 0
set playercolor = 0
set attachments = Effect.create()
call BlzSetSpecialEffectZ(effect, z)
return this
endmethod
endstruct
endlibrary
library MissileUtils requires Missiles, Alloc
/* -------------------- Missile Utils v2.6 by Chopinski -------------------- */
// This is a simple Utils library for the Relativistic Missiles system.
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module LinkedList
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method pushBack takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pushFront takes thistype node returns thistype
set node.prev = this
set node.next = next
set next.prev = node
set next = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct MGroup extends array
implement LinkedList
implement Alloc
Missiles missile
method remove takes nothing returns nothing
call pop()
call deallocate()
endmethod
method insert takes Missiles m returns thistype
local thistype node = pushBack(allocate())
set node.missile = m
return node
endmethod
static method create takes nothing returns thistype
return thistype(allocate()).init()
endmethod
endstruct
struct MissileGroup
MGroup group
integer size
method destroy takes nothing returns nothing
call group.deallocate()
call deallocate()
endmethod
method missileAt takes integer i returns Missiles
local MGroup node = group.next
local integer j = 0
if size > 0 and i <= size - 1 then
loop
exitwhen j == i
set node = node.next
set j = j + 1
endloop
return node.missile
else
return 0
endif
endmethod
method remove takes Missiles missile returns nothing
local MGroup node = group.next
loop
exitwhen node == group
if node.missile == missile then
set size = size - 1
call node.remove()
exitwhen true
endif
set node = node.next
endloop
endmethod
method insert takes Missiles missile returns nothing
set size = size + 1
call group.insert(missile)
endmethod
method clear takes nothing returns nothing
local MGroup node = group.next
loop
exitwhen node == group
call node.remove()
set node = node.next
endloop
set size = 0
endmethod
method contains takes Missiles missile returns boolean
local MGroup node = group.next
local boolean found = false
loop
exitwhen node == group
if node.missile == missile then
set found = true
exitwhen true
endif
set node = node.next
endloop
return found
endmethod
method addGroup takes MissileGroup source returns nothing
local MGroup node = source.group.next
loop
exitwhen node == source.group
if not contains(node.missile) then
call insert(node.missile)
endif
set node = node.next
endloop
endmethod
method removeGroup takes MissileGroup source returns nothing
local MGroup node = source.group.next
loop
exitwhen node == source.group
if contains(node.missile) then
call remove(node.missile)
endif
set node = node.next
endloop
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set group = MGroup.create()
set size = 0
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function CreateMissileGroup takes nothing returns MissileGroup
return MissileGroup.create()
endfunction
function DestroyMissileGroup takes MissileGroup missiles returns nothing
if missiles != 0 then
call missiles.clear()
call missiles.destroy()
endif
endfunction
function MissileGroupGetSize takes MissileGroup missiles returns integer
if missiles != 0 then
return missiles.size
else
return 0
endif
endfunction
function GroupMissileAt takes MissileGroup missiles, integer position returns Missiles
if missiles != 0 then
return missiles.missileAt(position)
else
return 0
endif
endfunction
function ClearMissileGroup takes MissileGroup missiles returns nothing
if missiles != 0 then
call missiles.clear()
endif
endfunction
function IsMissileInGroup takes Missiles missile, MissileGroup missiles returns boolean
if missiles != 0 and missile != 0 then
if missiles.size > 0 then
return missiles.contains(missile)
else
return false
endif
else
return false
endif
endfunction
function GroupRemoveMissile takes MissileGroup missiles, Missiles missile returns nothing
if missiles != 0 and missile != 0 then
if missiles.size > 0 then
call missiles.remove(missile)
endif
endif
endfunction
function GroupAddMissile takes MissileGroup missiles, Missiles missile returns nothing
if missiles != 0 and missile != 0 then
if not missiles.contains(missile) then
call missiles.insert(missile)
endif
endif
endfunction
function GroupPickRandomMissile takes MissileGroup missiles returns Missiles
if missiles != 0 then
if missiles.size > 0 then
return missiles.missileAt(GetRandomInt(0, missiles.size - 1))
else
return 0
endif
else
return 0
endif
endfunction
function FirstOfMissileGroup takes MissileGroup missiles returns Missiles
if missiles != 0 then
if missiles.size > 0 then
return missiles.group.next.missile
else
return 0
endif
else
return 0
endif
endfunction
function GroupAddMissileGroup takes MissileGroup source, MissileGroup destiny returns nothing
if source != 0 and destiny != 0 then
if source.size > 0 and source != destiny then
call destiny.addGroup(source)
endif
endif
endfunction
function GroupRemoveMissileGroup takes MissileGroup source, MissileGroup destiny returns nothing
if source != 0 and destiny != 0 then
if source == destiny then
call source.clear()
elseif source.size > 0 then
call destiny.removeGroup(source)
endif
endif
endfunction
function GroupEnumMissilesOfType takes MissileGroup missiles, integer whichType returns nothing
local integer i
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if missile.type == whichType then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfTypeCounted takes MissileGroup missiles, integer whichType, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if missile.type == whichType then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfPlayer takes MissileGroup missiles, player p returns nothing
local integer i
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if missile.owner == p then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfPlayerCounted takes MissileGroup missiles, player p, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if missile.owner == p then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRect takes MissileGroup missiles, rect r returns nothing
local integer i
local Missiles missile
if missiles != 0 and r != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if GetRectMinX(r) <= missile.x and missile.x <= GetRectMaxX(r) and GetRectMinY(r) <= missile.y and missile.y <= GetRectMaxY(r) then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRectCounted takes MissileGroup missiles, rect r, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and r != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if GetRectMinX(r) <= missile.x and missile.x <= GetRectMaxX(r) and GetRectMinY(r) <= missile.y and missile.y <= GetRectMaxY(r) then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeOfLoc takes MissileGroup missiles, location loc, real radius returns nothing
local real dx
local real dy
local integer i
local Missiles missile
if missiles != 0 and radius > 0 and loc != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
set dx = missile.x - GetLocationX(loc)
set dy = missile.y - GetLocationY(loc)
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeOfLocCounted takes MissileGroup missiles, location loc, real radius, integer amount returns nothing
local real dx
local real dy
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and radius > 0 and loc != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
set dx = missile.x - GetLocationX(loc)
set dy = missile.y - GetLocationY(loc)
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRange takes MissileGroup missiles, real x, real y, real radius returns nothing
local real dx
local real dy
local integer i
local Missiles missile
if missiles != 0 and radius > 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeCounted takes MissileGroup missiles, real x, real y, real radius, integer amount returns nothing
local real dx
local real dy
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and radius > 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
/* -------------------------------------------------------------------------- */
/* GUI API */
/* -------------------------------------------------------------------------- */
function PickedMissile takes nothing returns nothing
set udg_Missile = GroupMissileAt(udg_MissileGroup, udg_MissileAt)
endfunction
function MissileDestroyGroup takes nothing returns nothing
call DestroyMissileGroup(udg_MissileGroup)
endfunction
function MissilesInRange takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRange(udg_MissileGroup, GetLocationX(udg_MissileGroupLocation), GetLocationY(udg_MissileGroupLocation), udg_MissileGroupRange)
call RemoveLocation(udg_MissileGroupLocation)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesInRangeCounted takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRangeCounted(udg_MissileGroup, GetLocationX(udg_MissileGroupLocation), GetLocationY(udg_MissileGroupLocation), udg_MissileGroupRange, udg_MissileGroupCounted)
call RemoveLocation(udg_MissileGroupLocation)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesInRangeOfLoc takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRangeOfLoc(udg_MissileGroup, udg_MissileGroupLocation, udg_MissileGroupRange)
call RemoveLocation(udg_MissileGroupLocation)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesInRangeOfLocCounted takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRangeOfLocCounted(udg_MissileGroup, udg_MissileGroupLocation, udg_MissileGroupRange, udg_MissileGroupCounted)
call RemoveLocation(udg_MissileGroupLocation)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesInRect takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRect(udg_MissileGroup, udg_MissileGroupRect)
call RemoveRect(udg_MissileGroupRect)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesInRectCounted takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesInRectCounted(udg_MissileGroup, udg_MissileGroupRect, udg_MissileGroupCounted)
call RemoveRect(udg_MissileGroupRect)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesOfPlayer takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesOfPlayer(udg_MissileGroup, udg_MissileGroupPlayer)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesOfPlayerCounted takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesOfPlayerCounted(udg_MissileGroup, udg_MissileGroupPlayer, udg_MissileGroupCounted)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesOfType takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesOfType(udg_MissileGroup, udg_MissileGroupType)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissilesOfTypeCounted takes nothing returns nothing
set udg_MissileGroup = CreateMissileGroup()
call GroupEnumMissilesOfTypeCounted(udg_MissileGroup, udg_MissileGroupType, udg_MissileGroupCounted)
set udg_MissileGroupSize = MissileGroupGetSize(udg_MissileGroup)
endfunction
function MissileGroupClear takes nothing returns nothing
call ClearMissileGroup(udg_MissileGroup)
endfunction
function MissileGroupAdd takes nothing returns nothing
call GroupAddMissile(udg_MissileGroup, udg_Missile)
endfunction
function MissileGroupRemove takes nothing returns nothing
call GroupRemoveMissile(udg_MissileGroup, udg_Missile)
endfunction
function MissileGroupAddGroup takes nothing returns nothing
call GroupAddMissileGroup(udg_MissileGroupAddGroup, udg_MissileGroup)
endfunction
function MissileGroupRemoveGroup takes nothing returns nothing
call GroupRemoveMissileGroup(udg_MissileGroupRemoveGroup, udg_MissileGroup)
endfunction
endlibrary
library DummyRecycler /*
// DummyRecycler v1.25
// by Flux
//
// A system that recycles dummy units while considering their facing angle.
// It can be used as attachment dummies for visual effects or as dummy caster.
//
// Why is recycling a unit important?
// Because creating a unit is is one of the slowest function in the game
// and there are reports that will always leave a permanent tiny bit of
// memory (0.04 KB).
// On average, retrieving a pending Dummy is approximately 4x faster compared
// to creating a new one and recycling a Dummy compared to removing it is
// approximately 1.3x faster.
// Furthermore, if you're using a lot of "Unit has entered map" events,
// using this system will even result to even more better performance
// because retrieving Dummy units does not cause that event to run.
*/ requires /*
nothing
*/ optional Table/*
if not found, this system will use a hashtable. Hashtables are limited to
255 per map.
*/ optional WorldBounds /*
if not found, this system will initialize its own Map Boundaries.
//
//
// Features:
//
// -- Dummy Sharing
// When a Dummy List gets low on unit count, it will borrow Dummy Units
// from the Dummy List with the highest unit count. The transfer is not
// instant because the shared Dummy Unit has to turn to the appropriate
// angle of its new Dummy List before it can be recycled.
// See BORROW_REQUEST.
//
// -- Self-balancing recycling algorithm
// Recycled Dummy Units will be thrown to the List having the least number
// of Dummy Units.
//
// -- Recycling least used
// Allows recycling a Dummy from the Dummy List with the highest
// unit count. It is useful when the facing angle of the Dummy Unit
// does not matter.
// See GetRecycledDummyAnyAngle.
//
// -- Self-adaptation
// When there are no free Dummy Units from a Dummy List, it will end up creating
// a new unit instead but that unit will be permanently added as a Dummy
// Unit to be recycled increasing the overall total Dummy Unit count.
//
// -- Count control
// Allows limiting the overall number of Dummy Units.
// See MAX_DUMMY_COUNT.
//
// -- Delayed Recycle
// Allows recycling Dummy Units after some delay to allocate time for the
// death animation of Special Effects to be seen.
// See DummyAddRecycleTimer.
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
// function GetRecycledDummy takes real x, real y, real z, real facing returns unit
// - Retrieve an unused Dummy Unit from the List.
// - The equivalent of CreateUnit.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
// - Use this function if the facing angle of the Dummy doesn't matter to you.
// - It will return a unit from the list having the highest number of unused Dummy Units.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function RecycleDummy takes unit u returns nothing
// - Recycle the Dummy unit for it to be used again later.
// - The equivalent of RemoveUnit.
//
// function DummyAddRecycleTimer takes unit u, real time returns nothing
// - Recycle the Dummy unit after a certain time.
// - Use this to allocate time for the the death animation of an effect attached to the
// Dummy Unit to finish..
// - The equivalent of UnitApplyTimedLife.
//
// function ShowDummy takes unit u, boolean flag returns nothing
// - Shows/hides Dummy Unit without conflicting with the Locust ability.
//
//--------------------
// CREDITS
//--------------------
// Bribe - for the MissileRecycler (vJASS) where I got this concept from
// http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
// - for the optional Table
// http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
// Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
// http://www.wc3c.net/showthread.php?t=101150
// Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
// http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
// Nestharus - for the data structure
// http://www.hiveworkshop.com/forums/2809461-post7.html
// - for the optional WorldBounds
// http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== */
globals
//The rawcode of the Dummy Unit
private constant integer DUMMY_ID = 'dumi'
//The owner of the Dummy Unit
private constant player OWNER = Player(PLAYER_NEUTRAL_PASSIVE)
//The number of indexed angle. The higher the value the:
// - Lesser the turning time for the Dummy Units.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 10 (Max difference of 18 degrees)
private constant integer ANGLES_COUNT = 10
//The number of Dummy units per ANGLES_COUNT. The higher the value the:
// - Higher the number of units that can be recycled per angle, when
// no more units are in queue, the system will resort to use CreateUnit.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 3 to 5 (for less overhead in Map Loading Screen)
private constant integer STORED_UNIT_COUNT = 3
//The maximum number of Dummy units that can exist. When the system resort
//to using CreateUnit, the unit will be permanently added to the Dummy
//List. To avoid spamming Dummy Units and having too much free Dummy
//Units to allocate, the maximum number of Dummy Units is capped.
// Recommended Value: 80 to 120
private constant integer MAX_DUMMY_COUNT = 100
//When a certain angle have less than BORROW_REQUEST units in its list,
//it will start to borrow Dummy Units from the list with the highest
//Dummy Unit count.
// Recommended Value: Half of maximum STORED_UNIT_COUNT
private constant integer BORROW_REQUEST = 5
//It will only return a Dummy if the current dummy is close
//to it's appropriate facing angle. This is to avoid returning
//a Dummy which is still turning to face it's list angle.
private constant real ANGLE_TOLERANCE = 10.0
//An additional option to automatically hide recycled dummy units in the
//corner of the map camera bounds
private constant boolean HIDE_ON_MAP_CORNER = true
endglobals
//Every time a new dummy unit is retrieved, it will apply this resets
//If it is redundant/you dont need it, remove it.
//! textmacro DUMMY_UNIT_RESET
call SetUnitScale(bj_lastCreatedUnit, 1, 0, 0)
call SetUnitVertexColor(bj_lastCreatedUnit, 255, 255, 255, 255)
call SetUnitAnimationByIndex(bj_lastCreatedUnit, 90)
call ShowDummy(bj_lastCreatedUnit, true)
//! endtextmacro
// =============================================================== //
// ==================== END CONFIGURATION ======================== //
// =============================================================== //
globals
private integer dummyCount = ANGLES_COUNT*STORED_UNIT_COUNT
private real array angle
private integer array count
private integer array countHead
private integer array countNext
private integer array countPrev
private integer array next
private integer array prev
private unit array dummy
private integer upper
private integer lower
private integer lastInstance
private constant real FACING_OFFSET = 180.0/ANGLES_COUNT
endglobals
static if HIDE_ON_MAP_CORNER and not LIBRARY_WorldBounds then
private module BoundsInit
readonly static real x
readonly static real y
private static method onInit takes nothing returns nothing
local rect map = GetWorldBounds()
set thistype.x = GetRectMaxX(map)
set thistype.y = GetRectMaxY(map)
call RemoveRect(map)
set map = null
endmethod
endmodule
private struct Bounds extends array
implement BoundsInit
endstruct
endif
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable hash = InitHashtable()
endif
private static method onInit takes nothing returns nothing
local real add = 360.0/ANGLES_COUNT
local real a = 0
local integer this = ANGLES_COUNT
local integer head = 0
local integer cHead = JASS_MAX_ARRAY_SIZE - 1 //avoid allocation collision
local integer i = R2I(MAX_DUMMY_COUNT/ANGLES_COUNT + 0.5)
set upper = STORED_UNIT_COUNT
set lower = STORED_UNIT_COUNT
static if LIBRARY_Table then
set tb = Table.create()
endif
//Initialize countHeads
loop
exitwhen i < 0
set countNext[cHead] = cHead
set countPrev[cHead] = cHead
set countHead[i] = cHead
set cHead = cHead - 1
set i = i - 1
endloop
set cHead = countHead[STORED_UNIT_COUNT] //All heads will be inserted here initially
//Create the Dummy units
loop
exitwhen a >= 360
//Initialize head
set next[head] = head
set prev[head] = head
set count[head] = STORED_UNIT_COUNT
set angle[head] = a
//Insert head in the Count List
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
set i = 0
loop
exitwhen i >= STORED_UNIT_COUNT
//Queued Linked List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, a)
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, Bounds.x, Bounds.y, a)
endif
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, 0, 0, a)
endif
call PauseUnit(dummy[this], true)
static if LIBRARY_Table then
set tb[GetHandleId(dummy[this])] = this
else
call SaveInteger(hash, GetHandleId(dummy[this]), 0, this)
endif
set this = this + 1
set i = i + 1
endloop
set head = head + 1
set a = a + add
endloop
set lastInstance = this
endmethod
endmodule
private struct S extends array
implement M
endstruct
private function GetHead takes integer facing returns integer
if facing < 0 or facing >= 360 then
set facing = facing - (facing/360)*360
if facing < 0 then
set facing = facing + 360
endif
endif
return R2I((facing*ANGLES_COUNT/360.0))
endfunction
function ShowDummy takes unit u, boolean flag returns nothing
if IsUnitHidden(u) == flag then
call ShowUnit(u, flag)
if flag and GetUnitTypeId(u) == DUMMY_ID then
call UnitRemoveAbility(u, 'Aloc')
call UnitAddAbility(u, 'Aloc')
endif
endif
endfunction
function GetRecycledDummy takes real x, real y, real z, real facing returns unit
local integer head = GetHead(R2I(facing + FACING_OFFSET))
local integer this = next[head]
local integer cHead
//If there are Dummy Units in the Queue List already facing close to the appropriate angle
if this != head and RAbsBJ(GetUnitFacing(dummy[this]) - angle[head]) <= ANGLE_TOLERANCE then
//Remove from the Queue List
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//For double free protection
set next[this] = -1
//Unit Properties
set bj_lastCreatedUnit = dummy[this]
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFacing(bj_lastCreatedUnit, facing)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
//! runtextmacro DUMMY_UNIT_RESET()
//Update Count and Bounds
set count[head] = count[head] - 1
//------------------------------------------------
// Unit Sharing
//------------------------------------------------
if count[head] < BORROW_REQUEST and count[countNext[countHead[upper]]] > count[head] then
set count[head] = count[head] + 1
set this = next[countNext[countHead[upper]]]
call SetUnitFacing(dummy[this], angle[head])
//Remove
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//Add to the Current List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
set head = countNext[countHead[upper]]
set count[head] = count[head] - 1
endif
//---------------------------
//Update Count Lists
//---------------------------
//Remove from the current Count List
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[upper]
if countNext[cHead] == cHead then
set upper = upper - 1
endif
if count[head] < lower then
set lower = count[head]
endif
else
set bj_lastCreatedUnit = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
call PauseUnit(bj_lastCreatedUnit, true)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
if dummyCount < MAX_DUMMY_COUNT then
set this = lastInstance
//For double free protection
set next[this] = -1
set dummy[this] = bj_lastCreatedUnit
static if LIBRARY_Table then
set S.tb[GetHandleId(bj_lastCreatedUnit)] = this
else
call SaveInteger(S.hash, GetHandleId(bj_lastCreatedUnit), 0, this)
endif
set lastInstance = lastInstance + 1
endif
set dummyCount = dummyCount + 1
endif
return bj_lastCreatedUnit
endfunction
function RecycleDummy takes unit u returns nothing
static if LIBRARY_Table then
local integer this = S.tb[GetHandleId(u)]
else
local integer this = LoadInteger(S.hash, GetHandleId(u), 0)
endif
local integer head
local integer cHead
//If the unit is a legit Dummy Unit
if this > 0 and next[this] == -1 then
//Find where to insert based on the list having the least number of units
set head = countNext[countHead[lower]]
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
//Update Status
call SetUnitFacing(u, angle[head])
call PauseUnit(u, true)
call SetUnitOwner(u, OWNER, false)
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
call SetUnitX(u, WorldBounds.maxX)
call SetUnitY(u, WorldBounds.maxY)
else
call SetUnitX(u, Bounds.x)
call SetUnitY(u, Bounds.y)
endif
else
call SetUnitScale(u, 0, 0, 0)
call SetUnitVertexColor(u, 0, 0, 0, 0)
endif
set count[head] = count[head] + 1
//---------------------------
// Update Count Lists
//---------------------------
//Remove
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[lower]
if countNext[cHead] == cHead then
set lower = lower + 1
endif
if count[head] > upper then
set upper = count[head]
endif
elseif this == 0 then
call RemoveUnit(u)
debug elseif next[this] != -1 then
debug call BJDebugMsg("|cffffcc00[DummyRecycler]:|r Attempted to recycle a pending/free Dummy Unit.")
endif
endfunction
private function Expires takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
static if LIBRARY_Table then
call RecycleDummy(S.tb.unit[id])
call S.tb.unit.remove(id)
else
call RecycleDummy(LoadUnitHandle(S.hash, id, 0))
call FlushChildHashtable(S.hash, id)
endif
call DestroyTimer(t)
set t = null
endfunction
function DummyAddRecycleTimer takes unit u, real time returns nothing
local timer t = CreateTimer()
static if LIBRARY_Table then
set S.tb.unit[GetHandleId(t)] = u
else
call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
endif
call TimerStart(t, time, false, function Expires)
set t = null
endfunction
function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
endfunction
// runtextmacro DUMMY_DEBUG_TOOLS()
endlibrary
library Missiles requires WorldBounds, TimerUtils optional DummyRecycler
/* ----------------------- Missiles v2.6 by Chopinski ----------------------- */
// Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
// this Missiles library. Credits to Vexorian for the dummy model.
// How to Import:
// 1 -First copy the Missile dummy unit into your map and then import the dummy.mdx
// model, setting the missile dummy model path to imported dummy.mdx model.
// Dummy model: https://www.hiveworkshop.com/threads/vexorians-dummy-model.149230/
// WorldBounds: https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
// DummyRecycler: https://www.hiveworkshop.com/threads/dummy-recycler-v1-25.277659/ (Highly Recommended)
// 2 - Copy this library into your map and set the
// DUMMY_RAW_CODE to the raw code of the missile dummy (ctrl + d) and you
// are done
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The update period of the system
public constant real PERIOD = 1./40.
// The max amount of Missiles processed in a PERIOD
// You can play around with both these values to find
// your sweet spot. If equal to 0, the system will
// process all missiles at once every period.
public constant real SWEET_SPOT = 100
// the avarage collision size compensation when detecting
// collisions
private constant real COLLISION_SIZE = 128.
// item size used in z collision
private constant real ITEM_SIZE = 16.
// The raw code of the dummy unit.
private constant integer DUMMY = 'dumi'
// How long takes for the missile to be removed.
// This is necessary so the death animation of the
// effect can play through
private constant real RECYCLE_TIME = 2.
// Needed, don't touch.
private location LOC = Location(0., 0.)
private hashtable table = InitHashtable()
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
private function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
private constant function GetUnitCollisionSize takes unit u returns real
return 64.
endfunction
private function GetMapCliffLevel takes nothing returns integer
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
endfunction
private struct Pool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
timer timer
unit unit
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call ReleaseTimer(timer)
call RemoveUnit(unit)
call deallocate()
set timer = null
set unit = null
endmethod
static method recycle takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
static method retrieve takes real x, real y, real z, real face returns unit
set bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
call SetUnitZ(bj_lastCreatedUnit, z)
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amrf')
return bj_lastCreatedUnit
endmethod
endstruct
private struct Coordinates
readonly real x
readonly real y
readonly real z
readonly real angle
readonly real distance
readonly real square
readonly real slope
readonly real alpha
// Creates an origin - impact link.
private thistype ref
private static method math takes thistype a, thistype b returns nothing
local real dx
local real dy
loop
set dx = b.x - a.x
set dy = b.y - a.y
set dx = dx*dx + dy*dy
set dy = SquareRoot(dx)
exitwhen dx != 0. and dy != 0.
set b.x = b.x + .01
set b.z = b.z - GetLocZ(b.x -.01, b.y) + GetLocZ(b.x, b.y)
endloop
set a.square = dx
set a.distance = dy
set a.angle = Atan2(b.y - a.y, b.x - a.x)
set a.slope = (b.z - a.z)/dy
set a.alpha = Atan(a.slope)*bj_RADTODEG
// Set b.
if b.ref == a then
set b.angle = a.angle + bj_PI
set b.distance = dy
set b.slope = -a.slope
set b.alpha = -a.alpha
set b.square = dx
endif
endmethod
static method link takes thistype a, thistype b returns nothing
set a.ref = b
set b.ref = a
call math(a, b)
endmethod
method move takes real toX, real toY, real toZ returns nothing
set x = toX
set y = toY
set z = toZ + GetLocZ(toX, toY)
if ref != this then
call math(this, ref)
endif
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
static method create takes real x, real y, real z returns Coordinates
local thistype this = thistype.allocate()
set ref = this
call move(x, y, z)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module OnHit
set o = origin
set h = height
set c = open
set d = o.distance
call setup()
if onHit != null then
set udg_MissileEvent = udg_MissileOnHit
if allocated and udg_MissileCollision > 0 then
call GroupEnumUnitsInRange(group, x, y, udg_MissileCollision + COLLISION_SIZE, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if not HaveSavedBoolean(table, this, GetHandleId(u)) then
if IsUnitInRangeXY(u, x, y, udg_MissileCollision) then
if udg_MissileCollideZ then
set dx = GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
set dy = GetUnitCollisionSize(u)
if dx + dy >= z - udg_MissileCollision and dx <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
else
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
endif
endif
call GroupRemoveUnit(group, u)
endloop
endif
endif
endmodule
private module OnMissile
if onMissile != null then
set udg_MissileEvent = udg_MissileOnMissile
if allocated and udg_MissileCollision > 0 then
set k = 0
loop
exitwhen k > count
set missile = collection[k]
if missile != this then
if not HaveSavedBoolean(table, this, missile) then
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= udg_MissileCollision then
call SaveBoolean(table, this, missile, true)
set udg_MissileHitMissile = missile
if allocated and IsTriggerEnabled(onMissile) then
set udg_Missile = this
if TriggerEvaluate(onMissile) then
call TriggerExecute(onMissile)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitMissile = 0
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitMissile = 0
endif
endif
endif
set k = k + 1
endloop
endif
endif
endmodule
private module OnDestructable
if onDestructable != null then
set udg_MissileEvent = udg_MissileOnDestructable
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumDestructablesInRect(rect, null, function thistype.onDest)
endif
endif
endmodule
private module OnItem
if onItem != null then
set udg_MissileEvent = udg_MissileOnItem
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumItemsInRect(rect, null, function thistype.onItems)
endif
endif
endmodule
private module OnCliff
if onCliff != null then
set dx = GetTerrainCliffLevel(nextX, nextY)
set dy = GetTerrainCliffLevel(x, y)
set udg_MissileEvent = udg_MissileOnCliff
if dy < dx and z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if allocated and IsTriggerEnabled(onCliff) then
set udg_Missile = this
if TriggerEvaluate(onCliff) then
call TriggerExecute(onCliff)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTerrain
if onTerrain != null then
set udg_MissileEvent = udg_MissileOnTerrain
if GetLocZ(x, y) > z then
if allocated and IsTriggerEnabled(onTerrain) then
set udg_Missile = this
if TriggerEvaluate(onTerrain) then
call TriggerExecute(onTerrain)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTileset
if onTileset != null then
set udg_MissileTileset = GetTerrainType(x, y)
set udg_MissileEvent = udg_MissileOnTileset
if udg_MissileTileset != tileset then
if allocated and IsTriggerEnabled(onTileset) then
set udg_Missile = this
if TriggerEvaluate(onTileset) then
call TriggerExecute(onTileset)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
set tileset = udg_MissileTileset
set udg_MissileTileset = 0
endif
endmodule
private module OnPeriod
if onPeriod != null then
set udg_MissileEvent = udg_MissileOnPeriod
if allocated and IsTriggerEnabled(onPeriod) then
set udg_Missile = this
if TriggerEvaluate(onPeriod) then
call TriggerExecute(onPeriod)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnOrient
// Homing or not
if udg_MissileTarget != null and GetUnitTypeId(udg_MissileTarget) != 0 then
call impact.move(GetUnitX(udg_MissileTarget), GetUnitY(udg_MissileTarget), GetUnitFlyHeight(udg_MissileTarget) + toZ)
set dx = impact.x - nextX
set dy = impact.y - nextY
set a = Atan2(dy, dx)
set travel = o.distance - SquareRoot(dx*dx + dy*dy)
else
set a = o.angle
set target = null
set udg_MissileTarget = null
endif
// turn rate
if turn != 0 and not (Cos(cA-a) >= Cos(turn)) then
if Sin(a-cA) >= 0 then
set cA = cA + turn
else
set cA = cA - turn
endif
else
set cA = a
endif
set vel = veloc*dilation
set yaw = cA*bj_RADTODEG
set s = travel + vel
set veloc = veloc + acceleration
set travel = s
set pitch = origin.alpha
set prevX = x
set prevY = y
set prevZ = z
set x = nextX
set y = nextY
set z = nextZ
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
// arc calculation
if h != 0 or o.slope != 0 then
set nextZ = 4*h*s*(d-s)/(d*d) + o.slope*s + o.z
set pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))*bj_RADTODEG
endif
// curve calculation
if c != 0 then
set dx = 4*c*s*(d-s)/(d*d)
set a = cA + bj_PI/2
set x = x + dx*Cos(a)
set y = y + dx*Sin(a)
set yaw = (cA + Atan(-((4*c)*(2*s - d))/(d*d)))*bj_RADTODEG
endif
endmodule
private module OnFinish
if s >= d then
set finished = true
if onFinish != null then
set udg_MissileEvent = udg_MissileOnFinish
if allocated and IsTriggerEnabled(onFinish) then
set udg_Missile = this
if TriggerEvaluate(onFinish) then
call TriggerExecute(onFinish)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if travel > 0 and not paused then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
call terminate()
endif
endif
call SetUnitAnimationByIndex(dummy, R2I(pitch + 90.5))
call SetUnitFacing(dummy, yaw)
endmodule
private module OnBoundaries
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call SetUnitZ(dummy, z)
else
if onBoundaries != null then
set udg_MissileEvent = udg_MissileOnBoundaries
if allocated and IsTriggerEnabled(onBoundaries) then
set udg_Missile = this
if TriggerEvaluate(onBoundaries) then
call TriggerExecute(onBoundaries)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
call cleanup()
endmodule
private module OnPause
set pid = pid + 1
set pkey = pid
set frozen[pid] = this
set udg_MissilePaused = paused
if onPause != null then
set udg_MissileEvent = udg_MissileOnPause
if allocated and IsTriggerEnabled(onPause) then
call setup()
if TriggerEvaluate(onPause) then
call TriggerExecute(onPause)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnResume
local thistype aux
set paused = flag
set udg_MissilePaused = flag
if not paused and pkey != -1 then
set id = id + 1
set missiles[id] = this
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
if onResume != null then
set udg_MissileEvent = udg_MissileOnResume
if allocated and IsTriggerEnabled(onResume) then
call setup()
if TriggerEvaluate(onResume) then
call TriggerExecute(onResume)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if finished then
call terminate()
endif
endif
endif
endif
else
if finished then
call terminate()
endif
endif
endif
endmodule
private module OnRemove
local thistype aux
if allocated and launched then
set allocated = false
if pkey != -1 then
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
endif
if onRemove != null then
set udg_MissileEvent = udg_MissileOnRemove
if IsTriggerEnabled(onRemove) then
set udg_Missile = this
if TriggerEvaluate(onRemove) then
call TriggerExecute(onRemove)
call update()
endif
endif
endif
set aux = collection[count]
set aux.index = index
set collection[index] = collection[count]
set count = count - 1
set index = -1
set onPeriod = null
set onHit = null
set onMissile = null
set onItem = null
set onDestructable = null
set onCliff = null
set onTerrain = null
set onTileset = null
set onFinish = null
set onBoundaries = null
set onResume = null
set onPause = null
set onRemove = null
static if LIBRARY_DummyRecycler then
call SetUnitOwner(dummy, Player(PLAYER_NEUTRAL_PASSIVE), false)
call DummyAddRecycleTimer(dummy, RECYCLE_TIME)
else
call Pool.recycle(dummy, RECYCLE_TIME)
endif
call origin.destroy()
call impact.destroy()
call DestroyEffect(effect)
call reset()
call FlushChildHashtable(table, this)
endif
endmodule
private module Operators
/* -------------------------- Model of the missile -------------------------- */
method operator model= takes string fxpath returns nothing
call DestroyEffect(effect)
set path = fxpath
set effect = AddSpecialEffectTarget(fxpath, dummy, "origin")
endmethod
method operator model takes nothing returns string
return path
endmethod
/* ----------------------------- Curved movement ---------------------------- */
method operator curve= takes real value returns nothing
set open = Tan(value*bj_DEGTORAD)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)*bj_RADTODEG
endmethod
/* ----------------------------- Arced Movement ----------------------------- */
method operator arc= takes real value returns nothing
set height = Tan(value*bj_DEGTORAD)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)*bj_RADTODEG
endmethod
/* ------------------------------ Effect scale ------------------------------ */
method operator scale= takes real v returns nothing
call SetUnitScale(dummy, v, v, v)
set size = v
endmethod
method operator scale takes nothing returns real
return size
endmethod
/* ------------------------------ Missile Speed ----------------------------- */
method operator speed= takes real newspeed returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = newspeed*PERIOD
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator speed takes nothing returns real
return veloc/PERIOD
endmethod
/* ------------------------------- Flight Time ------------------------------ */
method operator duration= takes real flightTime returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = RMaxBJ(0.00000001, (origin.distance - travel)*PERIOD/RMaxBJ(0.00000001, flightTime))
set time = flightTime
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator duration takes nothing returns real
return time
endmethod
/* ------------------------------- Sight Range ------------------------------ */
method operator vision= takes real sightRange returns nothing
set sight = sightRange
if owner == null then
if source != null then
call SetUnitOwner(dummy, GetOwningPlayer(source), false)
endif
else
call SetUnitOwner(dummy, owner, false)
endif
endmethod
method operator vision takes nothing returns real
return sight
endmethod
endmodule
private module Methods
/* --------------------------- Bounce and Deflect --------------------------- */
method bounce takes nothing returns nothing
call origin.move(x, y, z - GetLocZ(x, y))
set travel = 0
set finished = false
endmethod
method deflect takes real tx, real ty, real tz returns nothing
local real locZ = GetLocZ(x, y)
set udg_MissileTarget = null
set target = null
set toZ = tz
if z < locZ then
set nextX = prevX
set nextY = prevY
set nextZ = prevZ
endif
call impact.move(tx, ty, tz)
call origin.move(x, y, z - locZ)
set travel = 0
set finished = false
endmethod
method deflectTarget takes unit u returns nothing
call deflect(GetUnitX(u), GetUnitY(u), toZ)
set target = u
set udg_MissileTarget = u
endmethod
/* ---------------------------- Flush hit targets --------------------------- */
method flushAll takes nothing returns nothing
call FlushChildHashtable(table, this)
endmethod
method flush takes widget w returns nothing
if w != null then
call RemoveSavedBoolean(table, this, GetHandleId(w))
endif
endmethod
method hitted takes widget w returns boolean
return HaveSavedBoolean(table, this, GetHandleId(w))
endmethod
/* ------------------------------ Missile Pause ----------------------------- */
method pause takes boolean flag returns nothing
implement OnResume
endmethod
/* ---------------------- Destructable collision method --------------------- */
static method onDest takes nothing returns nothing
local thistype this = temp
local destructable d = GetEnumDestructable()
local real dz
local real tz
if not HaveSavedBoolean(table, this, GetHandleId(d)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetWidgetX(d), GetWidgetY(d))
set tz = GetDestructableOccluderHeight(d)
if dz + tz >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
else
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
endif
set d = null
endmethod
/* -------------------------- Item collision method ------------------------- */
static method onItems takes nothing returns nothing
local thistype this = temp
local item i = GetEnumItem()
local real dz
if not HaveSavedBoolean(table, this, GetHandleId(i)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetItemX(i), GetItemY(i))
if dz + ITEM_SIZE >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
else
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
endif
set i = null
endmethod
/* -------------------------------- Terminate ------------------------------- */
method terminate takes nothing returns nothing
implement OnRemove
endmethod
/* ------------------------------- GUI Update ------------------------------- */
method setup takes nothing returns nothing
set udg_Missile = this
set udg_MissileStart = Location(origin.x, origin.y)
set udg_MissileStartZ = origin.z
set udg_MissileFinish = Location(impact.x, impact.y)
set udg_MissileFinishZ = impact.z
set udg_MissileTarget = target
set udg_MissileSource = source
set udg_MissileOwner = owner
set udg_MissilePaused = paused
set udg_MissileType = type
set udg_MissileData = data
set udg_MissileModel = path
set udg_MissileScale = size
set udg_MissileDamage = damage
set udg_MissileCollision = collision
set udg_MissileCollideZ = collideZ
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
set udg_MissileDuration = time
set udg_MissileArc = arc
set udg_MissileCurve = curve
set udg_MissileAcceleration = acceleration
set udg_MissileVision = sight
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endmethod
method update takes nothing returns nothing
if not paused then
set damage = udg_MissileDamage
set collision = udg_MissileCollision
set acceleration = udg_MissileAcceleration
set collideZ = udg_MissileCollideZ
set source = udg_MissileSource
set target = udg_MissileTarget
set owner = udg_MissileOwner
set type = udg_MissileType
set data = udg_MissileData
if path != udg_MissileModel then
set model = udg_MissileModel
endif
if size != udg_MissileScale then
set scale = udg_MissileScale
endif
if speed != udg_MissileSpeed then
set speed = udg_MissileSpeed
endif
if time != udg_MissileDuration then
set duration = udg_MissileDuration
endif
if arc != udg_MissileArc then
set arc = udg_MissileArc
endif
if curve != udg_MissileCurve then
set curve = udg_MissileCurve
endif
if sight != udg_MissileVision then
set vision = udg_MissileVision
endif
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endif
endmethod
method cleanup takes nothing returns nothing
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_Missile = 0
set udg_MissileStart = null
set udg_MissileStartZ = 0
set udg_MissileFinish = null
set udg_MissileFinishZ = 0
set udg_MissileTarget = null
set udg_MissileSource = null
set udg_MissileOwner = null
set udg_MissilePaused = false
set udg_MissileType = 0
set udg_MissileData = 0
set udg_MissileModel = ""
set udg_MissileScale = 0
set udg_MissileDamage = 0
set udg_MissileCollision = 0
set udg_MissileCollideZ = false
set udg_MissileVelocity = 0
set udg_MissileTravelled = 0
set udg_MissileSpeed = 0
set udg_MissileDuration = 0
set udg_MissileArc = 0
set udg_MissileCurve = 0
set udg_MissileAcceleration = 0
set udg_MissileVision = 0
set udg_MissilePosition = null
set udg_MissileZ = 0
set udg_MissileLastPosition = null
set udg_MissilePrevZ = 0
set udg_MissileNextPosition = null
set udg_MissileNextZ = 0
endmethod
endmodule
struct Missiles
private static timer timer = CreateTimer()
private static group group = CreateGroup()
private static rect rect = Rect(0., 0., 0., 0.)
private static hashtable table = InitHashtable()
private static integer last = 0
private static thistype temp = 0
private static integer id = -1
private static integer pid = -1
private static real dilation = 1
private static thistype array missiles
private static thistype array frozen
readonly static thistype array collection
readonly static integer count = -1
private real cA
private effect effect
private string path
private real size
private real height
private real open
private real toZ
private real time
private real sight
private integer pkey
private integer index
Coordinates impact
Coordinates origin
readonly real x
readonly real y
readonly real z
readonly real prevX
readonly real prevY
readonly real prevZ
readonly real nextX
readonly real nextY
readonly real nextZ
readonly real turn
readonly real veloc
readonly real travel
readonly unit dummy
readonly boolean launched
readonly boolean allocated
readonly boolean finished
readonly boolean paused
readonly integer tileset
unit source
unit target
player owner
boolean collideZ
real collision
real damage
real acceleration
integer data
integer type
trigger onPeriod = null
trigger onHit = null
trigger onMissile = null
trigger onItem = null
trigger onDestructable = null
trigger onCliff = null
trigger onTerrain = null
trigger onTileset = null
trigger onFinish = null
trigger onBoundaries = null
trigger onResume = null
trigger onPause = null
trigger onRemove = null
implement Operators
implement Methods
/* ------------------------------ Reset members ----------------------------- */
private method reset takes nothing returns nothing
set launched = false
set finished = false
set collideZ = false
set paused = false
set source = null
set target = null
set owner = null
set effect = null
set dummy = null
set path = ""
set open = 0.
set height = 0.
set veloc = 0.
set acceleration = 0.
set collision = 0.
set damage = 0.
set travel = 0.
set turn = 0.
set size = 0.
set time = 0.
set sight = 0.
set data = 0
set type = 0
set tileset = 0
set pkey = -1
set index = -1
endmethod
/* -------------------------- Destroys the missile -------------------------- */
private method remove takes integer i returns integer
if paused then
implement OnPause
else
implement OnRemove
endif
set missiles[i] = missiles[id]
set id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1
endif
if id == -1 then
call PauseTimer(timer)
endif
if not allocated then
call deallocate()
endif
return i - 1
endmethod
/* ---------------------------- Missiles movement --------------------------- */
private static method move takes nothing returns nothing
local integer j = 0
local integer i
local integer k
local unit u
local real a
local real d
local real s
local real h
local real c
local real dx
local real dy
local real vel
local real yaw
local real pitch
local Missiles missile
local Coordinates o
local thistype this
if SWEET_SPOT > 0 then
set i = last
else
set i = 0
endif
loop
exitwhen ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id)
set this = missiles[i]
set temp = this
if allocated and not paused then
implement OnHit
implement OnMissile
implement OnDestructable
implement OnItem
implement OnCliff
implement OnTerrain
implement OnTileset
implement OnPeriod
implement OnOrient
implement OnFinish
implement OnBoundaries
else
set i = remove(i)
set j = j - 1
endif
set i = i + 1
set j = j + 1
if i > id and SWEET_SPOT > 0 then
set i = 0
endif
endloop
set last = i
set u = null
endmethod
/* --------------------------- Launch the Missile --------------------------- */
method launch takes nothing returns nothing
if not launched and allocated then
set launched = true
set id = id + 1
set missiles[id] = this
set count = count + 1
set index = count
set collection[count] = this
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
endif
endmethod
/* --------------------------- Main Creator method -------------------------- */
static method create takes real x, real y, real z, real toX, real toY, real toZ returns thistype
local thistype this = thistype.allocate()
local real face = Atan2(toY - y, toX - x)*bj_RADTODEG
call .reset()
set .origin = Coordinates.create(x, y, z)
set .impact = Coordinates.create(toX, toY, toZ)
call Coordinates.link(origin, impact)
set .allocated = true
set .cA = origin.angle
set .x = x
set .y = y
set .z = impact.z
set .prevX = x
set .prevY = y
set .prevZ = impact.z
set .nextX = x
set .nextY = y
set .nextZ = impact.z
set .toZ = toZ
static if LIBRARY_DummyRecycler then
set .dummy = GetRecycledDummy(x, y, z, face)
else
set .dummy = Pool.retrieve(x, y, z, face)
endif
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* GUI API */
/* -------------------------------------------------------------------------- */
function MissileCreate takes nothing returns nothing
local Missiles missile = Missiles.create(GetLocationX(udg_MissileStart), GetLocationY(udg_MissileStart), udg_MissileStartZ, GetLocationX(udg_MissileFinish), GetLocationY(udg_MissileFinish), udg_MissileFinishZ)
if udg_MissileRemoveLocations then
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
else
set udg_MissileRemoveLocations = true
endif
set udg_Missile = missile
set udg_MissileStartZ = 0
set udg_MissileFinishZ = 0
set udg_MissileStart = null
set udg_MissileFinish = null
if udg_MissileModel != "" then
set missile.model = udg_MissileModel
set udg_MissileModel = ""
endif
if udg_MissileScale != 0 then
set missile.scale = udg_MissileScale
set udg_MissileScale = 0
endif
if udg_MissileSpeed != 0 then
set missile.speed = udg_MissileSpeed
set udg_MissileSpeed = 0
endif
if udg_MissileDuration != 0 then
set missile.duration = udg_MissileDuration
set udg_MissileDuration = 0
endif
if udg_MissileArc != 0 then
set missile.arc = udg_MissileArc
set udg_MissileArc = 0
endif
if udg_MissileCurve != 0 then
set missile.curve = udg_MissileCurve
set udg_MissileCurve = 0
endif
if udg_MissileDamage != 0 then
set missile.damage = udg_MissileDamage
set udg_MissileDamage = 0
endif
if udg_MissileCollision > 0 then
set missile.collision = udg_MissileCollision
set udg_MissileCollision = 0
endif
if udg_MissileAcceleration != 0 then
set missile.acceleration = udg_MissileAcceleration
set udg_MissileAcceleration = 0
endif
if udg_MissileCollideZ then
set missile.collideZ = udg_MissileCollideZ
set udg_MissileCollideZ = false
endif
if udg_MissileSource != null then
set missile.source = udg_MissileSource
set udg_MissileSource = null
endif
if udg_MissileTarget != null then
set missile.target = udg_MissileTarget
set udg_MissileTarget = null
endif
if udg_MissileOwner != null then
set missile.owner = udg_MissileOwner
set udg_MissileOwner = null
endif
if udg_MissileType != 0 then
set missile.type = udg_MissileType
set udg_MissileType = 0
endif
if udg_MissileData != 0 then
set missile.data = udg_MissileData
set udg_MissileData = 0
endif
if udg_MissileVision != 0 then
set missile.vision = udg_MissileVision
set udg_MissileVision = 0
endif
if udg_Missile_onPeriod != null then
set missile.onPeriod = udg_Missile_onPeriod
set udg_Missile_onPeriod = null
endif
if udg_Missile_onHit != null then
set missile.onHit = udg_Missile_onHit
set udg_Missile_onHit = null
endif
if udg_Missile_onDestructable != null then
set missile.onDestructable = udg_Missile_onDestructable
set udg_Missile_onDestructable = null
endif
if udg_Missile_onItem != null then
set missile.onItem = udg_Missile_onItem
set udg_Missile_onItem = null
endif
if udg_Missile_onMissile != null then
set missile.onMissile = udg_Missile_onMissile
set udg_Missile_onMissile = null
endif
if udg_Missile_onCliff != null then
set missile.onCliff = udg_Missile_onCliff
set udg_Missile_onCliff = null
endif
if udg_Missile_onTerrain != null then
set missile.onTerrain = udg_Missile_onTerrain
set udg_Missile_onTerrain = null
endif
if udg_Missile_onTileset != null then
set missile.onTileset = udg_Missile_onTileset
set udg_Missile_onTileset = null
endif
if udg_Missile_onFinish != null then
set missile.onFinish = udg_Missile_onFinish
set udg_Missile_onFinish = null
endif
if udg_Missile_onBoundaries != null then
set missile.onBoundaries = udg_Missile_onBoundaries
set udg_Missile_onBoundaries = null
endif
if udg_Missile_onResume != null then
set missile.onResume = udg_Missile_onResume
set udg_Missile_onResume = null
endif
if udg_Missile_onPause != null then
set missile.onPause = udg_Missile_onPause
set udg_Missile_onPause = null
endif
if udg_Missile_onRemove != null then
set missile.onRemove = udg_Missile_onRemove
set udg_Missile_onRemove = null
endif
call missile.launch()
endfunction
function MissileBounce takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.bounce()
endfunction
function MissileDeflectTarget takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflectTarget(udg_MissileDeflectTarget)
endfunction
function MissileDeflect takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflect(GetLocationX(udg_MissileDeflectPosition), GetLocationY(udg_MissileDeflectPosition), udg_MissileDeflectZ)
call RemoveLocation(udg_MissileDeflectPosition)
set udg_MissileDeflectPosition = null
endfunction
function MissileFlush takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flush(udg_MissileFlushUnit)
set udg_MissileFlushUnit = null
endfunction
function MissileFlushAll takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flushAll()
endfunction
function MissileHitted takes nothing returns nothing
local Missiles missile = udg_Missile
set udg_MissileHitted = missile.hitted(udg_MissileHittedUnit)
endfunction
function MissileAttach takes nothing returns nothing
//local Missiles missile = udg_Missile
//set bj_lastCreatedEffect = missile.attach(udg_MissileAttachModel, udg_MissileAttachX, udg_MissileAttachY, udg_MissileAttachZ, udg_MissileAttachScale)
endfunction
function MissileDetach takes nothing returns nothing
//local Missiles missile = udg_Missile
//call missile.detach(udg_MissileDetachEffect)
//set udg_MissileDetachEffect = null
endfunction
function MissilePause takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(true)
endfunction
function MissileResume takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(false)
endfunction
endlibrary
library Missiles requires MissileEffect
/* ----------------------- Missiles v2.6 by Chopinski ----------------------- */
// Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
// this Missiles library. Credits and thanks to AGD and for the effect orientation ideas.
// This version of Missiles requires patch 1.31+
// How to Import:
// 1 - Copy this and MissileEffect librarys into your map
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The update period of the system
public constant real PERIOD = 1./40.
// The max amount of Missiles processed in a PERIOD
// You can play around with both these values to find
// your sweet spot. If equal to 0, the system will
// process all missiles at once every period.
public constant real SWEET_SPOT = 100
// the avarage collision size compensation when detecting collisions
private constant real COLLISION_SIZE = 128.
// item size used in z collision
private constant real ITEM_SIZE = 16.
// Raw code of the dummy unit used for vision
private constant integer DUMMY = 'dumi'
// Needed, don't touch.
private location LOC = Location(0., 0.)
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
private function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
private function GetMapCliffLevel takes nothing returns integer
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
endfunction
private struct Pool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) == DUMMY then
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call PauseUnit(dummy, true)
endif
endmethod
static method retrieve takes real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call PauseUnit(bj_lastCreatedUnit, false)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitZ(bj_lastCreatedUnit, z)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face)
else
set bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
call SetUnitZ(bj_lastCreatedUnit, z)
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amrf')
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == SWEET_SPOT
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call PauseUnit(u, false)
call GroupAddUnit(group, u)
call UnitRemoveAbility(u, 'Amrf')
set i = i + 1
endloop
set u = null
endmethod
endstruct
private struct Coordinates
readonly real x
readonly real y
readonly real z
readonly real angle
readonly real distance
readonly real square
readonly real slope
readonly real alpha
// Creates an origin - impact link.
private thistype ref
private static method math takes thistype a, thistype b returns nothing
local real dx
local real dy
loop
set dx = b.x - a.x
set dy = b.y - a.y
set dx = dx*dx + dy*dy
set dy = SquareRoot(dx)
exitwhen dx != 0. and dy != 0.
set b.x = b.x + .01
set b.z = b.z - GetLocZ(b.x -.01, b.y) + GetLocZ(b.x, b.y)
endloop
set a.square = dx
set a.distance = dy
set a.angle = Atan2(b.y - a.y, b.x - a.x)
set a.slope = (b.z - a.z)/dy
set a.alpha = Atan(a.slope)
// Set b.
if b.ref == a then
set b.angle = a.angle + bj_PI
set b.distance = dy
set b.slope = -a.slope
set b.alpha = -a.alpha
set b.square = dx
endif
endmethod
static method link takes thistype a, thistype b returns nothing
set a.ref = b
set b.ref = a
call math(a, b)
endmethod
method move takes real toX, real toY, real toZ returns nothing
set x = toX
set y = toY
set z = toZ + GetLocZ(toX, toY)
if ref != this then
call math(this, ref)
endif
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
static method create takes real x, real y, real z returns Coordinates
local thistype this = thistype.allocate()
set ref = this
call move(x, y, z)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module OnHit
set o = origin
set h = height
set c = open
set d = o.distance
call setup()
if onHit != null then
set udg_MissileEvent = udg_MissileOnHit
if allocated and udg_MissileCollision > 0 then
call GroupEnumUnitsInRange(group, x, y, udg_MissileCollision + COLLISION_SIZE, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if not HaveSavedBoolean(table, this, GetHandleId(u)) then
if IsUnitInRangeXY(u, x, y, udg_MissileCollision) then
if udg_MissileCollideZ then
set dx = GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
set dy = BlzGetUnitCollisionSize(u)
if dx + dy >= z - udg_MissileCollision and dx <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
else
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
endif
endif
call GroupRemoveUnit(group, u)
endloop
endif
endif
endmodule
private module OnMissile
if onMissile != null then
set udg_MissileEvent = udg_MissileOnMissile
if allocated and udg_MissileCollision > 0 then
set k = 0
loop
exitwhen k > count
set missile = collection[k]
if missile != this then
if not HaveSavedBoolean(table, this, missile) then
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= udg_MissileCollision then
call SaveBoolean(table, this, missile, true)
set udg_MissileHitMissile = missile
if allocated and IsTriggerEnabled(onMissile) then
set udg_Missile = this
if TriggerEvaluate(onMissile) then
call TriggerExecute(onMissile)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitMissile = 0
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitMissile = 0
endif
endif
endif
set k = k + 1
endloop
endif
endif
endmodule
private module OnDestructable
if onDestructable != null then
set udg_MissileEvent = udg_MissileOnDestructable
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumDestructablesInRect(rect, null, function thistype.onDest)
endif
endif
endmodule
private module OnItem
if onItem != null then
set udg_MissileEvent = udg_MissileOnItem
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumItemsInRect(rect, null, function thistype.onItems)
endif
endif
endmodule
private module OnCliff
if onCliff != null then
set dx = GetTerrainCliffLevel(nextX, nextY)
set dy = GetTerrainCliffLevel(x, y)
set udg_MissileEvent = udg_MissileOnCliff
if dy < dx and z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if allocated and IsTriggerEnabled(onCliff) then
set udg_Missile = this
if TriggerEvaluate(onCliff) then
call TriggerExecute(onCliff)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTerrain
if onTerrain != null then
set udg_MissileEvent = udg_MissileOnTerrain
if GetLocZ(x, y) > z then
if allocated and IsTriggerEnabled(onTerrain) then
set udg_Missile = this
if TriggerEvaluate(onTerrain) then
call TriggerExecute(onTerrain)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTileset
if onTileset != null then
set udg_MissileTileset = GetTerrainType(x, y)
set udg_MissileEvent = udg_MissileOnTileset
if udg_MissileTileset != tileset then
if allocated and IsTriggerEnabled(onTileset) then
set udg_Missile = this
if TriggerEvaluate(onTileset) then
call TriggerExecute(onTileset)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
set tileset = udg_MissileTileset
set udg_MissileTileset = 0
endif
endmodule
private module OnPeriod
if onPeriod != null then
set udg_MissileEvent = udg_MissileOnPeriod
if allocated and IsTriggerEnabled(onPeriod) then
set udg_Missile = this
if TriggerEvaluate(onPeriod) then
call TriggerExecute(onPeriod)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnOrient
// Homing or not
if udg_MissileTarget != null and GetUnitTypeId(udg_MissileTarget) != 0 then
call impact.move(GetUnitX(udg_MissileTarget), GetUnitY(udg_MissileTarget), GetUnitFlyHeight(udg_MissileTarget) + toZ)
set dx = impact.x - nextX
set dy = impact.y - nextY
set a = Atan2(dy, dx)
set travel = o.distance - SquareRoot(dx*dx + dy*dy)
else
set a = o.angle
set target = null
set udg_MissileTarget = null
endif
// turn rate
if turn != 0 and not (Cos(cA-a) >= Cos(turn)) then
if Sin(a-cA) >= 0 then
set cA = cA + turn
else
set cA = cA - turn
endif
else
set cA = a
endif
set vel = veloc*dilation
set yaw = cA
set s = travel + vel
set veloc = veloc + acceleration
set travel = s
set pitch = o.alpha
set prevX = x
set prevY = y
set prevZ = z
set x = nextX
set y = nextY
set z = nextZ
set nextX = x + vel*Cos(yaw)
set nextY = y + vel*Sin(yaw)
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
// arc calculation
if h != 0 or o.slope != 0 then
set nextZ = 4*h*s*(d-s)/(d*d) + o.slope*s + o.z
set pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))
endif
// curve calculation
if c != 0 then
set dx = 4*c*s*(d-s)/(d*d)
set a = yaw + bj_PI/2
set x = x + dx*Cos(a)
set y = y + dx*Sin(a)
set yaw = yaw + Atan(-((4*c)*(2*s - d))/(d*d))
endif
endmodule
private module OnFinish
if s >= d - 0.0001 then
set finished = true
if onFinish != null then
set udg_MissileEvent = udg_MissileOnFinish
if allocated and IsTriggerEnabled(onFinish) then
set udg_Missile = this
if TriggerEvaluate(onFinish) then
call TriggerExecute(onFinish)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if travel > 0 and not paused then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
call terminate()
endif
else
if not udg_MissileRoll then
call effect.orient(yaw, -pitch, 0)
else
call effect.orient(yaw, -pitch, Atan2(c, h))
endif
endif
endmodule
private module OnBoundaries
if not effect.move(x, y, z) then
if onBoundaries != null then
set udg_MissileEvent = udg_MissileOnBoundaries
if allocated and IsTriggerEnabled(onBoundaries) then
set udg_Missile = this
if TriggerEvaluate(onBoundaries) then
call TriggerExecute(onBoundaries)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
else
if dummy != null then
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
endif
endif
call cleanup()
endmodule
private module OnPause
set pid = pid + 1
set pkey = pid
set frozen[pid] = this
set udg_MissilePaused = paused
if onPause != null then
set udg_MissileEvent = udg_MissileOnPause
if allocated and IsTriggerEnabled(onPause) then
call setup()
if TriggerEvaluate(onPause) then
call TriggerExecute(onPause)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnResume
local thistype aux
set paused = flag
set udg_MissilePaused = flag
if not paused and pkey != -1 then
set id = id + 1
set missiles[id] = this
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
if onResume != null then
set udg_MissileEvent = udg_MissileOnResume
if allocated and IsTriggerEnabled(onResume) then
call setup()
if TriggerEvaluate(onResume) then
call TriggerExecute(onResume)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if finished then
call terminate()
endif
endif
endif
endif
else
if finished then
call terminate()
endif
endif
endif
endmodule
private module OnRemove
local thistype aux
if allocated and launched then
set allocated = false
if pkey != -1 then
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
endif
if onRemove != null then
set udg_MissileEvent = udg_MissileOnRemove
if IsTriggerEnabled(onRemove) then
set udg_Missile = this
if TriggerEvaluate(onRemove) then
call TriggerExecute(onRemove)
call update()
endif
endif
endif
if dummy != null then
call Pool.recycle(dummy)
endif
set aux = collection[count]
set aux.index = index
set collection[index] = collection[count]
set count = count - 1
set index = -1
set onPeriod = null
set onHit = null
set onMissile = null
set onItem = null
set onDestructable = null
set onCliff = null
set onTerrain = null
set onTileset = null
set onFinish = null
set onBoundaries = null
set onResume = null
set onPause = null
set onRemove = null
call origin.destroy()
call impact.destroy()
call effect.destroy()
call reset()
call FlushChildHashtable(table, this)
endif
endmodule
private module Operators
/* -------------------------- Model of the missile -------------------------- */
method operator model= takes string fx returns nothing
call DestroyEffect(effect.effect)
set effect.path = fx
set effect.effect = AddSpecialEffect(fx, origin.x, origin.y)
call BlzSetSpecialEffectZ(effect.effect, origin.z)
call BlzSetSpecialEffectYaw(effect.effect, cA)
endmethod
method operator model takes nothing returns string
return effect.path
endmethod
/* ----------------------------- Curved movement ---------------------------- */
method operator curve= takes real value returns nothing
set open = Tan(value*bj_DEGTORAD)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)*bj_RADTODEG
endmethod
/* ----------------------------- Arced Movement ----------------------------- */
method operator arc= takes real value returns nothing
set height = Tan(value*bj_DEGTORAD)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)*bj_RADTODEG
endmethod
/* ------------------------------ Effect scale ------------------------------ */
method operator scale= takes real value returns nothing
set effect.size = value
call effect.scale(effect.effect, value)
endmethod
method operator scale takes nothing returns real
return effect.size
endmethod
/* ------------------------------ Missile Speed ----------------------------- */
method operator speed= takes real newspeed returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = newspeed*PERIOD
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator speed takes nothing returns real
return veloc/PERIOD
endmethod
/* ------------------------------- Flight Time ------------------------------ */
method operator duration= takes real flightTime returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = RMaxBJ(0.00000001, (origin.distance - travel)*PERIOD/RMaxBJ(0.00000001, flightTime))
set time = flightTime
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator duration takes nothing returns real
return time
endmethod
/* ------------------------------- Sight Range ------------------------------ */
method operator vision= takes real sightRange returns nothing
set sight = sightRange
if dummy == null then
if owner == null then
if source != null then
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, GetOwningPlayer(source), false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
endmethod
method operator vision takes nothing returns real
return sight
endmethod
/* ------------------------------- Time Scale ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set effect.timeScale = newTimeScale
endmethod
method operator timeScale takes nothing returns real
return effect.timeScale
endmethod
/* ---------------------------------- Alpha --------------------------------- */
method operator alpha= takes integer newAlpha returns nothing
set effect.alpha = newAlpha
endmethod
method operator alpha takes nothing returns integer
return effect.alpha
endmethod
/* ------------------------------ Player Color ------------------------------ */
method operator playerColor= takes integer playerId returns nothing
set effect.playerColor = playerId
endmethod
method operator playerColor takes nothing returns integer
return effect.playerColor
endmethod
/* -------------------------------- Animation ------------------------------- */
method operator animation= takes integer animType returns nothing
set effect.animation = animType
endmethod
method operator animation takes nothing returns integer
return effect.animation
endmethod
endmodule
private module Methods
/* --------------------------- Bounce and Deflect --------------------------- */
method bounce takes nothing returns nothing
call origin.move(x, y, z - GetLocZ(x, y))
set travel = 0
set finished = false
endmethod
method deflect takes real tx, real ty, real tz returns nothing
local real locZ = GetLocZ(x, y)
set udg_MissileTarget = null
set target = null
set toZ = tz
if z < locZ then
set nextX = prevX
set nextY = prevY
set nextZ = prevZ
endif
call impact.move(tx, ty, tz)
call origin.move(x, y, z - locZ)
set travel = 0
set finished = false
endmethod
method deflectTarget takes unit u returns nothing
call deflect(GetUnitX(u), GetUnitY(u), toZ)
set target = u
set udg_MissileTarget = u
endmethod
/* ---------------------------- Flush hit targets --------------------------- */
method flushAll takes nothing returns nothing
call FlushChildHashtable(table, this)
endmethod
method flush takes widget w returns nothing
if w != null then
call RemoveSavedBoolean(table, this, GetHandleId(w))
endif
endmethod
method hitted takes widget w returns boolean
return HaveSavedBoolean(table, this, GetHandleId(w))
endmethod
/* ----------------------- Missile attachment methods ----------------------- */
method attach takes string model, real dx, real dy, real dz, real scale returns effect
return effect.attach(model, dx, dy, dz, scale)
endmethod
method detach takes effect attachment returns nothing
if attachment != null then
call effect.detach(attachment)
endif
endmethod
/* ------------------------------ Missile Pause ----------------------------- */
method pause takes boolean flag returns nothing
implement OnResume
endmethod
/* ---------------------------------- Color --------------------------------- */
method color takes integer red, integer green, integer blue returns nothing
call effect.setColor(red, green, blue)
endmethod
/* ---------------------- Destructable collision method --------------------- */
static method onDest takes nothing returns nothing
local thistype this = temp
local destructable d = GetEnumDestructable()
local real dz
local real tz
if not HaveSavedBoolean(table, this, GetHandleId(d)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetWidgetX(d), GetWidgetY(d))
set tz = GetDestructableOccluderHeight(d)
if dz + tz >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
else
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
endif
set d = null
endmethod
/* -------------------------- Item collision method ------------------------- */
static method onItems takes nothing returns nothing
local thistype this = temp
local item i = GetEnumItem()
local real dz
if not HaveSavedBoolean(table, this, GetHandleId(i)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetItemX(i), GetItemY(i))
if dz + ITEM_SIZE >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
else
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
endif
set i = null
endmethod
/* -------------------------------- Terminate ------------------------------- */
method terminate takes nothing returns nothing
implement OnRemove
endmethod
/* ------------------------------- GUI Update ------------------------------- */
method setup takes nothing returns nothing
set udg_Missile = this
set udg_MissileStart = Location(origin.x, origin.y)
set udg_MissileStartZ = origin.z
set udg_MissileFinish = Location(impact.x, impact.y)
set udg_MissileFinishZ = impact.z
set udg_MissileTarget = target
set udg_MissileSource = source
set udg_MissileOwner = owner
set udg_MissileRoll = roll
set udg_MissilePaused = paused
set udg_MissileType = type
set udg_MissileData = data
set udg_MissileModel = effect.path
set udg_MissileScale = effect.size
set udg_MissileTimeScale = timeScale
set udg_MissileAlpha = alpha
set udg_MissilePlayerColor = playerColor
set udg_MissileAnimation = animation
set udg_MissileDamage = damage
set udg_MissileCollision = collision
set udg_MissileCollideZ = collideZ
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
set udg_MissileDuration = time
set udg_MissileArc = arc
set udg_MissileCurve = curve
set udg_MissileAcceleration = acceleration
set udg_MissileVision = sight
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endmethod
method update takes nothing returns nothing
if not paused then
set damage = udg_MissileDamage
set collision = udg_MissileCollision
set acceleration = udg_MissileAcceleration
set collideZ = udg_MissileCollideZ
set source = udg_MissileSource
set target = udg_MissileTarget
set owner = udg_MissileOwner
set roll = udg_MissileRoll
set type = udg_MissileType
set data = udg_MissileData
if effect.path != udg_MissileModel then
set model = udg_MissileModel
endif
if effect.size != udg_MissileScale then
set scale = udg_MissileScale
endif
if speed != udg_MissileSpeed then
set speed = udg_MissileSpeed
endif
if time != udg_MissileDuration then
set duration = udg_MissileDuration
endif
if arc != udg_MissileArc then
set arc = udg_MissileArc
endif
if curve != udg_MissileCurve then
set curve = udg_MissileCurve
endif
if sight != udg_MissileVision then
set vision = udg_MissileVision
endif
if timeScale != udg_MissileTimeScale then
set timeScale = udg_MissileTimeScale
endif
if alpha != udg_MissileAlpha then
set alpha = udg_MissileAlpha
endif
if playerColor != udg_MissilePlayerColor then
set playerColor = udg_MissilePlayerColor
endif
if animation != udg_MissileAnimation then
set animation = udg_MissileAnimation
endif
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endif
endmethod
method cleanup takes nothing returns nothing
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_Missile = 0
set udg_MissileStart = null
set udg_MissileStartZ = 0
set udg_MissileFinish = null
set udg_MissileFinishZ = 0
set udg_MissileTarget = null
set udg_MissileSource = null
set udg_MissileOwner = null
set udg_MissileRoll = false
set udg_MissilePaused = false
set udg_MissileType = 0
set udg_MissileData = 0
set udg_MissileModel = ""
set udg_MissileScale = 0
set udg_MissileTimeScale = 0
set udg_MissileAlpha = 0
set udg_MissilePlayerColor = 0
set udg_MissileAnimation = 0
set udg_MissileDamage = 0
set udg_MissileCollision = 0
set udg_MissileCollideZ = false
set udg_MissileVelocity = 0
set udg_MissileTravelled = 0
set udg_MissileSpeed = 0
set udg_MissileDuration = 0
set udg_MissileArc = 0
set udg_MissileCurve = 0
set udg_MissileAcceleration = 0
set udg_MissileVision = 0
set udg_MissilePosition = null
set udg_MissileZ = 0
set udg_MissileLastPosition = null
set udg_MissilePrevZ = 0
set udg_MissileNextPosition = null
set udg_MissileNextZ = 0
endmethod
endmodule
struct Missiles
private static timer timer = CreateTimer()
private static group group = CreateGroup()
private static rect rect = Rect(0., 0., 0., 0.)
private static hashtable table = InitHashtable()
private static integer last = 0
private static thistype temp = 0
private static integer id = -1
private static integer pid = -1
private static thistype array missiles
private static thistype array frozen
private static real dilation = 1
readonly static thistype array collection
readonly static integer count = -1
private real cA
private real height
private real open
private real toZ
private real time
private real sight
private unit dummy
private integer pkey
private integer index
Coordinates impact
Coordinates origin
MissileEffect effect
readonly real x
readonly real y
readonly real z
readonly real prevX
readonly real prevY
readonly real prevZ
readonly real nextX
readonly real nextY
readonly real nextZ
readonly real turn
readonly real veloc
readonly real travel
readonly boolean launched
readonly boolean allocated
readonly boolean finished
readonly boolean paused
readonly integer tileset
unit source
unit target
player owner
boolean collideZ
real collision
real damage
real acceleration
integer data
integer type
boolean roll
trigger onPeriod = null
trigger onHit = null
trigger onMissile = null
trigger onItem = null
trigger onDestructable = null
trigger onCliff = null
trigger onTerrain = null
trigger onTileset = null
trigger onFinish = null
trigger onBoundaries = null
trigger onResume = null
trigger onPause = null
trigger onRemove = null
implement Operators
implement Methods
/* ------------------------------ Reset members ----------------------------- */
private method reset takes nothing returns nothing
set launched = false
set finished = false
set collideZ = false
set paused = false
set roll = false
set source = null
set target = null
set owner = null
set dummy = null
set open = 0.
set height = 0.
set veloc = 0.
set acceleration = 0.
set collision = 0.
set damage = 0.
set travel = 0.
set turn = 0.
set time = 0.
set sight = 0.
set data = 0
set type = 0
set tileset = 0
set pkey = -1
set index = -1
endmethod
/* -------------------------- Destroys the missile -------------------------- */
private method remove takes integer i returns integer
if paused then
implement OnPause
else
implement OnRemove
endif
set missiles[i] = missiles[id]
set id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1
endif
if id == -1 then
call PauseTimer(timer)
endif
if not allocated then
call deallocate()
endif
return i - 1
endmethod
/* ---------------------------- Missiles movement --------------------------- */
private static method move takes nothing returns nothing
local integer j = 0
local integer i
local integer k
local unit u
local real a
local real d
local real s
local real h
local real c
local real dx
local real dy
local real vel
local real yaw
local real pitch
local real locZ
local Missiles missile
local Coordinates o
local thistype this
if SWEET_SPOT > 0 then
set i = last
else
set i = 0
endif
loop
exitwhen ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id)
set this = missiles[i]
set temp = this
if allocated and not paused then
implement OnHit
implement OnMissile
implement OnDestructable
implement OnItem
implement OnCliff
implement OnTerrain
implement OnTileset
implement OnPeriod
implement OnOrient
implement OnFinish
implement OnBoundaries
else
set i = remove(i)
set j = j - 1
endif
set i = i + 1
set j = j + 1
if i > id and SWEET_SPOT > 0 then
set i = 0
endif
endloop
set last = i
set u = null
endmethod
/* --------------------------- Launch the Missile --------------------------- */
method launch takes nothing returns nothing
if not launched and allocated then
set launched = true
set id = id + 1
set missiles[id] = this
set count = count + 1
set index = count
set collection[count] = this
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
endif
endmethod
/* --------------------------- Main Creator method -------------------------- */
static method create takes real x, real y, real z, real toX, real toY, real toZ returns thistype
local thistype this = thistype.allocate()
call .reset()
set .origin = Coordinates.create(x, y, z)
set .impact = Coordinates.create(toX, toY, toZ)
set .effect = MissileEffect.create(x, y, origin.z)
call Coordinates.link(origin, impact)
set .allocated = true
set .cA = origin.angle
set .x = x
set .y = y
set .z = impact.z
set .prevX = x
set .prevY = y
set .prevZ = impact.z
set .nextX = x
set .nextY = y
set .nextZ = impact.z
set .toZ = toZ
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* GUI API */
/* -------------------------------------------------------------------------- */
function MissileCreate takes nothing returns nothing
local Missiles missile = Missiles.create(GetLocationX(udg_MissileStart), GetLocationY(udg_MissileStart), udg_MissileStartZ, GetLocationX(udg_MissileFinish), GetLocationY(udg_MissileFinish), udg_MissileFinishZ)
if udg_MissileRemoveLocations then
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
else
set udg_MissileRemoveLocations = true
endif
set udg_Missile = missile
set udg_MissileStartZ = 0
set udg_MissileFinishZ = 0
set udg_MissileStart = null
set udg_MissileFinish = null
if udg_MissileModel != "" then
set missile.model = udg_MissileModel
set udg_MissileModel = ""
endif
if udg_MissileScale != 0 then
set missile.scale = udg_MissileScale
set udg_MissileScale = 0
endif
if udg_MissileSpeed != 0 then
set missile.speed = udg_MissileSpeed
set udg_MissileSpeed = 0
endif
if udg_MissileDuration != 0 then
set missile.duration = udg_MissileDuration
set udg_MissileDuration = 0
endif
if udg_MissileArc != 0 then
set missile.arc = udg_MissileArc
set udg_MissileArc = 0
endif
if udg_MissileCurve != 0 then
set missile.curve = udg_MissileCurve
set udg_MissileCurve = 0
endif
if udg_MissileDamage != 0 then
set missile.damage = udg_MissileDamage
set udg_MissileDamage = 0
endif
if udg_MissileCollision > 0 then
set missile.collision = udg_MissileCollision
set udg_MissileCollision = 0
endif
if udg_MissileAcceleration != 0 then
set missile.acceleration = udg_MissileAcceleration
set udg_MissileAcceleration = 0
endif
if udg_MissileCollideZ then
set missile.collideZ = udg_MissileCollideZ
set udg_MissileCollideZ = false
endif
if udg_MissileSource != null then
set missile.source = udg_MissileSource
set udg_MissileSource = null
endif
if udg_MissileTarget != null then
set missile.target = udg_MissileTarget
set udg_MissileTarget = null
endif
if udg_MissileOwner != null then
set missile.owner = udg_MissileOwner
set udg_MissileOwner = null
endif
if udg_MissileRoll then
set missile.roll = udg_MissileRoll
set udg_MissileRoll = false
endif
if udg_MissileType != 0 then
set missile.type = udg_MissileType
set udg_MissileType = 0
endif
if udg_MissileData != 0 then
set missile.data = udg_MissileData
set udg_MissileData = 0
endif
if udg_MissileVision != 0 then
set missile.vision = udg_MissileVision
set udg_MissileVision = 0
endif
if udg_MissileTimeScale != 0 then
set missile.timeScale = udg_MissileTimeScale
set udg_MissileTimeScale = 0
endif
if udg_MissileAlpha != 0 then
set missile.alpha = udg_MissileAlpha
set udg_MissileAlpha = 0
endif
if udg_MissilePlayerColor != 0 then
set missile.playerColor = udg_MissilePlayerColor
set udg_MissilePlayerColor = 0
endif
if udg_MissileAnimation != 0 then
set missile.animation = udg_MissileAnimation
set udg_MissileAnimation = 0
endif
if udg_Missile_onPeriod != null then
set missile.onPeriod = udg_Missile_onPeriod
set udg_Missile_onPeriod = null
endif
if udg_Missile_onHit != null then
set missile.onHit = udg_Missile_onHit
set udg_Missile_onHit = null
endif
if udg_Missile_onDestructable != null then
set missile.onDestructable = udg_Missile_onDestructable
set udg_Missile_onDestructable = null
endif
if udg_Missile_onItem != null then
set missile.onItem = udg_Missile_onItem
set udg_Missile_onItem = null
endif
if udg_Missile_onMissile != null then
set missile.onMissile = udg_Missile_onMissile
set udg_Missile_onMissile = null
endif
if udg_Missile_onCliff != null then
set missile.onCliff = udg_Missile_onCliff
set udg_Missile_onCliff = null
endif
if udg_Missile_onTerrain != null then
set missile.onTerrain = udg_Missile_onTerrain
set udg_Missile_onTerrain = null
endif
if udg_Missile_onTileset != null then
set missile.onTileset = udg_Missile_onTileset
set udg_Missile_onTileset = null
endif
if udg_Missile_onFinish != null then
set missile.onFinish = udg_Missile_onFinish
set udg_Missile_onFinish = null
endif
if udg_Missile_onBoundaries != null then
set missile.onBoundaries = udg_Missile_onBoundaries
set udg_Missile_onBoundaries = null
endif
if udg_Missile_onResume != null then
set missile.onResume = udg_Missile_onResume
set udg_Missile_onResume = null
endif
if udg_Missile_onPause != null then
set missile.onPause = udg_Missile_onPause
set udg_Missile_onPause = null
endif
if udg_Missile_onRemove != null then
set missile.onRemove = udg_Missile_onRemove
set udg_Missile_onRemove = null
endif
call missile.launch()
endfunction
function MissileBounce takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.bounce()
endfunction
function MissileDeflectTarget takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflectTarget(udg_MissileDeflectTarget)
endfunction
function MissileDeflect takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflect(GetLocationX(udg_MissileDeflectPosition), GetLocationY(udg_MissileDeflectPosition), udg_MissileDeflectZ)
call RemoveLocation(udg_MissileDeflectPosition)
set udg_MissileDeflectPosition = null
endfunction
function MissileFlush takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flush(udg_MissileFlushUnit)
set udg_MissileFlushUnit = null
endfunction
function MissileFlushAll takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flushAll()
endfunction
function MissileHitted takes nothing returns nothing
local Missiles missile = udg_Missile
set udg_MissileHitted = missile.hitted(udg_MissileHittedUnit)
endfunction
function MissileAttach takes nothing returns nothing
local Missiles missile = udg_Missile
set bj_lastCreatedEffect = missile.attach(udg_MissileAttachModel, udg_MissileAttachX, udg_MissileAttachY, udg_MissileAttachZ, udg_MissileAttachScale)
endfunction
function MissileDetach takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.detach(udg_MissileDetachEffect)
set udg_MissileDetachEffect = null
endfunction
function MissilePause takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(true)
endfunction
function MissileResume takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(false)
endfunction
function MissileColor takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.color(udg_MissileRed, udg_MissileGreen, udg_MissileBlue)
endfunction
endlibrary
library Missiles requires WorldBounds, TimerUtils
/* ----------------------- Missiles v2.6 by Chopinski ----------------------- */
// Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
// this Missiles library. Credits to Vexorian for the dummy model.
// How to Import:
// 1 -First copy the Missile dummy unit into your map and then import the dummy.mdx
// model, setting the missile dummy model path to imported dummy.mdx model.
// Dummy model: https://www.hiveworkshop.com/threads/vexorians-dummy-model.149230/
// WorldBounds: https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
// 2 - Copy this library into your map and set the
// DUMMY_RAW_CODE to the raw code of the missile dummy (ctrl + d) and you
// are done
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The update period of the system
public constant real PERIOD = 1./40.
// The max amount of Missiles processed in a PERIOD
// You can play around with both these values to find
// your sweet spot. If equal to 0, the system will
// process all missiles at once every period.
public constant real SWEET_SPOT = 100
// the avarage collision size compensation when detecting
// collisions
private constant real COLLISION_SIZE = 128.
// item size used in z collision
private constant real ITEM_SIZE = 16.
// The raw code of the dummy unit
private constant integer DUMMY = 'dumi'
// How long takes for the missile to be removed.
// This is necessary so the death animation of the
// effect can play through
private constant real RECYCLE_TIME = 2.
// Needed, don't touch.
private location LOC = Location(0., 0.)
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
private function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
private function GetMapCliffLevel takes nothing returns integer
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
endfunction
private struct Pool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) == DUMMY then
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call PauseUnit(dummy, true)
endif
endmethod
static method retrieve takes real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call PauseUnit(bj_lastCreatedUnit, false)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitZ(bj_lastCreatedUnit, z)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face)
else
set bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
call SetUnitZ(bj_lastCreatedUnit, z)
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amrf')
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == SWEET_SPOT
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call PauseUnit(u, false)
call GroupAddUnit(group, u)
call UnitRemoveAbility(u, 'Amrf')
set i = i + 1
endloop
set u = null
endmethod
endstruct
private struct Coordinates
readonly real x
readonly real y
readonly real z
readonly real angle
readonly real distance
readonly real square
readonly real slope
readonly real alpha
// Creates an origin - impact link.
private thistype ref
private static method math takes thistype a, thistype b returns nothing
local real dx
local real dy
loop
set dx = b.x - a.x
set dy = b.y - a.y
set dx = dx*dx + dy*dy
set dy = SquareRoot(dx)
exitwhen dx != 0. and dy != 0.
set b.x = b.x + .01
set b.z = b.z - GetLocZ(b.x -.01, b.y) + GetLocZ(b.x, b.y)
endloop
set a.square = dx
set a.distance = dy
set a.angle = Atan2(b.y - a.y, b.x - a.x)
set a.slope = (b.z - a.z)/dy
set a.alpha = Atan(a.slope)*bj_RADTODEG
// Set b.
if b.ref == a then
set b.angle = a.angle + bj_PI
set b.distance = dy
set b.slope = -a.slope
set b.alpha = -a.alpha
set b.square = dx
endif
endmethod
static method link takes thistype a, thistype b returns nothing
set a.ref = b
set b.ref = a
call math(a, b)
endmethod
method move takes real toX, real toY, real toZ returns nothing
set x = toX
set y = toY
set z = toZ + GetLocZ(toX, toY)
if ref != this then
call math(this, ref)
endif
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
static method create takes real x, real y, real z returns Coordinates
local thistype this = thistype.allocate()
set ref = this
call move(x, y, z)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module OnHit
set o = origin
set h = height
set c = open
set d = o.distance
call setup()
if onHit != null then
set udg_MissileEvent = udg_MissileOnHit
if allocated and udg_MissileCollision > 0 then
call GroupEnumUnitsInRange(group, x, y, udg_MissileCollision + COLLISION_SIZE, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if not HaveSavedBoolean(table, this, GetHandleId(u)) then
if IsUnitInRangeXY(u, x, y, udg_MissileCollision) then
if udg_MissileCollideZ then
set dx = GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
set dy = BlzGetUnitCollisionSize(u)
if dx + dy >= z - udg_MissileCollision and dx <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
else
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
endif
endif
call GroupRemoveUnit(group, u)
endloop
endif
endif
endmodule
private module OnMissile
if onMissile != null then
set udg_MissileEvent = udg_MissileOnMissile
if allocated and udg_MissileCollision > 0 then
set k = 0
loop
exitwhen k > count
set missile = collection[k]
if missile != this then
if not HaveSavedBoolean(table, this, missile) then
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= udg_MissileCollision then
call SaveBoolean(table, this, missile, true)
set udg_MissileHitMissile = missile
if allocated and IsTriggerEnabled(onMissile) then
set udg_Missile = this
if TriggerEvaluate(onMissile) then
call TriggerExecute(onMissile)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitMissile = 0
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitMissile = 0
endif
endif
endif
set k = k + 1
endloop
endif
endif
endmodule
private module OnDestructable
if onDestructable != null then
set udg_MissileEvent = udg_MissileOnDestructable
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumDestructablesInRect(rect, null, function thistype.onDest)
endif
endif
endmodule
private module OnItem
if onItem != null then
set udg_MissileEvent = udg_MissileOnItem
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumItemsInRect(rect, null, function thistype.onItems)
endif
endif
endmodule
private module OnCliff
if onCliff != null then
set dx = GetTerrainCliffLevel(nextX, nextY)
set dy = GetTerrainCliffLevel(x, y)
set udg_MissileEvent = udg_MissileOnCliff
if dy < dx and z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if allocated and IsTriggerEnabled(onCliff) then
set udg_Missile = this
if TriggerEvaluate(onCliff) then
call TriggerExecute(onCliff)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTerrain
if onTerrain != null then
set udg_MissileEvent = udg_MissileOnTerrain
if GetLocZ(x, y) > z then
if allocated and IsTriggerEnabled(onTerrain) then
set udg_Missile = this
if TriggerEvaluate(onTerrain) then
call TriggerExecute(onTerrain)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTileset
if onTileset != null then
set udg_MissileTileset = GetTerrainType(x, y)
set udg_MissileEvent = udg_MissileOnTileset
if udg_MissileTileset != tileset then
if allocated and IsTriggerEnabled(onTileset) then
set udg_Missile = this
if TriggerEvaluate(onTileset) then
call TriggerExecute(onTileset)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
set tileset = udg_MissileTileset
set udg_MissileTileset = 0
endif
endmodule
private module OnPeriod
if onPeriod != null then
set udg_MissileEvent = udg_MissileOnPeriod
if allocated and IsTriggerEnabled(onPeriod) then
set udg_Missile = this
if TriggerEvaluate(onPeriod) then
call TriggerExecute(onPeriod)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnOrient
// Homing or not
if udg_MissileTarget != null and GetUnitTypeId(udg_MissileTarget) != 0 then
call impact.move(GetUnitX(udg_MissileTarget), GetUnitY(udg_MissileTarget), GetUnitFlyHeight(udg_MissileTarget) + toZ)
set dx = impact.x - nextX
set dy = impact.y - nextY
set a = Atan2(dy, dx)
set travel = o.distance - SquareRoot(dx*dx + dy*dy)
else
set a = o.angle
set target = null
set udg_MissileTarget = null
endif
// turn rate
if turn != 0 and not (Cos(cA-a) >= Cos(turn)) then
if Sin(a-cA) >= 0 then
set cA = cA + turn
else
set cA = cA - turn
endif
else
set cA = a
endif
set vel = veloc*dilation
set yaw = cA
set s = travel + vel
set veloc = veloc + acceleration
set travel = s
set pitch = o.alpha
set prevX = x
set prevY = y
set prevZ = z
set x = nextX
set y = nextY
set z = nextZ
set nextX = x + vel*Cos(yaw)
set nextY = y + vel*Sin(yaw)
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
// arc calculation
if h != 0 or o.slope != 0 then
set nextZ = 4*h*s*(d-s)/(d*d) + o.slope*s + o.z
set pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))*bj_RADTODEG
endif
// curve calculation
if c != 0 then
set dx = 4*c*s*(d-s)/(d*d)
set a = cA + bj_PI/2
set x = x + dx*Cos(a)
set y = y + dx*Sin(a)
set yaw = (cA + Atan(-((4*c)*(2*s - d))/(d*d)))*bj_RADTODEG
endif
endmodule
private module OnFinish
if s >= d then
set finished = true
if onFinish != null then
set udg_MissileEvent = udg_MissileOnFinish
if allocated and IsTriggerEnabled(onFinish) then
set udg_Missile = this
if TriggerEvaluate(onFinish) then
call TriggerExecute(onFinish)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if travel > 0 and not paused then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
call terminate()
endif
endif
call SetUnitAnimationByIndex(dummy, R2I(pitch + 90.5))
call SetUnitFacing(dummy, yaw)
endmodule
private module OnBoundaries
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call SetUnitZ(dummy, z)
else
if onBoundaries != null then
set udg_MissileEvent = udg_MissileOnBoundaries
if allocated and IsTriggerEnabled(onBoundaries) then
set udg_Missile = this
if TriggerEvaluate(onBoundaries) then
call TriggerExecute(onBoundaries)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
call cleanup()
endmodule
private module OnPause
set pid = pid + 1
set pkey = pid
set frozen[pid] = this
set udg_MissilePaused = paused
if onPause != null then
set udg_MissileEvent = udg_MissileOnPause
if allocated and IsTriggerEnabled(onPause) then
call setup()
if TriggerEvaluate(onPause) then
call TriggerExecute(onPause)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnResume
local thistype aux
set paused = flag
set udg_MissilePaused = flag
if not paused and pkey != -1 then
set id = id + 1
set missiles[id] = this
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
if onResume != null then
set udg_MissileEvent = udg_MissileOnResume
if allocated and IsTriggerEnabled(onResume) then
call setup()
if TriggerEvaluate(onResume) then
call TriggerExecute(onResume)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if finished then
call terminate()
endif
endif
endif
endif
else
if finished then
call terminate()
endif
endif
endif
endmodule
private module OnRemove
local thistype aux
if allocated and launched then
set allocated = false
if pkey != -1 then
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
endif
if onRemove != null then
set udg_MissileEvent = udg_MissileOnRemove
if IsTriggerEnabled(onRemove) then
set udg_Missile = this
if TriggerEvaluate(onRemove) then
call TriggerExecute(onRemove)
call update()
endif
endif
endif
set aux = collection[count]
set aux.index = index
set collection[index] = collection[count]
set count = count - 1
set index = -1
set onPeriod = null
set onHit = null
set onMissile = null
set onItem = null
set onDestructable = null
set onCliff = null
set onTerrain = null
set onTileset = null
set onFinish = null
set onBoundaries = null
set onResume = null
set onPause = null
set onRemove = null
call origin.destroy()
call impact.destroy()
call DestroyEffect(effect)
call Pool.recycleTimed(dummy, RECYCLE_TIME)
call reset()
call FlushChildHashtable(table, this)
endif
endmodule
private module Operators
/* -------------------------- Model of the missile -------------------------- */
method operator model= takes string fxpath returns nothing
call DestroyEffect(effect)
set path = fxpath
set effect = AddSpecialEffectTarget(fxpath, dummy, "origin")
endmethod
method operator model takes nothing returns string
return path
endmethod
/* ----------------------------- Curved movement ---------------------------- */
method operator curve= takes real value returns nothing
set open = Tan(value*bj_DEGTORAD)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)*bj_RADTODEG
endmethod
/* ----------------------------- Arced Movement ----------------------------- */
method operator arc= takes real value returns nothing
set height = Tan(value*bj_DEGTORAD)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)*bj_RADTODEG
endmethod
/* ------------------------------ Effect scale ------------------------------ */
method operator scale= takes real v returns nothing
call SetUnitScale(dummy, v, v, v)
set size = v
endmethod
method operator scale takes nothing returns real
return size
endmethod
/* ------------------------------ Missile Speed ----------------------------- */
method operator speed= takes real newspeed returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = newspeed*PERIOD
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator speed takes nothing returns real
return veloc/PERIOD
endmethod
/* ------------------------------- Flight Time ------------------------------ */
method operator duration= takes real flightTime returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = RMaxBJ(0.00000001, (origin.distance - travel)*PERIOD/RMaxBJ(0.00000001, flightTime))
set time = flightTime
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator duration takes nothing returns real
return time
endmethod
/* ------------------------------- Sight Range ------------------------------ */
method operator vision= takes real sightRange returns nothing
set sight = sightRange
if owner == null then
if source != null then
call SetUnitOwner(dummy, GetOwningPlayer(source), false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
endmethod
method operator vision takes nothing returns real
return sight
endmethod
endmodule
private module Methods
/* --------------------------- Bounce and Deflect --------------------------- */
method bounce takes nothing returns nothing
call origin.move(x, y, z - GetLocZ(x, y))
set travel = 0
set finished = false
endmethod
method deflect takes real tx, real ty, real tz returns nothing
local real locZ = GetLocZ(x, y)
set udg_MissileTarget = null
set target = null
set toZ = tz
if z < locZ then
set nextX = prevX
set nextY = prevY
set nextZ = prevZ
endif
call impact.move(tx, ty, tz)
call origin.move(x, y, z - locZ)
set travel = 0
set finished = false
endmethod
method deflectTarget takes unit u returns nothing
call deflect(GetUnitX(u), GetUnitY(u), toZ)
set target = u
set udg_MissileTarget = u
endmethod
/* ---------------------------- Flush hit targets --------------------------- */
method flushAll takes nothing returns nothing
call FlushChildHashtable(table, this)
endmethod
method flush takes widget w returns nothing
if w != null then
call RemoveSavedBoolean(table, this, GetHandleId(w))
endif
endmethod
method hitted takes widget w returns boolean
return HaveSavedBoolean(table, this, GetHandleId(w))
endmethod
/* ------------------------------ Missile Pause ----------------------------- */
method pause takes boolean flag returns nothing
implement OnResume
endmethod
/* ---------------------- Destructable collision method --------------------- */
static method onDest takes nothing returns nothing
local thistype this = temp
local destructable d = GetEnumDestructable()
local real dz
local real tz
if not HaveSavedBoolean(table, this, GetHandleId(d)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetWidgetX(d), GetWidgetY(d))
set tz = GetDestructableOccluderHeight(d)
if dz + tz >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
else
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
endif
set d = null
endmethod
/* -------------------------- Item collision method ------------------------- */
static method onItems takes nothing returns nothing
local thistype this = temp
local item i = GetEnumItem()
local real dz
if not HaveSavedBoolean(table, this, GetHandleId(i)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetItemX(i), GetItemY(i))
if dz + ITEM_SIZE >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
else
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
endif
set i = null
endmethod
/* -------------------------------- Terminate ------------------------------- */
method terminate takes nothing returns nothing
implement OnRemove
endmethod
/* ------------------------------- GUI Update ------------------------------- */
method setup takes nothing returns nothing
set udg_Missile = this
set udg_MissileStart = Location(origin.x, origin.y)
set udg_MissileStartZ = origin.z
set udg_MissileFinish = Location(impact.x, impact.y)
set udg_MissileFinishZ = impact.z
set udg_MissileTarget = target
set udg_MissileSource = source
set udg_MissileOwner = owner
set udg_MissilePaused = paused
set udg_MissileType = type
set udg_MissileData = data
set udg_MissileModel = path
set udg_MissileScale = size
set udg_MissileDamage = damage
set udg_MissileCollision = collision
set udg_MissileCollideZ = collideZ
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
set udg_MissileDuration = time
set udg_MissileArc = arc
set udg_MissileCurve = curve
set udg_MissileAcceleration = acceleration
set udg_MissileVision = sight
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endmethod
method update takes nothing returns nothing
if not paused then
set damage = udg_MissileDamage
set collision = udg_MissileCollision
set acceleration = udg_MissileAcceleration
set collideZ = udg_MissileCollideZ
set source = udg_MissileSource
set target = udg_MissileTarget
set owner = udg_MissileOwner
set type = udg_MissileType
set data = udg_MissileData
if path != udg_MissileModel then
set model = udg_MissileModel
endif
if size != udg_MissileScale then
set scale = udg_MissileScale
endif
if speed != udg_MissileSpeed then
set speed = udg_MissileSpeed
endif
if time != udg_MissileDuration then
set duration = udg_MissileDuration
endif
if arc != udg_MissileArc then
set arc = udg_MissileArc
endif
if curve != udg_MissileCurve then
set curve = udg_MissileCurve
endif
if sight != udg_MissileVision then
set vision = udg_MissileVision
endif
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endif
endmethod
method cleanup takes nothing returns nothing
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_Missile = 0
set udg_MissileStart = null
set udg_MissileStartZ = 0
set udg_MissileFinish = null
set udg_MissileFinishZ = 0
set udg_MissileTarget = null
set udg_MissileSource = null
set udg_MissileOwner = null
set udg_MissilePaused = false
set udg_MissileType = 0
set udg_MissileData = 0
set udg_MissileModel = ""
set udg_MissileScale = 0
set udg_MissileDamage = 0
set udg_MissileCollision = 0
set udg_MissileCollideZ = false
set udg_MissileVelocity = 0
set udg_MissileTravelled = 0
set udg_MissileSpeed = 0
set udg_MissileDuration = 0
set udg_MissileArc = 0
set udg_MissileCurve = 0
set udg_MissileAcceleration = 0
set udg_MissileVision = 0
set udg_MissilePosition = null
set udg_MissileZ = 0
set udg_MissileLastPosition = null
set udg_MissilePrevZ = 0
set udg_MissileNextPosition = null
set udg_MissileNextZ = 0
endmethod
endmodule
struct Missiles
private static timer timer = CreateTimer()
private static group group = CreateGroup()
private static rect rect = Rect(0., 0., 0., 0.)
private static hashtable table = InitHashtable()
private static integer last = 0
private static thistype temp = 0
private static integer id = -1
private static integer pid = -1
private static real dilation = 1
private static thistype array missiles
private static thistype array frozen
readonly static thistype array collection
readonly static integer count = -1
private real cA
private effect effect
private string path
private real size
private real height
private real open
private real toZ
private real time
private real sight
private integer pkey
private integer index
Coordinates impact
Coordinates origin
readonly real x
readonly real y
readonly real z
readonly real prevX
readonly real prevY
readonly real prevZ
readonly real nextX
readonly real nextY
readonly real nextZ
readonly real turn
readonly real veloc
readonly real travel
readonly unit dummy
readonly boolean launched
readonly boolean allocated
readonly boolean finished
readonly boolean paused
readonly integer tileset
unit source
unit target
player owner
boolean collideZ
real collision
real damage
real acceleration
integer data
integer type
trigger onPeriod = null
trigger onHit = null
trigger onMissile = null
trigger onItem = null
trigger onDestructable = null
trigger onCliff = null
trigger onTerrain = null
trigger onTileset = null
trigger onFinish = null
trigger onBoundaries = null
trigger onResume = null
trigger onPause = null
trigger onRemove = null
implement Operators
implement Methods
/* ------------------------------ Reset members ----------------------------- */
private method reset takes nothing returns nothing
set launched = false
set finished = false
set collideZ = false
set paused = false
set source = null
set target = null
set owner = null
set effect = null
set dummy = null
set path = ""
set open = 0.
set height = 0.
set veloc = 0.
set acceleration = 0.
set collision = 0.
set damage = 0.
set travel = 0.
set turn = 0.
set size = 0.
set time = 0.
set sight = 0.
set data = 0
set type = 0
set tileset = 0
set pkey = -1
set index = -1
endmethod
/* -------------------------- Destroys the missile -------------------------- */
private method remove takes integer i returns integer
if paused then
implement OnPause
else
implement OnRemove
endif
set missiles[i] = missiles[id]
set id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1
endif
if id == -1 then
call PauseTimer(timer)
endif
if not allocated then
call deallocate()
endif
return i - 1
endmethod
/* ---------------------------- Missiles movement --------------------------- */
private static method move takes nothing returns nothing
local integer j = 0
local integer i
local integer k
local unit u
local real a
local real d
local real s
local real h
local real c
local real dx
local real dy
local real vel
local real locZ
local real yaw
local real pitch
local Missiles missile
local Coordinates o
local thistype this
if SWEET_SPOT > 0 then
set i = last
else
set i = 0
endif
loop
exitwhen ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id)
set this = missiles[i]
set temp = this
if allocated and not paused then
implement OnHit
implement OnMissile
implement OnDestructable
implement OnItem
implement OnCliff
implement OnTerrain
implement OnTileset
implement OnPeriod
implement OnOrient
implement OnFinish
implement OnBoundaries
else
set i = remove(i)
set j = j - 1
endif
set i = i + 1
set j = j + 1
if i > id and SWEET_SPOT > 0 then
set i = 0
endif
endloop
set last = i
set u = null
endmethod
/* --------------------------- Launch the Missile --------------------------- */
method launch takes nothing returns nothing
if not launched and allocated then
set launched = true
set id = id + 1
set missiles[id] = this
set count = count + 1
set index = count
set collection[count] = this
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
endif
endmethod
/* --------------------------- Main Creator method -------------------------- */
static method create takes real x, real y, real z, real toX, real toY, real toZ returns thistype
local thistype this = thistype.allocate()
local real face = Atan2(toY - y, toX - x)*bj_RADTODEG
call .reset()
set .origin = Coordinates.create(x, y, z)
set .impact = Coordinates.create(toX, toY, toZ)
set .dummy = Pool.retrieve(x, y, z, face)
call Coordinates.link(origin, impact)
set .allocated = true
set .cA = origin.angle
set .x = x
set .y = y
set .z = impact.z
set .prevX = x
set .prevY = y
set .prevZ = impact.z
set .nextX = x
set .nextY = y
set .nextZ = impact.z
set .toZ = toZ
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* GUI API */
/* -------------------------------------------------------------------------- */
function MissileCreate takes nothing returns nothing
local Missiles missile = Missiles.create(GetLocationX(udg_MissileStart), GetLocationY(udg_MissileStart), udg_MissileStartZ, GetLocationX(udg_MissileFinish), GetLocationY(udg_MissileFinish), udg_MissileFinishZ)
if udg_MissileRemoveLocations then
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
else
set udg_MissileRemoveLocations = true
endif
set udg_Missile = missile
set udg_MissileStartZ = 0
set udg_MissileFinishZ = 0
set udg_MissileStart = null
set udg_MissileFinish = null
if udg_MissileModel != "" then
set missile.model = udg_MissileModel
set udg_MissileModel = ""
endif
if udg_MissileScale != 0 then
set missile.scale = udg_MissileScale
set udg_MissileScale = 0
endif
if udg_MissileSpeed != 0 then
set missile.speed = udg_MissileSpeed
set udg_MissileSpeed = 0
endif
if udg_MissileDuration != 0 then
set missile.duration = udg_MissileDuration
set udg_MissileDuration = 0
endif
if udg_MissileArc != 0 then
set missile.arc = udg_MissileArc
set udg_MissileArc = 0
endif
if udg_MissileCurve != 0 then
set missile.curve = udg_MissileCurve
set udg_MissileCurve = 0
endif
if udg_MissileDamage != 0 then
set missile.damage = udg_MissileDamage
set udg_MissileDamage = 0
endif
if udg_MissileCollision > 0 then
set missile.collision = udg_MissileCollision
set udg_MissileCollision = 0
endif
if udg_MissileAcceleration != 0 then
set missile.acceleration = udg_MissileAcceleration
set udg_MissileAcceleration = 0
endif
if udg_MissileCollideZ then
set missile.collideZ = udg_MissileCollideZ
set udg_MissileCollideZ = false
endif
if udg_MissileSource != null then
set missile.source = udg_MissileSource
set udg_MissileSource = null
endif
if udg_MissileTarget != null then
set missile.target = udg_MissileTarget
set udg_MissileTarget = null
endif
if udg_MissileOwner != null then
set missile.owner = udg_MissileOwner
set udg_MissileOwner = null
endif
if udg_MissileType != 0 then
set missile.type = udg_MissileType
set udg_MissileType = 0
endif
if udg_MissileData != 0 then
set missile.data = udg_MissileData
set udg_MissileData = 0
endif
if udg_MissileVision != 0 then
set missile.vision = udg_MissileVision
set udg_MissileVision = 0
endif
if udg_Missile_onPeriod != null then
set missile.onPeriod = udg_Missile_onPeriod
set udg_Missile_onPeriod = null
endif
if udg_Missile_onHit != null then
set missile.onHit = udg_Missile_onHit
set udg_Missile_onHit = null
endif
if udg_Missile_onDestructable != null then
set missile.onDestructable = udg_Missile_onDestructable
set udg_Missile_onDestructable = null
endif
if udg_Missile_onItem != null then
set missile.onItem = udg_Missile_onItem
set udg_Missile_onItem = null
endif
if udg_Missile_onMissile != null then
set missile.onMissile = udg_Missile_onMissile
set udg_Missile_onMissile = null
endif
if udg_Missile_onCliff != null then
set missile.onCliff = udg_Missile_onCliff
set udg_Missile_onCliff = null
endif
if udg_Missile_onTerrain != null then
set missile.onTerrain = udg_Missile_onTerrain
set udg_Missile_onTerrain = null
endif
if udg_Missile_onTileset != null then
set missile.onTileset = udg_Missile_onTileset
set udg_Missile_onTileset = null
endif
if udg_Missile_onFinish != null then
set missile.onFinish = udg_Missile_onFinish
set udg_Missile_onFinish = null
endif
if udg_Missile_onBoundaries != null then
set missile.onBoundaries = udg_Missile_onBoundaries
set udg_Missile_onBoundaries = null
endif
if udg_Missile_onResume != null then
set missile.onResume = udg_Missile_onResume
set udg_Missile_onResume = null
endif
if udg_Missile_onPause != null then
set missile.onPause = udg_Missile_onPause
set udg_Missile_onPause = null
endif
if udg_Missile_onRemove != null then
set missile.onRemove = udg_Missile_onRemove
set udg_Missile_onRemove = null
endif
call missile.launch()
endfunction
function MissileBounce takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.bounce()
endfunction
function MissileDeflectTarget takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflectTarget(udg_MissileDeflectTarget)
endfunction
function MissileDeflect takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflect(GetLocationX(udg_MissileDeflectPosition), GetLocationY(udg_MissileDeflectPosition), udg_MissileDeflectZ)
call RemoveLocation(udg_MissileDeflectPosition)
set udg_MissileDeflectPosition = null
endfunction
function MissileFlush takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flush(udg_MissileFlushUnit)
set udg_MissileFlushUnit = null
endfunction
function MissileFlushAll takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flushAll()
endfunction
function MissileHitted takes nothing returns nothing
local Missiles missile = udg_Missile
set udg_MissileHitted = missile.hitted(udg_MissileHittedUnit)
endfunction
function MissileAttach takes nothing returns nothing
//local Missiles missile = udg_Missile
//set bj_lastCreatedEffect = missile.attach(udg_MissileAttachModel, udg_MissileAttachX, udg_MissileAttachY, udg_MissileAttachZ, udg_MissileAttachScale)
endfunction
function MissileDetach takes nothing returns nothing
//local Missiles missile = udg_Missile
//call missile.detach(udg_MissileDetachEffect)
//set udg_MissileDetachEffect = null
endfunction
function MissilePause takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(true)
endfunction
function MissileResume takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(false)
endfunction
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
//local location data__targetLoc = GetSpellTargetLoc()
//local boolean data__targetBoo = false
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()
//===================================================
//custom spell target location
//check location
// if data__targetLoc != null then
// call RemoveLocation(data__targetLoc)
// else
// set data__targetBoo = true //spelltargetloc is null
// endif
//
// if GetSpellTargetX() == 0 and GetSpellTargetY() == 0 or data__targetBoo == true then
// set udg_Spell_i_TargetX[i] = udg_MouseX_Cont [ GetConvertedPlayerId ( GetOwningPlayer( udg_Spell__Caster ) ) ]
// set udg_Spell_i_TargetY[i] = udg_MouseY_Cont [ GetConvertedPlayerId ( GetOwningPlayer( udg_Spell__Caster ) ) ]
// else
// set udg_Spell_i_TargetX[i] = GetSpellTargetX()
// set udg_Spell_i_TargetY[i] = GetSpellTargetY()
// endif
//end custom
//========================================================
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
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_Ori takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS
local player p
local trigger t
if gg_trg_Spell_System_Ori != 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_Ori = CreateTrigger()
call TriggerAddAction(gg_trg_Spell_System_Ori, function SpellSystemRegister)
set gg_trg_Spell_System_Config = gg_trg_Spell_System_Ori //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
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__Duration
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
set udg_Spell__Time = udg_Spell__Time
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_Edited_Zam takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS
local player p
local trigger t
if gg_trg_Spell_System_Edited_Zam != 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_Edited_Zam = CreateTrigger()
call TriggerAddAction(gg_trg_Spell_System_Edited_Zam, function SpellSystemRegister)
set gg_trg_Spell_System_Config = gg_trg_Spell_System_Edited_Zam //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
function Trig_ShieldBlockFront_Conditions takes nothing returns boolean
local unit source = udg_DamageEventSource
local unit target = udg_DamageEventTarget
local real x2 = GetUnitX(source)
local real y2 = GetUnitY(source)
local real x1 = GetUnitX(target)
local real y1 = GetUnitY(target)
local real arc = 180
local real angle = Atan2(y2 - y1, x2 - x1)*bj_RADTODEG
local real anglefacing = GetUnitFacing(target)
local real angledifference
// if anglefacing > 180 then
// set anglefacing = -(360 -anglefacing)
// endif
set angledifference = ModuloReal(angle-(anglefacing+180),360) - 180
// call BJDebugMsg("AngleDifference: " +R2S(angledifference))
set source = null
set target = null
if angledifference <= arc/2.0 and angledifference >= -arc/2.0 then
return true
endif
return false
endfunction
function Trig_ShieldBlockFront_Actions takes nothing returns nothing
endfunction
//===========================================================================
function InitTrig_ShieldBlockFront takes nothing returns nothing
set gg_trg_ShieldBlockFront = CreateTrigger( )
call TriggerAddCondition( gg_trg_ShieldBlockFront, Condition( function Trig_ShieldBlockFront_Conditions ) )
call TriggerAddAction( gg_trg_ShieldBlockFront, function Trig_ShieldBlockFront_Actions )
endfunction
function Trig_ShieldBlockByEffect60_Conditions takes nothing returns boolean
local effect e = LoadEffectHandle(udg_ShieldTable, udg_ShieldIndex, StringHash("ShieldEffect"))
local unit source = udg_DamageEventSource
local unit target = udg_DamageEventTarget
local real x2 = GetUnitX(source)
local real y2 = GetUnitY(source)
local real x1 = GetUnitX(target)
local real y1 = GetUnitY(target)
local real x3 = BlzGetLocalSpecialEffectX(e)
local real y3 = BlzGetLocalSpecialEffectY(e)
local real arc = 120
local real angle = Atan2(y2 - y1, x2 - x1)*bj_RADTODEG
local real anglefacing = Atan2(y3 - y1, x3 - x1)*bj_RADTODEG
local real angledifference
set angledifference = ModuloReal(angle-(anglefacing+180),360) - 180
//call BJDebugMsg("AngleDifference: " +R2S(angledifference))
set source = null
set target = null
if angledifference <= arc/2.0 and angledifference >= -arc/2.0 then
return true
endif
return false
endfunction
//===========================================================================
function InitTrig_ShieldBlockByEffect120 takes nothing returns nothing
set gg_trg_ShieldBlockByEffect120 = CreateTrigger( )
call TriggerAddCondition( gg_trg_ShieldBlockByEffect120, Condition( function Trig_ShieldBlockByEffect60_Conditions ) )
endfunction
function Trig_ShieldPeriodicEval_Actions takes nothing returns nothing
local integer unitcount = BlzGroupGetSize(udg_SystemShieldedUnits)
local integer counter = 0
local unit u
local real shieldcurrenthp
local real shieldmaxhp
loop
exitwhen counter >= unitcount
set u = BlzGroupUnitAt(udg_SystemShieldedUnits, counter)
set udg_ShieldUnitIndex = GetUnitUserData(u)
set udg_ShieldIterationTrigger = gg_trg_ShieldPeriodicIterationTrigger
call TriggerExecute( gg_trg_ForAllShieldsOfUnit )
set udg_ShieldUnitIndex = GetUnitUserData(u)
set udg_ShieldEvent = 0.00
set udg_ShieldEvent = 4.00
set counter = counter + 1
endloop
set u = null
endfunction
//===========================================================================
function InitTrig_ShieldPeriodicEval takes nothing returns nothing
set gg_trg_ShieldPeriodicEval = CreateTrigger( )
call TriggerRegisterTimerExpireEventBJ( gg_trg_ShieldPeriodicEval, udg_SystemShieldPeriodicTimer )
call TriggerAddAction( gg_trg_ShieldPeriodicEval, function Trig_ShieldPeriodicEval_Actions )
endfunction
function Trig_RemoveShield_Actions takes nothing returns nothing
local integer shieldindex = udg_ShieldIndex
if ( udg_ShieldIndex != 0 ) then
if ( udg_SystemShieldListInUse <= 1 ) then
set udg_ShieldLastOfIDRemoved = false
set udg_ShieldUnitIndex = GetUnitUserData(udg_ShieldedUnit[udg_ShieldIndex])
// Adjust shield lists
if ( udg_ShieldNextSame[udg_ShieldIndex] == 0 ) then
// Next same does not exist
if ( udg_ShieldPrevSame[udg_ShieldIndex] == 0 ) then
// Next same, Prev same do not exist
// Last of type being removed
set udg_ShieldLastOfIDRemoved = true
// Check diff shield values, to see if it's head, tail, or middle removal
if ( udg_ShieldNextDiff[udg_ShieldIndex] == 0 ) then
if ( udg_ShieldPrevDiff[udg_ShieldIndex] == 0 ) then
// Only buff remaining
set udg_UnitFirstShield[udg_ShieldUnitIndex] = 0
set udg_UnitLastShield[udg_ShieldUnitIndex] = 0
call GroupRemoveUnitSimple( udg_ShieldedUnit[udg_ShieldIndex], udg_SystemShieldedUnits )
else
// no next, has prev, is on tail end of diff list
set udg_UnitLastShield[udg_ShieldUnitIndex] = udg_ShieldPrevDiff[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldPrevDiff[udg_ShieldIndex]] = 0
endif
else
if ( udg_ShieldPrevDiff[udg_ShieldIndex] == 0 ) then
// Has next, no prev. Is head of diff list
set udg_UnitFirstShield[udg_ShieldUnitIndex] = udg_ShieldNextDiff[udg_ShieldIndex]
set udg_ShieldPrevDiff[udg_ShieldNextDiff[udg_ShieldIndex]] = 0
else
// has next, has prev, is in middle of diff list
set udg_ShieldPrevDiff[udg_ShieldNextDiff[udg_ShieldIndex]] = udg_ShieldPrevDiff[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldPrevDiff[udg_ShieldIndex]] = udg_ShieldNextDiff[udg_ShieldIndex]
endif
endif
else
// On tail end of same list
set udg_ShieldNextSame[udg_ShieldPrevSame[udg_ShieldIndex]] = 0
endif
else
// Next same exists
if ( udg_ShieldPrevSame[udg_ShieldIndex] == 0 ) then
// On head of same list
set udg_ShieldPrevSame[udg_ShieldNextSame[udg_ShieldIndex]] = 0
if ( udg_ShieldNextDiff[udg_ShieldIndex] == 0 ) then
if ( udg_ShieldPrevDiff[udg_ShieldIndex] == 0 ) then
// No next, no prev. Only type
set udg_UnitFirstShield[udg_ShieldUnitIndex] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_UnitLastShield[udg_ShieldUnitIndex] = udg_ShieldNextSame[udg_ShieldIndex]
else
// no next, has prev, is on tail end of diff list
set udg_UnitLastShield[udg_ShieldUnitIndex] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldPrevDiff[udg_ShieldIndex]] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldPrevDiff[udg_ShieldNextSame[udg_ShieldIndex]] = udg_ShieldPrevDiff[udg_ShieldIndex]
endif
else
if ( udg_ShieldPrevDiff[udg_ShieldIndex] == 0 ) then
// Has next, no prev. Is head of diff list
set udg_UnitFirstShield[udg_ShieldUnitIndex] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldPrevDiff[udg_ShieldNextDiff[udg_ShieldIndex]] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldNextSame[udg_ShieldIndex]] = udg_ShieldNextDiff[udg_ShieldIndex]
else
// has next, has prev, is in middle of diff list
set udg_ShieldPrevDiff[udg_ShieldNextDiff[udg_ShieldIndex]] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldPrevDiff[udg_ShieldIndex]] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldNextDiff[udg_ShieldNextSame[udg_ShieldIndex]] = udg_ShieldNextDiff[udg_ShieldIndex]
set udg_ShieldPrevDiff[udg_ShieldNextSame[udg_ShieldIndex]] = udg_ShieldPrevDiff[udg_ShieldIndex]
endif
endif
else
// In middle of same list
set udg_ShieldNextSame[udg_ShieldPrevSame[udg_ShieldIndex]] = udg_ShieldNextSame[udg_ShieldIndex]
set udg_ShieldPrevSame[udg_ShieldNextSame[udg_ShieldIndex]] = udg_ShieldPrevSame[udg_ShieldIndex]
endif
endif
call TriggerExecute( udg_ShieldRemoved[udg_ShieldIndex] )
set udg_ShieldIndex = shieldindex
set udg_ShieldEvent = 0.00
set udg_ShieldEvent = 2.00
// Just in case the event somehow changed the shieldindex
set udg_ShieldIndex = shieldindex
set udg_SystemShieldFreeIndexCurrent = ( udg_SystemShieldFreeIndexCurrent - 1 )
set udg_SystemShieldFreeIndexes[udg_SystemShieldFreeIndexCurrent] = udg_ShieldIndex
call FlushChildHashtable(udg_ShieldTable, udg_ShieldIndex)
//call BJDebugMsg("Shield removed: "+I2S(udg_ShieldIndex))
else
// If list in use, do not remove entries yet, could affect traversal of list
// Add shields to be removed into a queue
if udg_SystemShieldFlaggedRemove[udg_ShieldIndex] == false then
set udg_SystemShieldFlaggedRemove[udg_ShieldIndex] = true
set udg_SystemShieldsRemovalQueueIndex = ( udg_SystemShieldsRemovalQueueIndex + 1 )
set udg_SystemShieldsRemovalQueue[udg_SystemShieldsRemovalQueueIndex] = udg_ShieldIndex
endif
endif
else
endif
endfunction
//===========================================================================
function InitTrig_RemoveShield takes nothing returns nothing
set gg_trg_RemoveShield = CreateTrigger( )
call TriggerAddAction( gg_trg_RemoveShield, function Trig_RemoveShield_Actions )
endfunction
function Trig_ForAllShieldsOfUnit_Actions takes nothing returns nothing
local integer counter
local integer previndex = udg_ShieldIndex
local integer shieldindex
local trigger iterationtrigger = udg_ShieldIterationTrigger
local integer unitindex = udg_ShieldUnitIndex
local integer topshield = udg_UnitFirstShield[udg_ShieldUnitIndex]
local integer queuedshields
local boolean baseiteration = false
if ( udg_SystemShieldListInUse == 0 ) then
set udg_SystemShieldsRemovalQueueIndex = -1
set baseiteration = true
endif
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse + 1 )
set udg_ShieldIndex = udg_UnitFirstShield[udg_ShieldUnitIndex]
set udg_SystemShieldIterationStop = false
loop
exitwhen topshield == 0 or udg_SystemShieldIterationStop
set udg_ShieldIndex = topshield
loop
exitwhen udg_ShieldIndex == 0 or udg_SystemShieldIterationStop
if udg_SystemShieldFlaggedRemove[udg_ShieldIndex] == false or udg_ShieldIterationTrigger == gg_trg_RemoveShield then
set shieldindex = udg_ShieldIndex
set udg_ShieldIterationTrigger = iterationtrigger
call TriggerExecute( udg_ShieldIterationTrigger )
set udg_ShieldIndex = shieldindex
endif
set udg_ShieldIndex = udg_ShieldNextSame[udg_ShieldIndex]
endloop
set topshield = udg_ShieldNextDiff[topshield]
endloop
// If any shields were queued to be removed, remove them after list traversal is done
if ( baseiteration and udg_SystemShieldsRemovalQueueIndex >= 0 ) then
call BJDebugMsg("Index: "+I2S(udg_SystemShieldsRemovalQueueIndex))
call BJDebugMsg("Removing shields in queue")
set counter = 0
loop
exitwhen counter > udg_SystemShieldsRemovalQueueIndex
set udg_ShieldIndex = udg_SystemShieldsRemovalQueue[counter]
set queuedshields = udg_SystemShieldsRemovalQueueIndex
call TriggerExecute( gg_trg_RemoveShield )
set udg_SystemShieldsRemovalQueueIndex = queuedshields
set counter = counter + 1
endloop
else
endif
set udg_ShieldUnitIndex = unitindex
set iterationtrigger = null
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse - 1 )
set udg_ShieldIndex = previndex
endfunction
//===========================================================================
function InitTrig_ForAllShieldsOfUnit takes nothing returns nothing
set gg_trg_ForAllShieldsOfUnit = CreateTrigger( )
call TriggerAddAction( gg_trg_ForAllShieldsOfUnit, function Trig_ForAllShieldsOfUnit_Actions )
endfunction
function Trig_ForAllShieldsOfUnitDisplayOrder_Actions takes nothing returns nothing
local integer counter
local integer shieldindex
local trigger iterationtrigger = udg_ShieldIterationTrigger
local integer unitindex = udg_ShieldUnitIndex
local integer topshield = udg_UnitFirstShield[udg_ShieldUnitIndex]
local integer queuedshields
local boolean baseiteration = false
if ( udg_SystemShieldListInUse == 0 ) then
set udg_SystemShieldsRemovalQueueIndex = -1
set baseiteration = true
endif
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse + 1 )
set udg_ShieldIndex = udg_UnitFirstShield[udg_ShieldUnitIndex]
set udg_SystemShieldIterationStop = false
loop
exitwhen topshield == 0 or udg_SystemShieldIterationStop
set udg_ShieldIndex = topshield
loop
exitwhen udg_ShieldNextSame[udg_ShieldIndex] == 0
set udg_ShieldIndex = udg_ShieldNextSame[udg_ShieldIndex]
endloop
loop
exitwhen udg_ShieldIndex == 0 or udg_SystemShieldIterationStop
if udg_SystemShieldFlaggedRemove[udg_ShieldIndex] == false or udg_ShieldIterationTrigger == gg_trg_RemoveShield then
set shieldindex = udg_ShieldIndex
set udg_ShieldIterationTrigger = iterationtrigger
call TriggerExecute( udg_ShieldIterationTrigger )
set udg_ShieldIndex = shieldindex
endif
set udg_ShieldIndex = udg_ShieldPrevSame[udg_ShieldIndex]
endloop
set topshield = udg_ShieldNextDiff[topshield]
endloop
// If any shields were queued to be removed, remove them after list traversal is done
if ( baseiteration and udg_SystemShieldsRemovalQueueIndex >= 0 ) then
call BJDebugMsg("Index: "+I2S(udg_SystemShieldsRemovalQueueIndex))
call BJDebugMsg("Removing shields in queue")
set counter = 0
loop
exitwhen counter > udg_SystemShieldsRemovalQueueIndex
set udg_ShieldIndex = udg_SystemShieldsRemovalQueue[counter]
set queuedshields = udg_SystemShieldsRemovalQueueIndex
call TriggerExecute( gg_trg_RemoveShield )
set udg_SystemShieldsRemovalQueueIndex = queuedshields
set counter = counter + 1
endloop
else
endif
set udg_ShieldUnitIndex = unitindex
set iterationtrigger = null
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse - 1 )
endfunction
//===========================================================================
function InitTrig_ForAllShieldsOfUnitDisplayOrder takes nothing returns nothing
set gg_trg_ForAllShieldsOfUnitDisplayOrder = CreateTrigger( )
call TriggerAddAction( gg_trg_ForAllShieldsOfUnitDisplayOrder, function Trig_ForAllShieldsOfUnitDisplayOrder_Actions )
endfunction
function Trig_ForAllShieldsOfUnitBackward_Actions takes nothing returns nothing
local integer counter
local integer shieldindex
local trigger iterationtrigger = udg_ShieldIterationTrigger
local integer unitindex = udg_ShieldUnitIndex
local integer topshield = udg_UnitLastShield[udg_ShieldUnitIndex]
local integer queuedshields
local boolean baseiteration = false
if ( udg_SystemShieldListInUse == 0 ) then
set udg_SystemShieldsRemovalQueueIndex = -1
set baseiteration = true
endif
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse + 1 )
set udg_ShieldIndex = udg_UnitLastShield[udg_ShieldUnitIndex]
set udg_SystemShieldIterationStop = false
loop
exitwhen topshield == 0 or udg_SystemShieldIterationStop
set udg_ShieldIndex = topshield
loop
exitwhen udg_ShieldNextSame[udg_ShieldIndex] == 0
set udg_ShieldIndex = udg_ShieldNextSame[udg_ShieldIndex]
endloop
loop
exitwhen udg_ShieldIndex == 0 or udg_SystemShieldIterationStop
if udg_SystemShieldFlaggedRemove[udg_ShieldIndex] == false or udg_ShieldIterationTrigger == gg_trg_RemoveShield then
set shieldindex = udg_ShieldIndex
set udg_ShieldIterationTrigger = iterationtrigger
call TriggerExecute( udg_ShieldIterationTrigger )
set udg_ShieldIndex = shieldindex
endif
set udg_ShieldIndex = udg_ShieldPrevSame[udg_ShieldIndex]
endloop
set topshield = udg_ShieldPrevDiff[topshield]
endloop
// If any shields were queued to be removed, remove them after list traversal is done
if ( baseiteration and udg_SystemShieldsRemovalQueueIndex >= 0 ) then
call BJDebugMsg("Index: "+I2S(udg_SystemShieldsRemovalQueueIndex))
call BJDebugMsg("Removing shields in queue")
set counter = 0
loop
exitwhen counter > udg_SystemShieldsRemovalQueueIndex
set udg_ShieldIndex = udg_SystemShieldsRemovalQueue[counter]
set queuedshields = udg_SystemShieldsRemovalQueueIndex
call TriggerExecute( gg_trg_RemoveShield )
set udg_SystemShieldsRemovalQueueIndex = queuedshields
set counter = counter + 1
endloop
else
endif
set udg_ShieldUnitIndex = unitindex
set iterationtrigger = null
set udg_SystemShieldListInUse = ( udg_SystemShieldListInUse - 1 )
endfunction
//===========================================================================
function InitTrig_ForAllShieldsOfUnitBackward takes nothing returns nothing
set gg_trg_ForAllShieldsOfUnitBackward = CreateTrigger( )
call TriggerAddAction( gg_trg_ForAllShieldsOfUnitBackward, function Trig_ForAllShieldsOfUnitBackward_Actions )
endfunction
function Trig_PRD_Init_Actions takes nothing returns nothing
set udg_PRD_C [ 1 ] = 0.00016
set udg_PRD_C [ 2 ] = 0.00062
set udg_PRD_C [ 3 ] = 0.00139
set udg_PRD_C [ 4 ] = 0.00245
set udg_PRD_C [ 5 ] = 0.0038
set udg_PRD_C [ 6 ] = 0.00544
set udg_PRD_C [ 7 ] = 0.00736
set udg_PRD_C [ 8 ] = 0.00955
set udg_PRD_C [ 9 ] = 0.01202
set udg_PRD_C [ 10 ] = 0.01475
set udg_PRD_C [ 11 ] = 0.01774
set udg_PRD_C [ 12 ] = 0.02098
set udg_PRD_C [ 13 ] = 0.02448
set udg_PRD_C [ 14 ] = 0.02823
set udg_PRD_C [ 15 ] = 0.03222
set udg_PRD_C [ 16 ] = 0.03645
set udg_PRD_C [ 17 ] = 0.04092
set udg_PRD_C [ 18 ] = 0.04562
set udg_PRD_C [ 19 ] = 0.05055
set udg_PRD_C [ 20 ] = 0.0557
set udg_PRD_C [ 21 ] = 0.06108
set udg_PRD_C [ 22 ] = 0.06668
set udg_PRD_C [ 23 ] = 0.07249
set udg_PRD_C [ 24 ] = 0.07851
set udg_PRD_C [ 25 ] = 0.08474
set udg_PRD_C [ 26 ] = 0.09118
set udg_PRD_C [ 27 ] = 0.09783
set udg_PRD_C [ 28 ] = 0.10467
set udg_PRD_C [ 29 ] = 0.11171
set udg_PRD_C [ 30 ] = 0.11895
set udg_PRD_C [ 31 ] = 0.12638
set udg_PRD_C [ 32 ] = 0.134
set udg_PRD_C [ 33 ] = 0.14181
set udg_PRD_C [ 34 ] = 0.14981
set udg_PRD_C [ 35 ] = 0.15798
set udg_PRD_C [ 36 ] = 0.16633
set udg_PRD_C [ 37 ] = 0.17491
set udg_PRD_C [ 38 ] = 0.18362
set udg_PRD_C [ 39 ] = 0.19249
set udg_PRD_C [ 40 ] = 0.20155
set udg_PRD_C [ 41 ] = 0.21092
set udg_PRD_C [ 42 ] = 0.22036
set udg_PRD_C [ 43 ] = 0.2299
set udg_PRD_C [ 44 ] = 0.23954
set udg_PRD_C [ 45 ] = 0.24931
set udg_PRD_C [ 46 ] = 0.25987
set udg_PRD_C [ 47 ] = 0.27045
set udg_PRD_C [ 48 ] = 0.28101
set udg_PRD_C [ 49 ] = 0.29155
set udg_PRD_C [ 50 ] = 0.3021
set udg_PRD_C [ 51 ] = 0.31268
set udg_PRD_C [ 52 ] = 0.32329
set udg_PRD_C [ 53 ] = 0.33412
set udg_PRD_C [ 54 ] = 0.34737
set udg_PRD_C [ 55 ] = 0.3604
set udg_PRD_C [ 56 ] = 0.37322
set udg_PRD_C [ 57 ] = 0.38584
set udg_PRD_C [ 58 ] = 0.39828
set udg_PRD_C [ 59 ] = 0.41054
set udg_PRD_C [ 60 ] = 0.42265
set udg_PRD_C [ 61 ] = 0.4346
set udg_PRD_C [ 62 ] = 0.44642
set udg_PRD_C [ 63 ] = 0.4581
set udg_PRD_C [ 64 ] = 0.46967
set udg_PRD_C [ 65 ] = 0.48113
set udg_PRD_C [ 66 ] = 0.49248
set udg_PRD_C [ 67 ] = 0.50746
set udg_PRD_C [ 68 ] = 0.52941
set udg_PRD_C [ 69 ] = 0.55072
set udg_PRD_C [ 70 ] = 0.57143
set udg_PRD_C [ 71 ] = 0.59155
set udg_PRD_C [ 72 ] = 0.61111
set udg_PRD_C [ 73 ] = 0.63014
set udg_PRD_C [ 74 ] = 0.64865
set udg_PRD_C [ 75 ] = 0.66667
set udg_PRD_C [ 76 ] = 0.68421
set udg_PRD_C [ 77 ] = 0.7013
set udg_PRD_C [ 78 ] = 0.71795
set udg_PRD_C [ 79 ] = 0.73418
set udg_PRD_C [ 80 ] = 0.75
set udg_PRD_C [ 81 ] = 0.76543
set udg_PRD_C [ 82 ] = 0.78049
set udg_PRD_C [ 83 ] = 0.79518
set udg_PRD_C [ 84 ] = 0.80952
set udg_PRD_C [ 85 ] = 0.82353
set udg_PRD_C [ 86 ] = 0.83721
set udg_PRD_C [ 87 ] = 0.85057
set udg_PRD_C [ 88 ] = 0.86364
set udg_PRD_C [ 89 ] = 0.8764
set udg_PRD_C [ 90 ] = 0.88889
set udg_PRD_C [ 91 ] = 0.9011
set udg_PRD_C [ 92 ] = 0.91304
set udg_PRD_C [ 93 ] = 0.92473
set udg_PRD_C [ 94 ] = 0.93617
set udg_PRD_C [ 95 ] = 0.94737
set udg_PRD_C [ 96 ] = 0.95833
set udg_PRD_C [ 97 ] = 0.96907
set udg_PRD_C [ 98 ] = 0.97959
set udg_PRD_C [ 99 ] = 0.9899
set udg_PRD_C [ 100 ] = 1.0
endfunction
//===========================================================================
function InitTrig_PRD_Init takes nothing returns nothing
set gg_trg_PRD_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_PRD_Init, function Trig_PRD_Init_Actions )
endfunction
// my first vjass script
// calculate P from the chance of the event before running
// N is the number of times the event is ran before proccing, store N with unit indexer as array
// get PRD_C from the PRD init constants
//
// the C values are calculated in python with script from Rakurai
// because i dont get the maths that dota 2 did, but I at lesat know what they do with the C value
//
//=============================================================================================
// TO USE
// - Use Custom Script ( call Prd.Calc ( P , N ) )
// - Both variables are real numbers, you can make your own global variable
// - P is the chance of your event in a real 0.XX value
// - N is the amount of times the event ran before proccing,
// use a unit indexer to help you store N values per unit as variables
//=============================================================================================
library PrdDist initializer init
globals
private real array C [102]
endglobals
private function init takes nothing returns nothing
set C [1] = 0.00016
set C [2] = 0.00062
set C [3] = 0.00139
set C [4] = 0.00245
set C [5] = 0.0038
set C [6] = 0.00544
set C [7] = 0.00736
set C [8] = 0.00955
set C [9] = 0.01202
set C [10] = 0.01475
set C [11] = 0.01774
set C [12] = 0.02098
set C [13] = 0.02448
set C [14] = 0.02823
set C [15] = 0.03222
set C [16] = 0.03645
set C [17] = 0.04092
set C [18] = 0.04562
set C [19] = 0.05055
set C [20] = 0.0557
set C [21] = 0.06108
set C [22] = 0.06668
set C [23] = 0.07249
set C [24] = 0.07851
set C [25] = 0.08474
set C [26] = 0.09118
set C [27] = 0.09783
set C [28] = 0.10467
set C [29] = 0.11171
set C [30] = 0.11895
set C [31] = 0.12638
set C [32] = 0.134
set C [33] = 0.14181
set C [34] = 0.14981
set C [35] = 0.15798
set C [36] = 0.16633
set C [37] = 0.17491
set C [38] = 0.18362
set C [39] = 0.19249
set C [40] = 0.20155
set C [41] = 0.21092
set C [42] = 0.22036
set C [43] = 0.2299
set C [44] = 0.23954
set C [45] = 0.24931
set C [46] = 0.25987
set C [47] = 0.27045
set C [48] = 0.28101
set C [49] = 0.29155
set C [50] = 0.3021
set C [51] = 0.31268
set C [52] = 0.32329
set C [53] = 0.33412
set C [54] = 0.34737
set C [55] = 0.3604
set C [56] = 0.37322
set C [57] = 0.38584
set C [58] = 0.39828
set C [59] = 0.41054
set C [60] = 0.42265
set C [61] = 0.4346
set C [62] = 0.44642
set C [63] = 0.4581
set C [64] = 0.46967
set C [65] = 0.48113
set C [66] = 0.49248
set C [67] = 0.50746
set C [68] = 0.52941
set C [69] = 0.55072
set C [70] = 0.57143
set C [71] = 0.59155
set C [72] = 0.61111
set C [73] = 0.63014
set C [74] = 0.64865
set C [75] = 0.66667
set C [76] = 0.68421
set C [77] = 0.7013
set C [78] = 0.71795
set C [79] = 0.73418
set C [80] = 0.75
set C [81] = 0.76543
set C [82] = 0.78049
set C [83] = 0.79518
set C [84] = 0.80952
set C [85] = 0.82353
set C [86] = 0.83721
set C [87] = 0.85057
set C [88] = 0.86364
set C [89] = 0.8764
set C [90] = 0.88889
set C [91] = 0.9011
set C [92] = 0.91304
set C [93] = 0.92473
set C [94] = 0.93617
set C [95] = 0.94737
set C [96] = 0.95833
set C [97] = 0.96907
set C [98] = 0.97959
set C [99] = 0.9899
set C [100] = 1
endfunction
struct Prd extends array
public static method Calc takes real P, real N returns nothing
local real r = GetRandomReal ( 0, 1 )
local integer i2 = R2I(P*100)
if i2 > 100 then
set i2 = 100
endif
set udg_PRD_boo = false
if i2 < 0 then
//PRD_boo already false
elseif r <= ( C [ i2 ] * N ) then
set udg_PRD_boo = true
endif
//call DisplayTextToForce( GetPlayersAll(), "P: "+R2S( P ) )
//call DisplayTextToForce( GetPlayersAll(), "C: "+R2S( C[i2] ) )
//call DisplayTextToForce( GetPlayersAll(), "N: "+R2S( N ) )
//call DisplayTextToForce( GetPlayersAll(), "Chance: "+R2S( C [ i2 ] * N ) )
endmethod
endstruct
endlibrary
function KeyPressActions takes nothing returns nothing
local oskeytype pressedkey = BlzGetTriggerPlayerKey()
local item useitem
set udg_item_unit = udg_Hero_Unit [ GetConvertedPlayerId( GetTriggerPlayer()) ]
if (pressedkey == OSKEY_1) then
set useitem = UnitItemInSlot(udg_item_unit,0)
call UnitUseItem(udg_item_unit,useitem)
elseif (pressedkey == OSKEY_2) then
set useitem = UnitItemInSlot(udg_item_unit,1)
call UnitUseItem(udg_item_unit,useitem)
elseif (pressedkey == OSKEY_3) then
set useitem = UnitItemInSlot(udg_item_unit,2)
call UnitUseItem(udg_item_unit,useitem)
elseif (pressedkey == OSKEY_4) then
set useitem = UnitItemInSlot(udg_item_unit,3)
call UnitUseItem(udg_item_unit,useitem)
elseif (pressedkey == OSKEY_5) then
set useitem = UnitItemInSlot(udg_item_unit,4)
call UnitUseItem(udg_item_unit,useitem)
elseif (pressedkey == OSKEY_6) then
set useitem = UnitItemInSlot(udg_item_unit,5)
call UnitUseItem(udg_item_unit,useitem)
endif
endfunction
// @pInt = player number
function InitializeItemHotkey takes integer pInt returns nothing
local trigger keytrig = CreateTrigger()
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_1, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_2, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_3, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_4, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_5, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(keytrig, Player(pInt-1), OSKEY_6, 0, false)
//call TriggerAddCondition(keytrig, null)
call TriggerAddAction(keytrig, function KeyPressActions)
endfunction
function Trig_RGB_Values_Actions takes nothing returns nothing
set udg_Color_r [1] = 255
set udg_Color_g [1] = 60
set udg_Color_b [1] = 60
set udg_Color_r [2] = 60
set udg_Color_g [2] = 60
set udg_Color_b [2] = 255
set udg_Color_r [3] = 60
set udg_Color_g [3] = 200
set udg_Color_b [3] = 200
set udg_Color_r [4] = 230
set udg_Color_g [4] = 230
set udg_Color_b [4] = 250
set udg_Color_r [5] = 255
set udg_Color_g [5] = 255
set udg_Color_b [5] = 0
set udg_Color_r [6] = 255
set udg_Color_g [6] = 165
set udg_Color_b [6] = 0
set udg_Color_r [7] = 60
set udg_Color_g [7] = 255
set udg_Color_b [7] = 60
set udg_Color_r [8] = 255
set udg_Color_g [8] = 192
set udg_Color_b [8] = 203
set udg_Color_r [9] = 211
set udg_Color_g [9] = 211
set udg_Color_b [9] = 211
set udg_Color_r [10] = 173
set udg_Color_g [10] = 216
set udg_Color_b [10] = 230
endfunction
//===========================================================================
function InitTrig_RGB_Values takes nothing returns nothing
set gg_trg_RGB_Values = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_RGB_Values, 0.00 )
call TriggerAddAction( gg_trg_RGB_Values, function Trig_RGB_Values_Actions )
endfunction
// made from (listfile) using python script, aint nobody got time to type this
// apparently there is an easier method using pld file or something, but I cant find a guide on that
function Trig_Preloads_Actions takes nothing returns nothing
call Preload ( "Rock Lee 01.blp" )
call Preload ( "Rock Lee 02.blp" )
call Preload ( "Rock Lee 03.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAbility_Kick.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNFist.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNLee.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAbility_Kick.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNFist.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNLee.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISPASLee.blp" )
call Preload ( "ReplaceableTextures\\PassiveButtons\\PASLee.blp" )
call Preload ( "Glow_Hero_Glow.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTN8Gates.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTN8Gates.blp" )
call Preload ( "VFX_Hit_Y2.blp" )
call Preload ( "VFX_Hit_Y2_soundless_hitstun.mdx" )
call Preload ( "war3mapImported\\groundcrack02_bw.blp" )
call Preload ( "war3mapImported\\flaresimple02_bw.blp" )
call Preload ( "war3mapImported\\flaresimple01_bw.blp" )
call Preload ( "war3mapImported\\dust3.blp" )
call Preload ( "war3mapImported\\btnglacier.blp" )
call Preload ( "VFX_Crystal2.mdx" )
call Preload ( "war3mapImported\\Angry.blp" )
call Preload ( "Buff_Angry_Buff.mdx" )
call Preload ( "AnimeWind.blp" )
call Preload ( "DustWind.blp" )
call Preload ( "VFX_Dust_WindWeak2_Smol.mdx" )
call Preload ( "VFX_Dust_DustWindFaster3_Less.mdx" )
call Preload ( "VFX_Dust_WindWeak2_Smol_Add.mdx" )
call Preload ( "TerrainArt\\Northrend\\North_SnowRock.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNDonut.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSandwich.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNDonut.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSandwich.blp" )
call Preload ( "Item_Donut.mdx" )
call Preload ( "Item_Sandwich_Thicc.mdx" )
call Preload ( "VFX_Spotlight.mdx" )
call Preload ( "war3mapImported\\AshGlow.blp" )
call Preload ( "war3mapImported\\btnorbofcorruption.blp" )
call Preload ( "war3mapImported\\btnorbofvenom.blp" )
call Preload ( "war3mapImported\\bubble.blp" )
call Preload ( "war3mapImported\\flaresimple_bw.blp" )
call Preload ( "war3mapImported\\flaresimple_green.blp" )
call Preload ( "war3mapImported\\heroglow_bw.blp" )
call Preload ( "VFX_Orb of Corruption - Classic.mdx" )
call Preload ( "VFX_Orb of Fire - Classic.mdx" )
call Preload ( "VFX_Orb of Frost - Classic.mdx" )
call Preload ( "VFX_Orb of Poison - Classic.mdx" )
call Preload ( "war3mapImported\\organicblobs_hblood_2x2_demon.blp" )
call Preload ( "war3mapImported\\rune_unholyaura_bw_2x2.blp" )
call Preload ( "war3mapImported\\shockwavesoft03_bw.blp" )
call Preload ( "war3mapImported\\shockwavewarp01_bw.blp" )
call Preload ( "war3mapImported\\shockwavewarp_bw.blp" )
call Preload ( "war3mapImported\\smoke_bw.blp" )
call Preload ( "war3mapImported\\snowflakes_bw_2x2.blp" )
call Preload ( "war3mapImported\\spikebeam_green.blp" )
call Preload ( "war3mapImported\\wavering_bw.blp" )
call Preload ( "VFX_Lee_Dpunch.mdx" )
call Preload ( "war3mapImported\\Glow1_256.blp" )
call Preload ( "war3mapImported\\Ring4_128.blp" )
call Preload ( "war3mapImported\\Smoke_128.blp" )
call Preload ( "war3mapImported\\Smoke2X2_256.blp" )
call Preload ( "war3mapImported\\Wavy_256.blp" )
call Preload ( "VFX_Recall_2_End.mdx" )
call Preload ( "VFX_Speed_Arrow.mdx" )
call Preload ( "Item_Canister_Red_Tier1.mdx" )
call Preload ( "Item_Canister_Red_Tier2.mdx" )
call Preload ( "Dood_ThievesGuild.mdx" )
call Preload ( "war3mapImported\\Mercenary.blp" )
call Preload ( "Dood_RockGate.mdx" )
call Preload ( "VFX_Heal Gold.mdx" )
call Preload ( "RadiantGlow.blp" )
call Preload ( "VFX_Soul Discharge.mdx" )
call Preload ( "VFX_Soul Discharge Red.mdx" )
call Preload ( "VFX_Soul Discharge Purple.mdx" )
call Preload ( "VFX_Soul Discharge Blue.mdx" )
call Preload ( "war3mapImported\\cleanwave_bw01.blp" )
call Preload ( "war3mapImported\\eleccircle01_bw_2x1.blp" )
call Preload ( "VFX_Gravity Storm - Classic.mdx" )
call Preload ( "war3mapImported\\RoyalGlow.blp" )
call Preload ( "war3mapImported\\sphericalaura_bw.blp" )
call Preload ( "war3mapImported\\tail_dust3.blp" )
call Preload ( "VFX_Died.blp" )
call Preload ( "VFX_You_Died.mdx" )
call Preload ( "VFX_Menacing.mdx" )
call Preload ( "VFX_Menacing128.blp" )
call Preload ( "Unit_ObsidianGolem.mdx" )
call Preload ( "UI\\Feedback\\HpBarConsole\\human-healthbar-fill.blp" )
call Preload ( "RepleaceableTextures\\Selection\\SelectionCircleSmall.blp" )
call Preload ( "RepleaceableTextures\\Selection\\SelectionCircleMed.blp" )
call Preload ( "RepleaceableTextures\\Selection\\SelectionCircleLarge.blp" )
call Preload ( "UI\\Console\\Human\\HumanUITile05.dds" )
call Preload ( "UI\\Console\\Human\\HumanUITile06.dds" )
call Preload ( "VFX_DuelFX_Circle_Blu_2.mdx" )
call Preload ( "VFX_DuelFX_Circle_Red_2.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNBlink_V2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNBlink_V2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAbility_Vanish.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAbility_Vanish.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNDunk2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNDunk2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNGaara.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSand_1.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNGaara.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSand_1.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISPASGaara.blp" )
call Preload ( "ReplaceableTextures\\PassiveButtons\\PASGaara.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSandStorm.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSandstorm3.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSandStorm.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSandstorm3.blp" )
call Preload ( "Gaara.blp" )
call Preload ( "VFX_Gaara_Sand_Shield.blp" )
call Preload ( "VFX_Gaara_Sand_Tex.blp" )
call Preload ( "VFX_Gaara_Sand_Explode_Up.mdx" )
call Preload ( "VFX_Gaara_SandAura.MDX" )
call Preload ( "VFX_Gaara_SandExplosion.mdx" )
call Preload ( "VFX_Gaara_Sand_shield.mdx" )
call Preload ( "VFX_Gaara_Missile 2.mdx" )
call Preload ( "VFX_Spell_Marker.blp" )
call Preload ( "VFX_Gaara_Sand_Hand.blp" )
call Preload ( "VFX_Gaara_Sand Tomb.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSlow1.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSlow2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNSlow3.BLP" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSlow1.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSlow2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNSlow3.BLP" )
call Preload ( "Buff_Magic Block armor.mdx" )
call Preload ( "VFX_Recall_2_Loop_2.mdx" )
call Preload ( "VFX_Gaara_Sand Wave Big.mdx" )
call Preload ( "VFX_Gaara_Sand_Explode_Up_Big.mdx" )
call Preload ( "Hero_Gaara_f3.mdx" )
call Preload ( "VFX_Gaara_Sand_Hand_1.mdx" )
call Preload ( "VFX_Gaara_Sand Pit 2.mdx" )
call Preload ( "VFX_Gaara_SandWaveDamage.mdx" )
call Preload ( "VFX_Gaara_SandTrap.mdx" )
call Preload ( "VFX_Gaara_Sand_Tomb_CD_6_3.mdx" )
call Preload ( "VFX_Gaara_Sand_Tomb_CD_7.mdx" )
call Preload ( "VFX_Lee_Punches 2.mdx" )
call Preload ( "VFX_Hit_Y1.blp" )
call Preload ( "VFX_Hit_Y1_Hitstun.mdx" )
call Preload ( "VFX_Ribbon_Trail_Y.mdx" )
call Preload ( "VFX_Lee_Aura.mdx" )
call Preload ( "Spell_Marker_100.mdx" )
call Preload ( "VFX_shukaku spear.BLP" )
call Preload ( "VFX_Gaara_Sand Spear 2.mdx" )
call Preload ( "VFX_Gaara_SandAura_4s_2.MDX" )
call Preload ( "VFX_Lee_SpinFX2_2.mdx" )
call Preload ( "Hero_Tex_Metal_Bat.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNHero_MBat.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNHero_MBat_Dragon.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHero_MBat.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHero_MBat_Dragon.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISPASHero_MBat.blp" )
call Preload ( "ReplaceableTextures\\PassiveButtons\\PASHero_MBat.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNHero_Mbat_BloodTornado.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNHero_Mbat_Uppercut.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHero_Mbat_BloodTornado.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHero_Mbat_Uppercut.blp" )
call Preload ( "VFX_tsunadeslam.mdx" )
call Preload ( "SFX_DrekTharA_Ending_Blue00.wav" )
call Preload ( "SFX_DrekTharA_Ending_Red00.wav" )
call Preload ( "SFX_DrekTharA_Epic00.wav" )
call Preload ( "SFX_DrekTharA_FirstBlood_Blue00.wav" )
call Preload ( "SFX_DrekTharA_FirstBlood_Red00.wav" )
call Preload ( "SFX_DrekTharA_HeroKill00.wav" )
call Preload ( "SFX_DrekTharA_HeroKill01.wav" )
call Preload ( "SFX_DrekTharA_Legendary00.wav" )
call Preload ( "SFX_DrekTharA_MegaKill02.wav" )
call Preload ( "SFX_DrekTharA_PlayerAbandon00.wav" )
call Preload ( "SFX_DrekTharA_SpreeStart00.wav" )
call Preload ( "SFX_DrekTharA_TeamKill_Blue00.wav" )
call Preload ( "SFX_DrekTharA_TeamKill_Red00.wav" )
call Preload ( "SFX_DrekTharA_GameStart00.wav" )
call Preload ( "SFX_DrekTharA_SpreeEnd00.wav" )
call Preload ( "Buff_Alacrity.mdx" )
call Preload ( "Buff_Armor Penetration Blue.mdx" )
call Preload ( "Buff_Armor Penetration Green.mdx" )
call Preload ( "Buff_Armor Penetration Orange.mdx" )
call Preload ( "Buff_Armor Penetration Purple.mdx" )
call Preload ( "Buff_Armor Penetration Red.mdx" )
call Preload ( "Buff_Armor Stimulus Blue.mdx" )
call Preload ( "Buff_Burning Rage Green.mdx" )
call Preload ( "Buff_Burning Rage Orange.mdx" )
call Preload ( "Buff_Burning Rage Purple.mdx" )
call Preload ( "Buff_Burning Rage Red.mdx" )
call Preload ( "CrimsonGlow2.blp" )
call Preload ( "Buff_Ember Blue.mdx" )
call Preload ( "Buff_Ember Green.mdx" )
call Preload ( "Buff_Ember Purple.mdx" )
call Preload ( "Buff_Ember Red.mdx" )
call Preload ( "Buff_Ember Teal.mdx" )
call Preload ( "Buff_Ember Yellow.mdx" )
call Preload ( "Buff_Ember.mdx" )
call Preload ( "EmberGlow7.blp" )
call Preload ( "Buff_First_Aid.mdx" )
call Preload ( "Buff_Infernal_Bulwark.mdx" )
call Preload ( "Buff_Infernal_Bulwark_Null.mdx" )
call Preload ( "RoyalGlow02.blp" )
call Preload ( "VerdantGlow3.blp" )
call Preload ( "Buff_Armor Stimulus Orange Plus.mdx" )
call Preload ( "VFX_MBat_animeslashfinal_uppercut.mdx" )
call Preload ( "animeslash.blp" )
call Preload ( "animeslashp.blp" )
call Preload ( "Hero_Metal Bat OPM 4.mdx" )
call Preload ( "VFX_MBat_Pummelling 2.mdx" )
call Preload ( "Fire_Nova.blp" )
call Preload ( "VFX_FireNova.mdx" )
call Preload ( "VFX_MBat_Pummelling_x2.mdx" )
call Preload ( "Buff_Armor Stimulus Green.mdx" )
call Preload ( "Hero_Ghiaccio.blp" )
call Preload ( "Hero_Ghiaccio_opt.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNGhiaccio.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNGhiaccio.blp" )
call Preload ( "ReplaceableTextures\\PassiveButtons\\PASGhiaccio.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISPASGhiaccio.blp" )
call Preload ( "VFX_GhIce Shard.mdx" )
call Preload ( "VFX_GhIceNova.mdx" )
call Preload ( "VFX_GhSleet Storm.mdx" )
call Preload ( "Buff_Shield.mdx" )
call Preload ( "VFX_Shield.blp" )
call Preload ( "VFX_GhIce_Floor2.mdx" )
call Preload ( "VFX_ProgressBar_HappyTauren.mdx" )
call Preload ( "Buff_Disarm2.mdx" )
call Preload ( "war3mapImported\\Disarm_buff.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNDisarm_Icon3.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNDisarm_Icon3.blp" )
call Preload ( "Spell_Marker_100_1s-but-2s_2.mdx" )
call Preload ( "VFX_Battle Standard Classic.mdx" )
call Preload ( "war3mapImported\\flarering_bw.blp" )
call Preload ( "war3mapImported\\flareshot01_bw.blp" )
call Preload ( "Buff_Bleed_Hemorrhage.mdx" )
call Preload ( "war3mapImported\\OrderFlag3.blp" )
call Preload ( "Buff_Safeguard Classic.mdx" )
call Preload ( "SFX_Hero_Ghiaccio ult2.wav" )
call Preload ( "SFX_Hero_Gaara ult.wav" )
call Preload ( "SFX_Hero_Lee ult daisenpuu.wav" )
call Preload ( "SFX_Hero_Lee ult On.wav" )
call Preload ( "VFX_Culling Cleave Red.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNOrange.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNOrange.blp" )
call Preload ( "VFX_Substitute_Stand.mdx" )
call Preload ( "VFX_Substitute_Slanted.mdx" )
call Preload ( "Buff_Stun_AnimatedBash.mdx" )
call Preload ( "Animatedbash.blp" )
call Preload ( "Father1.blp" )
call Preload ( "Father2.blp" )
call Preload ( "Boss_GilgameshExtra.mdx" )
call Preload ( "GilgameshExtra.blp" )
call Preload ( "Pacifista.BLP" )
call Preload ( "Boss_vfx_laser.MDX" )
call Preload ( "Boss_vfx_Earth NovaTarget.mdx" )
call Preload ( "VFX_Mbat_animeslashfinal.mdx" )
call Preload ( "SFX_Hero_MBat ult-s.wav" )
call Preload ( "VFX_MBat_Ephemeral Slash Red_z100_2.mdx" )
call Preload ( "VFX_Goal_Bonus.blp" )
call Preload ( "VFX_Goal2.mdx" )
call Preload ( "VFX_Goal_Bonus2.mdx" )
call Preload ( "VFX_Goal_Break2.mdx" )
call Preload ( "VFX_Hero_Destroyed.mdx" )
call Preload ( "VFX_Hero_Destroyed.blp" )
call Preload ( "Hero_Aang.blp" )
call Preload ( "VFX_Aang_TornadoMissile.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_Avatar.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_WindLance.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_Avatar.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_WindLance.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISPASAang2.blp" )
call Preload ( "ReplaceableTextures\\PassiveButtons\\PASAang2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_earth.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_fire.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_water.blp" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_wind.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_earth.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_fire.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_water.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_wind.blp" )
call Preload ( "VFX_Aang_Change.mdx" )
call Preload ( "VFX_Aang_OrbOfSeas 2.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNAang_4_elements.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNAang_4_elements.blp" )
call Preload ( "VFX_Aang_RockMissile.mdx" )
call Preload ( "Hero_Aang_RippedBigBellies_5.mdx" )
call Preload ( "Spell_Marker_QuarterCircle_100.mdx" )
call Preload ( "VFX_Aang_Air_Blast_2.mdx" )
call Preload ( "SFX_Hero_Aang_ult.flac" )
call Preload ( "VFX_Aang_Avatar_3.mdx" )
call Preload ( "VFX_Aang_Wind Ball 2.mdx" )
call Preload ( "Boss_VFX_BeamMissile.mdx" )
call Preload ( "Boss_VFX_HellBond.mdx" )
call Preload ( "Boss_VFX_Magma Slam_200.mdx" )
call Preload ( "Boss_VFX_Artillery.mdx" )
call Preload ( "Boss_Father2.mdx" )
call Preload ( "laser1_Y.blp" )
call Preload ( "laser1.blp" )
call Preload ( "Boss_VFX_laser_yellow_2.MDX" )
call Preload ( "Boss_Pacifista Fix.mdx" )
call Preload ( "Timer_ClockRune_30s_Kino.mdx" )
call Preload ( "Timer_Countdown_60s_btr.mdx" )
call Preload ( "VFX_Hero_SLASH.mdx" )
call Preload ( "VFX_Slash.blp" )
call Preload ( "Dood_Smith_GiFun.mdx" )
call Preload ( "Dood_Mr. Goblin's Stall_deolrin.mdx" )
call Preload ( "VFX_ProgressBar_Round_fix_fatter.mdx" )
call Preload ( "Boss_VFX_Firebolt Classic.mdx" )
call Preload ( "war3mapImported\\fb_whisp_fire_8x8.blp" )
call Preload ( "war3mapImported\\flareshot_tail.blp" )
call Preload ( "war3mapImported\\largesmoke1.blp" )
call Preload ( "war3mapImported\\moon_bw.blp" )
call Preload ( "Boss_VFX_laser_yellow_short.MDX" )
call Preload ( "SFX_DrekTharA_HeroSlain_Neutral.flac" )
call Preload ( "SFX_TF2_Hit_1.flac" )
call Preload ( "SFX_TF2_Hit_Crit.flac" )
call Preload ( "SFX_Item.flac" )
call Preload ( "SFX_Item_2.flac" )
call Preload ( "SFX_Item_Lost.flac" )
call Preload ( "Critter_Mettaur1.1_ByEpsilon.mdx" )
call Preload ( "MettaurTexture.blp" )
call Preload ( "SFX_Fanfare2_audeption.flac" )
call Preload ( "SFX_Fanfare1_robinhood76.flac" )
call Preload ( "Buff_Shield_Defensive Barrier big.mdx" )
call Preload ( "Buff_Shield_Energy Shield.mdx" )
call Preload ( "Buff_Shield_FrozenShell.MDX" )
call Preload ( "Buff_Shield_RuneShell.mdx" )
call Preload ( "VFX_Rune_J.blp" )
call Preload ( "Boss_Spawn_MassTeleportCaster.mdx" )
call Preload ( "massteleportcircle.blp" )
call Preload ( "VFX_Aang_Water Shot_e2.mdx" )
call Preload ( "ReplaceableTextures\\CommandButtons\\BTNStop2.blp" )
call Preload ( "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNStop2.blp" )
call Preload ( "SFX_BGM_Anime_Unite_Mix1.flac" )
call Preload ( "LoadingScreen.mdx" )
call Preload ( "Timer_ClockRune_150s_Kino.mdx" )
call Preload ( "SFX_Cine4_c.flac" )
call Preload ( "SFX_Cine1_c.flac" )
call Preload ( "SFX_Cine2_c.flac" )
call Preload ( "SFX_Cine3_c.flac" )
call Preload ( "Spell_Marker_Spike_100.mdx" )
call Preload ( "VFX_Spell_Marker_Spike.blp" )
call Preload ( "Timer_Countdown_10s.mdx" )
call Preload ( "VFX_Lee_Punches_Fire.mdx" )
call Preload ( "SFX_Hero_Lee ult Asa Niwatori.flac" )
call Preload ( "SFX_Hero_Lee ult daisenpuu2.flac" )
call Preload ( "FullScreen.tga" )
call Preload ( "Unit_Dummy.mdx" )
call Preload ( "Dood_AnimatedGrass_White.mdx" )
call Preload ( "Grass_white.blp" )
call Preload ( "Dood_Tall_Grass_animated.blp" )
call Preload ( "Dood_Tall_Grass2.mdx" )
call Preload ( "Hero_Rock Lee2.mdx" )
call Preload ( "Hero_Zenitsu_opt.mdx" )
call Preload ( "Hero_Zenitsu.blp" )
call Preload ( "VFX_ProgressBar_Round_fix2.mdx" )
call Preload ( "SFX_Hero_Mihile.flac" )
call Preload ( "SFX_Hero_Aegi.flac" )
endfunction
//===========================================================================
function InitTrig_Preloads takes nothing returns nothing
set gg_trg_Preloads = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Preloads, 0.00 )
call TriggerAddAction( gg_trg_Preloads, function Trig_Preloads_Actions )
endfunction
library HeroRevival requires TimerUtils
//*******************************************************************************************************************************
//
// This is just a simple hero revival
// by baassee
// Credits is appreciated
// and please credit Bribe too for his brilliant remake.
//
// *Requires:
// TimerUtils by Vexorian
// A vJass Compiler
//
//
// Credits flies out to:
// Axarion for showing me his scope
// Hell Gate and Deaod for their Health Reserve system, taught me alot
// Vexorian for TimerUtils, JassHelper and vJass
// Bribe for recoding the system.
//
// How to use:
// This library provides you with these functions
// function HeroRevive takes unit hero, real time, real x, real y, boolean eff
// function HeroReviveLoc takes unit hero, real time, location loc, boolean eff
//
// The unit hero is obviously the hero you are going to revive.
// The real time is the time you want to revive your hero.
// ps. you can set this to 0 and use the GetTime func to make your formula.
// The real x states which x coordinate where you are going to revive your hero.
// The real y states which y coordinate where you are going to revive your hero.
// The location loc is for those who don't know to use coordinates.
// The boolean eff is for show or not show rebirth effect.
//
// Example 1:
// call HeroRevive(GetTriggerUnit(), 30., 0., 0., true)
//
// If you use this with an event "A Unit Dies" then it will
// Revive the dying unit, revive it after 30 seconds at coord (0,0) showing revival effect
//
// Example 2:
// call HeroRevive(GetTriggerUnit(), 0., GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), false)
//
// If you use this as said above it will
// Revive the dying unit, it will USE the formula function so you better customize it there.
// It will revive where it died and will not show revival effect.
//
// Example 3:
// call HeroReviveLoc(GetTriggerUnit(), 0., udg_TempLoc, true)
//
// If you use this as said above with a location for all GUI users it will
// Revive the dying unit, it will USE the formula function so you better customize it there.
// It will revive the unit at a location you've set
// Just remember to remove the location afterwards!
//
// End of Documentation
//
//***************************************************************************************************************************
//
// SETUP
//
//
globals
//
//*************GUI USERS LOOK BELOW HERE****************************
//
// This variable is where you can set how fast the camera should pan to the revived unit.
// As this usally is set to a low value, lower the greater the size is, you can set it
// to 0. if you want to, then it will be panned instantly.
//
private constant real PANCAM = 0.3
endglobals
private function GetAdjustedTime takes real time, unit hero returns real
return time + 0. * GetHeroLevel(hero)
//if you want something extra or you can set the time to 0
//and use this for a formula instead
//I call this function for the formula func in the documentation
endfunction
private function FilterHero takes unit u returns boolean
//ORIGINAL return IsUnitType(u, UNIT_TYPE_HERO) and IsUnitType(u, UNIT_TYPE_DEAD)
return IsUnitType(u, UNIT_TYPE_DEAD)
//just check if the unit is a hero
//and to check if the unit is already dead (thanks to axarion for this one)
//you can edit the filter if you want
endfunction
// END SETUP
//******************************************************************************************************************************
//
globals
//
// To make sure that the users wont run several instances with the same unit
//
private group NOSTACK = CreateGroup()
endglobals
private struct data extends array
static integer i = 0
static integer array r
unit hero
real x
real y
boolean eff
endstruct
private function finish takes nothing returns nothing
local timer t = GetExpiredTimer()
local data dat = GetTimerData(t)
call ReleaseTimer(t) //recycle timer
set t = null
call ReviveHero(dat.hero, dat.x, dat.y, dat.eff) //revive hero
call GroupRemoveUnit(NOSTACK, dat.hero)
// custom add
//haste on revive
set udg_target_caster = dat.hero
set udg_target_target_u = dat.hero
set udg_target_duration_r = 6.0
set udg_target_abil_type = 'A01W'
set udg_target_boo_isPosBuff = true
call ConditionalTriggerExecute( gg_trg_slowbased_dummy )
// custom end
if GetLocalPlayer() == GetOwningPlayer(dat.hero) then
call PanCameraToTimed(dat.x, dat.y, PANCAM)
call ClearSelection()
call SelectUnit(dat.hero, true)
endif
// camera
set udg_Cam_P = GetConvertedPlayerId(GetOwningPlayer(dat.hero))
call ConditionalTriggerExecute( gg_trg_Camera_Run_Event )
// camera end
set data.r[0] = data.r[data.r[0]]
set data.r[data.r[0]] = dat
endfunction
function HeroRevive takes unit hero, real time, real x, real y, boolean eff returns nothing
local data dat
local timer t
if FilterHero(hero) and not IsUnitInGroup(hero, NOSTACK) then
if 0 == data.r[0] then
set data.i = data.i + 1
set dat = data.i
else
set dat = data.r[0]
set data.r[0] = data.r[data.r[0]]
endif
set t = NewTimer()
set dat.hero = hero
set dat.x = x
set dat.y = y
set dat.eff = eff
call GroupAddUnit(NOSTACK, hero)
call SetTimerData(t, dat)
call TimerStart(t, GetAdjustedTime(time, hero), false, function finish)
set t = null
debug else
debug call BJDebugMsg("HeroRevival Error: The unit is either alive or isn't a hero unit or is already in the system, please check your trigger calls.")
endif
endfunction
function HeroReviveLoc takes unit hero, real time, location loc, boolean eff returns nothing
call HeroRevive(hero, time, GetLocationX(loc), GetLocationY(loc), eff)
endfunction
endlibrary
function Trig_Bush_Init_Actions takes nothing returns nothing
set udg_Bush_g_vision = CreateGroup()
set udg_Bush_region[0] = gg_rct_Region_012
set udg_Bush_region[1] = gg_rct_Region_012_Copy
set udg_Bush_region[2] = gg_rct_Region_014
set udg_Bush_region[3] = gg_rct_Region_014_Copy
set udg_Bush_region[4] = gg_rct_Region_016
set udg_Bush_region[5] = gg_rct_Region_016_Copy
set udg_Bush_region[6] = gg_rct_Region_018
set udg_Bush_region[7] = gg_rct_Region_018_Copy
set udg_Bush_region[8] = gg_rct_Region_020
set udg_Bush_region[9] = gg_rct_Region_020_Copy
set udg_Bush_region[10] = gg_rct_Region_022
set udg_Bush_region[11] = gg_rct_Region_022_Copy
set udg_Bush_region[12] = gg_rct_Region_024
set udg_Bush_region[13] = gg_rct_Region_024_Copy
set udg_Bush_region[14] = gg_rct_Region_026
set udg_Bush_region[15] = gg_rct_Region_026_Copy
set udg_Bush_region[16] = gg_rct_Region_028
set udg_Bush_region[17] = gg_rct_Region_028_Copy
set udg_Bush_region[18] = gg_rct_Region_030
set udg_Bush_region[19] = gg_rct_Region_030_Copy
set udg_Bush_region[20] = gg_rct_Region_032
set udg_Bush_region[21] = gg_rct_Region_033
set udg_Bush_region[22] = gg_rct_Region_033_Copy
set udg_Bush_region[23] = gg_rct_Region_035
set udg_Bush_region[24] = gg_rct_Region_035_Copy
set udg_Bush_region[25] = gg_rct_Region_037
set udg_Bush_max_int = 25
set udg_TempInt1 = 0
loop
exitwhen udg_TempInt1 > udg_Bush_max_int
call TriggerRegisterEnterRectSimple( gg_trg_Bush_Entering, udg_Bush_region[udg_TempInt1] )
call TriggerRegisterLeaveRectSimple( gg_trg_Bush_Leaving, udg_Bush_region[udg_TempInt1] )
set udg_TempInt1 = udg_TempInt1 + 1
endloop
endfunction
//===========================================================================
function InitTrig_Bush_Init takes nothing returns nothing
set gg_trg_Bush_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Bush_Init, function Trig_Bush_Init_Actions )
endfunction
function Trig_Cam_Shake_dummy_Actions takes nothing returns nothing
local player p
local integer i
local real r_dur
local real r_mag
set r_dur = udg_CamShake_Dur
set r_mag = udg_CamShake_Mag
set p = udg_CamShake_Player
set i = GetConvertedPlayerId(p)
if udg_Dummy_CamShake[ i ] == false then
set udg_Dummy_CamShake[ i ] = true
call CameraSetEQNoiseForPlayer( p, r_mag )
call TriggerSleepAction( r_dur )
call CameraClearNoiseForPlayer( p )
set udg_Dummy_CamShake[ i ] = false
endif
set p = null
endfunction
//===========================================================================
function InitTrig_Cam_Shake_dummy takes nothing returns nothing
set gg_trg_Cam_Shake_dummy = CreateTrigger( )
call TriggerAddAction( gg_trg_Cam_Shake_dummy, function Trig_Cam_Shake_dummy_Actions )
endfunction
function Trig_Item_Oranges_Init_Actions takes nothing returns nothing
set udg_Itm_UseOrder [1] = 852008
set udg_Itm_UseOrder [2] = 852009
set udg_Itm_UseOrder [3] = 852010
set udg_Itm_UseOrder [4] = 852011
set udg_Itm_UseOrder [5] = 852012
set udg_Itm_UseOrder [6] = 852013
endfunction
//===========================================================================
function InitTrig_Item_Oranges_Init takes nothing returns nothing
set gg_trg_Item_Oranges_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Item_Oranges_Init, function Trig_Item_Oranges_Init_Actions )
endfunction