function StartGameSound(whichPlayer)
if (udg_StartGameSound == nil) then
udg_StartGameSound = CreateSoundFromLabel('H02Arthas03',false,false,false,10,10)
end
if (GetLocalPlayer()==whichPlayer) then
StartSound(udg_StartGameSound)
end
end
function ErrorMessage(error, whichPlayer)
if udg_ErrorSound == nil then
udg_ErrorSound = CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
end
local error = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00"+error+"|r"
if (GetLocalPlayer()==whichPlayer) then
ClearTextMessages()
DisplayTimedTextToPlayer(whichPlayer,0.52,0.96,2,error)
StartSound(udg_ErrorSound)
end
end
Name | Type | is_array | initial_value |
A | integer | No | |
AbductTable | hashtable | No | |
AfterDamageEvent | real | No | |
ambush_level | integer | No | |
Ambush_unit_preset | unitcode | Yes | |
AmbushersTable | hashtable | No | |
AmbusherWaitGroup | group | No | |
AMSAmount | real | Yes | |
angle | real | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
AOEString | string | No | |
ArcaneRunes_Group | group | No | |
ArcaneUnit | unit | No | |
Archives_Type | abilcode | 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 | |
armor_var | real | No | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
BarrageAlreadyDMG | group | No | |
Brainwash | hashtable | No | |
BrainwashUnits | group | No | |
BreezeGroup | group | No | |
Broodaura_HP_Bonus | abilcode | Yes | |
BroodCareHealTarget | unit | No | |
BroodCareLifeMeter | real | No | |
BroodGuardTable | hashtable | No | |
BroodKeeperMinions | hashtable | No | |
BS_Bonus_Ability | abilcode | Yes | |
BS_Buff | buffcode | Yes | |
BS_Buff_Ability | abilcode | Yes | |
BS_Buff_Category | integer | Yes | |
BS_Buff_Duration | real | Yes | |
BS_Buff_Type | integer | Yes | |
BS_Buffed_Event | real | No | |
BS_Buffed_Unit | unit | Yes | |
BS_Buffing_Unit | unit | Yes | |
BS_Event_Index | integer | No | |
BS_Index1 | integervar | No | |
BS_Index2 | integer | No | |
BS_Index3 | integervar | No | |
BS_IntegerA | integervar | No | |
BS_MagicImmune | boolean | Yes | |
BS_MaxStack | integer | Yes | |
BS_Permanent | boolean | Yes | |
BS_Recycle | boolean | No | |
BS_Stack | integer | Yes | |
BS_Use_Bonus | boolean | Yes | |
BuildHastable | hashtable | No | |
buildings_BuildNaga | group | No | |
BurrowedUnit | unit | No | |
Caster | unit | No | |
CasterMindBlast | unit | No | |
CatchFishTable | hashtable | No | |
ChooseRace | button | Yes | |
ChoosingRace | dialog | No | |
ClearDamageEvent | trigger | No | |
CocoonGroup | group | No | |
CocoonHashTable | hashtable | No | |
CocoonTimer | real | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
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 | |
DamageAmount | real | No | |
DamageBlockingAbility | abilcode | No | |
DamageEngineEnabled | boolean | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventUserAmt | real | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterConfigured | boolean | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
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 | |
Debuff_Buffs | buffcode | Yes | |
Debuff_IntegerA | integervar | No | |
Debuff_IntegerB | integervar | No | |
Debuff_Number | integer | No | |
Debuff_Unit | unit | No | |
DeepFreezeGroup | group | No | |
DeepFreezeTable | hashtable | 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 | |
DestinyOverTimeUnits | group | No | |
DestinyRemainingTime | real | No | |
DestinyTable | hashtable | No | |
Devour_table | hashtable | No | |
DevourGroup | group | No | |
Dispell_BuffCount | integer | No | |
Dispell_Buffs_Number | integer | No | |
Dispell_Buffs_Type | integer | No | |
Dispell_Categories | integer | No | |
Dispell_Category | integer | Yes | |
Dispell_IntegerA | integervar | No | |
Dispell_IntegerB | integervar | No | |
Dispell_Target | unit | No | |
Distance | real | No | |
DiveAttackAudioInt | integer | No | |
DiveAttackCanceled | boolean | Yes | |
DiveAttackCaster | unit | Yes | |
DiveAttackChaseDur | real | No | |
DiveAttackCooldownMax | real | No | |
DiveAttackCooldownMin | real | No | |
DiveAttackCooldownTimer | real | Yes | |
DiveAttackDamage | real | Yes | |
DiveAttackDamageMax | real | No | |
DiveAttackDamageMin | real | No | |
DiveAttackDir | real | No | |
DiveAttackDist | real | No | |
DiveAttackGroup | group | No | |
DiveAttackGroupAutocast | group | No | |
DiveAttackHeal | real | Yes | |
DiveAttackHealMultiplier | real | No | |
DiveAttackHeight | real | Yes | |
DiveAttackHeightLoss | real | No | |
DiveAttackIndex | integer | No | |
DiveAttackLocCasterCurrent | location | No | |
DiveAttackLocCasterNew | location | No | |
DiveAttackLocCursor | location | No | |
DiveAttackLoop | integervar | No | |
DiveAttackMaxDur | real | Yes | |
DiveAttackMoveSpeed | real | No | |
DiveAttackSpeed | real | Yes | |
DiveAttackSpeedMultiplier | real | No | |
DiveAttackState | integer | Yes | |
DiveAttackTarget | unit | Yes | |
DiveAttackUnit | unit | Yes | |
dmg | real | No | |
DmgEvBracers | itemcode | No | |
DmgEvMana | real | No | |
DmgEvManaMult | real | No | |
DmgEvMSlvl | integer | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
DummyDamageRetraction | hashtable | No | |
EmberGroup | group | No | |
EnemiesRiptide | group | No | |
EnhancedDamageTarget | unit | No | |
ErrorMessage | string | No | |
ErrorPlayer | player | No | |
ErrorSound | sound | No | |
Exp | integer | Yes | |
ExpTable | hashtable | No | |
FadeSystemGroup | group | No | |
FadeSystemHash | hashtable | No | |
FadeUnitKey | integer | No | |
FearGroup | group | No | |
FearTable | hashtable | No | |
FL_Ability | abilcode | No | |
FL_Alpha | real | Yes | |
FL_Caster | unit | Yes | |
FL_CasterLoc | location | Yes | |
FL_CheckVisibility | boolean | No | |
FL_CollisionBoolean | boolean | No | |
FL_CutRange | real | No | |
FL_Duration | real | Yes | |
FL_Lightning | lightning | Yes | |
FL_MaxDistance | real | No | |
FL_PercentDamage | real | Yes | |
FL_SE | effect | Yes | |
FL_SlowFactor | real | No | |
FL_StringSE | string | No | |
FL_StringSE2 | string | No | |
FL_Target | unit | Yes | |
FL_TargetLoc | location | Yes | |
FL_UnitDistance | real | Yes | |
FSBlue | real | No | |
FSEnd | real | No | |
FSFadeIn | boolean | No | |
FSGreen | real | No | |
FSRed | real | No | |
FSRemove | boolean | No | |
FSSpeed | real | No | |
FSStart | real | No | |
FSStartOpacity | real | No | |
FSTinted | boolean | No | |
FSUnit | unit | No | |
Gamers | force | No | |
Gold | integer | No | |
GuardianCooldownGroup | group | No | |
Handle | integer | No | |
handle | handle | No | |
hash_BuildNaga | hashtable | No | |
HashTable_ArcaneRunes | hashtable | No | |
HashtableRiptide | hashtable | No | |
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 | |
HideDamageFrom | boolean | Yes | |
HM_Angle | real | Yes | |
HM_Angle_Add | real | Yes | |
HM_CASTER | unit | No | |
HM_CHECK | boolean | No | |
HM_Check_Homing | boolean | Yes | |
HM_Count | integer | Yes | |
HM_Damage | real | Yes | |
HM_DAMAGE | real | No | |
HM_Distance | real | Yes | |
HM_DISTANCE | real | No | |
HM_Distance2 | real | Yes | |
HM_Group | group | Yes | |
HM_LEVEL | integer | No | |
HM_Mui | integer | Yes | |
HM_Point_Dummy | location | Yes | |
HM_Points | location | Yes | |
HM_Sfx | string | Yes | |
HM_SFX | string | No | |
HM_Speed | real | Yes | |
HM_SPEED | real | No | |
HM_Speed_Add | real | Yes | |
HM_SPEED_ADD | real | No | |
HM_Unit_Caster | unit | Yes | |
HM_Unit_Dummy | unit | Yes | |
HM_Unit_Target | unit | Yes | |
HM_Unit_Type | unitcode | No | |
i | integer | No | |
ImpaleDMG | boolean | No | |
Index | integer | Yes | |
InfestedBuildingTable | hashtable | No | |
Intrappola_Bi | boolean | Yes | |
Intrappola_BOOL | boolean | Yes | |
Intrappola_Caster | unit | Yes | |
Intrappola_Count | integer | Yes | |
Intrappola_Distance | real | Yes | |
Intrappola_Effect1 | effect | Yes | |
Intrappola_Light | lightning | Yes | |
Intrappola_Target | unit | Yes | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
Jump_Caster | unit | No | |
Jump_Hashtable | hashtable | No | |
Jump_Leapers | group | No | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LifeForQueenTable | hashtable | No | |
LifefortheQueen_Group | group | No | |
Lightning | lightning | No | |
LightningRodGroup | group | No | |
LightningRodTable | hashtable | No | |
LitCandleTable | hashtable | No | |
LivingWaterGroup | group | No | |
LivingWaterTable | hashtable | No | |
ManabugTable | hashtable | No | |
MathSacrifice | real | No | |
MindBlastTable | hashtable | No | |
MuddyWaters | hashtable | No | |
MuddyWatersUnits | group | No | |
MurlocOrderTable | hashtable | No | |
MurlocTideDamage | group | No | |
NagaOverseerTable | hashtable | No | |
NerubianHashtable | hashtable | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NextHealAmount | real | No | |
NextHealSource | unit | No | |
NextHealTarget | unit | No | |
OnDamageEvent | real | No | |
Order | ordercode | No | |
Overseers | integer | Yes | 1 |
Point | location | No | |
Point_2 | location | No | |
Point_3 | location | No | |
Points | location | Yes | |
PreDamageEvent | real | No | |
PStun_Category | integer | No | |
PStun_Event | real | No | |
PStun_LeakPoint | location | No | |
QJ_AoE | boolean | No | |
QJ_AoERadius | real | No | |
QJ_AoESFX | string | No | |
QJ_attackTypeID | integer | No | |
QJ_Caster | unit | No | |
QJ_Collision | boolean | No | |
QJ_Damage | real | No | |
QJ_damageTypeID | integer | No | |
QJ_Homing | boolean | No | |
QJ_Model | unitcode | No | |
QJ_Pierce | boolean | No | |
QJ_Position | location | No | |
QJ_Size | real | No | |
QJ_Solo | boolean | No | |
QJ_Speed | real | No | |
QJ_TargetPoint | location | No | |
QJ_TargetUnit | unit | No | |
QJS_Angle | real | No | |
QJS_arrowGroup | group | No | |
QJS_arrowPos | location | No | |
QJS_arrowTable | hashtable | No | |
QJS_atkTypePreset | attacktype | Yes | |
QJS_AttackType | attacktype | No | |
QJS_DamagedGroup | group | No | |
QJS_DamageType | damagetype | No | |
QJS_Distance | real | No | |
QJS_dmgTypePreset | damagetype | Yes | |
QJS_movePos | location | No | |
QJS_tempPos | location | No | |
QJS_tempPos_Target | location | No | |
QJS_victimGroup | group | No | |
QJS_victimPos | location | No | |
RaceChoosenTable | hashtable | No | |
Random | integer | No | |
RayCasters | group | No | |
Ready | integer | No | |
Real | real | Yes | |
RealSacrifice | real | No | |
regen_buildup | real | Yes | |
REGEN_EVENT_INTERVAL | real | No | |
REGEN_STRENGTH_VALUE | real | No | |
REGEN_THRESHOLD | real | No | |
regen_timeleft | real | Yes | |
RemainingTime_Stagger | real | No | |
RemainingTimeofDestiny | real | No | |
RemoveDamageEvent | boolean | No | |
ReportLife | real | No | |
RessurectTable | hashtable | No | |
Restoration | unit | No | |
RetreatGroup | group | No | |
RetreatTable | hashtable | No | |
RevealWarning | string | No | You will be revealed to your opponents unless you build a town-hall type structure. |
RiptideHeal | real | No | |
RoyalGuard | hashtable | No | |
RS_Angle | real | Yes | |
RS_Boolean | boolean | Yes | |
RS_Caster | unit | Yes | |
RS_CurDis | real | Yes | |
RS_Index | integer | Yes | |
RS_LevelA | integer | Yes | |
RS_Loc | location | Yes | |
RS_MaxD | real | Yes | |
RS_MaxH | real | Yes | |
RS_Player | player | Yes | |
RS_Real | real | Yes | |
RS_Speed | real | Yes | |
RS_Target | unit | Yes | |
SeaElementalTable | hashtable | No | |
SeasickGroup | group | No | |
SeasickTable | hashtable | No | |
SecretTimer | real | No | |
SeismicActivityGroup | group | No | |
SeismicActivityTable | hashtable | No | |
Shockwaves | group | No | |
Slaves | group | No | |
SourceDamageEvent | real | No | |
SpellDamageAbility | abilcode | No | |
SpellSteal_BuffCount | integer | No | |
SpellSteal_Buffs_Number | integer | No | |
SpellSteal_Caster | unit | No | |
SpellSteal_Categories | integer | No | |
SpellSteal_Category | integer | Yes | |
SpellSteal_IntegerA | integervar | No | |
SpellSteal_IntegerB | integervar | No | |
SpellSteal_Target | unit | No | |
spider_size | real | No | |
SpiderLord_LineAttackGroup | group | No | |
SpiderLordLineDamageAmount | real | No | |
SS_CheckIntegerA | integervar | No | |
SS_CountStuns | integer | No | |
StartGameSound | sound | No | |
StormEyeGroup | group | No | |
StrongholdGroup | group | No | |
StrongholdTable | hashtable | No | |
Target | unit | No | |
TargetMindBlast | unit | No | |
TempBool | boolean | No | |
TempInteger | integer | No | |
TempLoc | location | No | |
tempReal1_BuildNaga | real | No | |
tempReal2_BuildNaga | real | No | |
TempUnit | unit | No | |
TempX | real | No | |
TempY | real | No | |
Tic | sound | No | |
TidalGuard | hashtable | No | |
TimerGameStart | integer | No | |
TrueSightAbility | ability | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
UnderlordGroup | group | No | |
Unit | unit | No | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
UnitDamageRegistered | boolean | Yes | |
UnitGroup | group | No | |
UnitGroup_2 | group | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitIndexLock | integer | Yes | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes | |
VialGroup | group | No | |
VialNagaTable | hashtable | 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 | |
Weather | weathereffect | No | |
WeatherUnit | unit | No | |
WEBB | lightningtype | No | |
x1 | real | Yes | |
x2 | real | Yes | |
y1 | real | Yes | |
y2 | real | Yes | |
z1 | real | Yes | |
z2 | real | Yes | |
ZeroDamageEvent | real | No |
function GetPlayerColorString(player)
local c = GetPlayerColor(player)
if c == PLAYER_COLOR_RED then
return "|cffFF0202"
elseif c == PLAYER_COLOR_BLUE then
return "|cff0041FF"
elseif c == PLAYER_COLOR_CYAN then
return "|cff1BE5B8"
elseif c == PLAYER_COLOR_PURPLE then
return "|cff530080"
elseif c == PLAYER_COLOR_YELLOW then
return "|cffFFFC00"
elseif c == PLAYER_COLOR_ORANGE then
return "|cffFE890D"
elseif c == PLAYER_COLOR_GREEN then
return "|cff1FBF00"
elseif c == PLAYER_COLOR_PINK then
return "|cffE45AAF"
elseif c == PLAYER_COLOR_LIGHT_GRAY then
return "|cff949596"
elseif c == PLAYER_COLOR_LIGHT_BLUE then
return "|cff7DBEF1"
elseif c == PLAYER_COLOR_AQUA then
return "|cff0F6145"
elseif c == PLAYER_COLOR_BROWN then
return "|cff4D2903"
else
return "|cffFFFFFF"
end
end
races = {
{
id=1,
name='Human',
mainBuilding = FourCC('htow'),
icon = 'ChooseRace\\Human.blp',
worker = FourCC('hpea')
},
{
id=2,
name='Orc',
mainBuilding = FourCC('orge'),
icon = 'ChooseRace\\Orc.blp',
worker = FourCC('opeo')
},
{
id=3,
name='Undead',
mainBuilding = FourCC('unpl'),
icon = 'ChooseRace\\Undead.blp',
worker = FourCC('uaco'),
ghoal = FourCC('ugho')
},
{
id=4,
name='Night Elf',
mainBuilding = FourCC('etol'),
icon = 'ChooseRace\\Elf.blp',
worker = FourCC('ewsp')
},
{
id=5,
name='Nerubian',
mainBuilding = FourCC('o00D'),
icon = 'ChooseRace\\Nerubian.blp',
worker = FourCC('o002')
},
{
id=6,
name='Naga',
mainBuilding = FourCC('o00N'),
icon = 'ChooseRace\\Naga.blp',
worker = FourCC('n00A'),
overseer = FourCC('n00E'),
},
{
id=7,
name='Random',
icon = 'Random.blp'
},
}
-- in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
-- This runs all functions added to it with a 0s delay after the game was loaded.
FrameLoader = {
OnLoadTimer = function ()
for _,v in ipairs(FrameLoader) do v() end
end
,OnLoadAction = function()
TimerStart(FrameLoader.Timer, 0, false, FrameLoader.OnLoadTimer)
end
}
function FrameLoaderAdd(func)
if not FrameLoader.Timer then
FrameLoader.Trigger = CreateTrigger()
FrameLoader.Timer = CreateTimer()
TriggerRegisterGameEvent(FrameLoader.Trigger, EVENT_GAME_LOADED)
TriggerAddAction(FrameLoader.Trigger, FrameLoader.OnLoadAction)
end
table.insert(FrameLoader, func)
end
--[[
CustomConsoleUI by Tasyen
CustomConsoleUI allows to change the UI during the game, when setuped correctly. This excludes the mouse cursor and the UI sounds.
In non reforged it can also not change the Idle worker Button nor the no inventory cover.
How to setup this: First you have to make the default Console Textures be hidden that is done in Game Interface.
Set ConsoleTexture01 to ConsoleTexture06 to UI\Widgets\EscMenu\Human\blank-background.blp
The Day of Time clock has hardcoded textures therefore you need to swap it out. That also should be done in Gameinterface.
TimeOfDayIndicator to the model included in this system.
Now export and Import war3mapImported\CustomConsoleUI.toc & war3mapImported\CustomConsoleUI.fdf
Finally you have to set the used textures into local data
UseCustomConsole(player, index)
CreateCustomConsole()
--]]
do
local real = MarkGameStarted
local idleWorkerButton, idleWorkerButtonOverlay, idleWorkerButtonOverlayParent
local customInventoryCoverParent, customInventoryCover, fullscreenFrame
local data = {
[1] = { --1
"ui\\console\\human\\humanuitile01",
"ui\\console\\human\\humanuitile02",
"ui\\console\\human\\humanuitile03",
"ui\\console\\human\\humanuitile04",
"war3mapImported\\HumanUITile05",
"war3mapImported\\HumanUITile06",
"ui\\console\\human\\humanuitile-timeindicatorframe",
"ui\\console\\human\\humanuitile-inventorycover",
"ReplaceableTextures\\CommandButtons\\BTNPeasant",
-- postion offset
x = 0.0009,
y = 0.0
},
[2] = { --2
"ui\\console\\orc\\orcuitile01",
"ui\\console\\orc\\orcuitile02",
"ui\\console\\orc\\orcuitile03",
"ui\\console\\orc\\orcuitile04",
"war3mapImported\\OrcUITile05",
"war3mapImported\\OrcUITile05",
"ui\\console\\orc\\orcuitile-timeindicatorframe",
"ui\\console\\orc\\orcuitile-inventorycover",
"ReplaceableTextures\\CommandButtons\\BTNPeon",
x = 0.0009,
y = 0.0
},
[3] = { --3
"ui\\console\\undead\\undeaduitile01",
"ui\\console\\undead\\undeaduitile02",
"ui\\console\\undead\\undeaduitile03",
"ui\\console\\undead\\undeaduitile04",
"war3mapImported\\UndeadUITile05",
"war3mapImported\\UndeadUITile06",
"ui\\console\\undead\\undeaduitile-timeindicatorframe",
"ui\\console\\undead\\undeaduitile-inventorycover",
"ReplaceableTextures\\CommandButtons\\BTNAcolyte",
x = 0.0009,
y = 0.0
},
[4] = { --4
"ui\\console\\nightelf\\nightelfuitile01",
"ui\\console\\nightelf\\nightelfuitile02",
"ui\\console\\nightelf\\nightelfuitile03",
"ui\\console\\nightelf\\nightelfuitile04",
"war3mapImported\\NightElfUITile05",
"war3mapImported\\NightElfUITile06",
"ui\\console\\nightelf\\nightelfuitile-timeindicatorframe",
"ui\\console\\nightelf\\nightelfuitile-inventorycover",
"ReplaceableTextures\\CommandButtons\\BTNWisp",
x = 0.0009,
y = 0.0
},
[5] = { --5
"war3mapImported\\naga01",
"war3mapImported\\naga02",
"war3mapImported\\naga03",
"war3mapImported\\naga04",
"war3mapImported\\nagauitile05",
"war3mapImported\\nagauitile06",
"war3mapImported\\nagauitile-timeindicatorframe",
"war3mapImported\\nagauitile-inventorycover",
"ReplaceableTextures\\CommandButtons\\BTNMurgalSlave",
x = 0.0009,
y = 0.0
},
[6] = { --7
"war3mapImported\\nerub-tile 1",
"war3mapImported\\nerub-tile 2",
"war3mapImported\\nerub-tile 3",
"war3mapImported\\nerub-tile 4",
"war3mapImported\\nerub-tile 5",
"war3mapImported\\nerub-tile 6",
"war3mapImported\\nerub-timeindicatorframe",
"war3mapImported\\nerub-inventory cover",
"BTNGatherer",
x = 0.0009,
y = 0.0,
}
}
function UseCustomConsole(player, index)
if GetLocalPlayer() ~= player then return end
if not index then index = GetHandleId(GetPlayerRace(player)) end
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5T", 0), data[index][5], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6T", 0), data[index][6], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4T", 0), data[index][4], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3T", 0), data[index][3], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TL", 0), data[index][2], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TR", 0), data[index][2] , 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1T", 0), data[index][1], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1B", 0), data[index][1], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2B", 0), data[index][2], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3B", 0), data[index][3], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4B", 0), data[index][4], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5B", 0), data[index][5], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6B", 0), data[index][6], 0, false)
BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUIClock", 0), data[index][7] ,0, true)
if GetLocalizedString("REFORGED") ~= "REFORGED" then
BlzFrameSetTexture(BlzGetFrameByName("InventoryCoverTexture", 0), data[index][8] ,0, true)
--BlzFrameSetTexture(idleWorkerButtonOverlay, data[index][9], 0, false)
else
BlzFrameSetTexture(customInventoryCover, data[index][8] ,0, true)
end
if data[index].x then BlzFrameSetPoint(BlzGetFrameByName("CustomConsoleUIClock", 0), FRAMEPOINT_TOP, BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOP, data[index].x, data[index].y) end
end
function CreateCustomConsole()
BlzLoadTOCFile( "war3mapimported\\CustomConsoleUI.toc" )
BlzCreateSimpleFrame( "CustomConsoleUI", BlzGetFrameByName("ConsoleUI", 0), 0)
BlzFrameSetLevel(BlzGetFrameByName("CustomConsoleUI", 0), 0)
if GetLocalizedString("REFORGED") ~= "REFORGED" then
--idleWorkerButton = BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7)
-- idleWorkerButtonOverlayParent = BlzCreateSimpleFrame( "SimpleTextureFrame", idleWorkerButton, 0 )
-- idleWorkerButtonOverlay = BlzGetFrameByName("SimpleTextureFrameValue", 0)
-- BlzFrameSetAllPoints(idleWorkerButtonOverlay, idleWorkerButton)
-- BlzFrameSetLevel(idleWorkerButtonOverlayParent, 4)
else
customInventoryCoverParent = BlzCreateSimpleFrame( "SimpleTextureFrame", BlzGetFrameByName("ConsoleUI", 0), 0)
BlzFrameSetLevel(customInventoryCoverParent, 4)
customInventoryCover = BlzGetFrameByName("SimpleTextureFrameValue", 0)
BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_BOTTOMRIGHT, 0.6, 0)
BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_TOPLEFT, 0.6 - 0.128, 0.2558)
end
-- Preload
BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)
BlzGetFrameByName("InventoryCoverTexture", 0)
BlzGetFrameByName("CustomConsoleUIClock", 0)
BlzGetFrameByName("CustomConsoleUI5T", 0)
BlzGetFrameByName("CustomConsoleUI6T", 0)
BlzGetFrameByName("CustomConsoleUI4T", 0)
BlzGetFrameByName("CustomConsoleUI3T", 0)
BlzGetFrameByName("CustomConsoleUI2TL", 0)
BlzGetFrameByName("CustomConsoleUI2TR", 0)
BlzGetFrameByName("CustomConsoleUI1T", 0)
BlzGetFrameByName("CustomConsoleUI1B", 0)
BlzGetFrameByName("CustomConsoleUI2B", 0)
BlzGetFrameByName("CustomConsoleUI3B", 0)
BlzGetFrameByName("CustomConsoleUI4B", 0)
BlzGetFrameByName("CustomConsoleUI5B", 0)
BlzGetFrameByName("CustomConsoleUI6B", 0)
end
local function Init()
CreateCustomConsole()
UseCustomConsole(GetLocalPlayer())
if GetLocalizedString("REFORGED") == "REFORGED" then
TimerStart(CreateTimer(), 1/32.0, true, function()
BlzFrameSetVisible(customInventoryCoverParent, not BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)))
end)
end
end
function MarkGameStarted()
xpcall(function()
real()
Init()
if FrameLoaderAdd then FrameLoaderAdd(Init) end
end, print)
end
end
playerRaces = {}
interface = {}
function HideChooseRaceTitle()
BlzFrameSetVisible(interface.chooseRaceFrameText, false)
BlzFrameSetVisible(interface.chooseRaceFrame, false)
end
function HideChooseRaceInterface()
local raceButtons = interface.raceButtons
for i, button in ipairs(raceButtons) do
BlzFrameSetVisible(button, false)
end
BlzFrameSetVisible(interface.raceTooltipText, false)
BlzFrameSetVisible(interface.raceTooltip, false)
end
function CreateChooseRaceButtons()
CreateChooseRaceTitle()
local mainFrame = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
local baseOffsetX = 0.080
local middleLineOffset = baseOffsetX * (#races - 1) / 2
interface.raceButtons = {}
for i, race in ipairs(races) do
local button = BlzCreateFrame('ScoreScreenBottomButtonTemplate', mainFrame, 0, 0)
local icon = BlzGetFrameByName('ScoreScreenButtonBackdrop', 0)
BlzFrameSetSize(button, 0.08, 0.096)
local offsetX = baseOffsetX * (i - 1) - middleLineOffset
BlzFrameSetPoint(button, FRAMEPOINT_BOTTOM, mainFrame, FRAMEPOINT_BOTTOM, offsetX , 0.35)
BlzFrameSetTexture(icon, race.icon, 0, true)
interface.raceButtons[i] = button
onRaceClick(button, race)
end
BlzFrameSetText(interface.chooseRaceFrameText, 'Choose Race: 10')
ForForce( GetPlayersAll(), function()
if(GetPlayerState(GetEnumPlayer(), PLAYER_STATE_OBSERVER) == 1
or GetPlayerController(player) == MAP_CONTROL_COMPUTER) then
BlzFrameSetVisible(interface.chooseRaceFrame, false)
end
end)
end
function CreateChooseRaceTitle()
local mainFrame = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
local chooseRaceFrame = BlzCreateFrame('ListBoxWar3', mainFrame, 0, 0)
BlzFrameSetSize(chooseRaceFrame, 0.21, 0.06)
BlzFrameSetPoint(chooseRaceFrame, FRAMEPOINT_BOTTOM, mainFrame, FRAMEPOINT_BOTTOM, 0, 0.45)
local textFrame = BlzCreateFrameByType('TEXT', 'StandardInfoTextTemplate', chooseRaceFrame, '', 0)
BlzFrameSetSize(textFrame, 0.20, 0.05)
BlzFrameSetPoint(textFrame, FRAMEPOINT_CENTER, chooseRaceFrame, FRAMEPOINT_CENTER, 0, 0)
BlzFrameSetTextAlignment(textFrame, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
BlzFrameSetScale(textFrame, 2)
interface.chooseRaceFrame = chooseRaceFrame
interface.chooseRaceFrameText = textFrame
end
function CreateRaceTooltip(button, race)
local mainFrame = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
local tooltipFrame = BlzCreateFrame('ListBoxWar3', mainFrame, 0, 0)
BlzFrameSetSize(tooltipFrame, 0.14, 0.04)
BlzFrameSetPoint(tooltipFrame, FRAMEPOINT_BOTTOM, button, FRAMEPOINT_TOP, 0, 0)
local tooltipTextFrame = BlzCreateFrameByType('TEXT', 'StandardInfoTextTemplate', tooltipFrame, '', 0)
BlzFrameSetSize(tooltipTextFrame, 0.11, 0.04)
BlzFrameSetPoint(tooltipTextFrame, FRAMEPOINT_CENTER, tooltipFrame, FRAMEPOINT_CENTER, 0, 0)
BlzFrameSetTextAlignment(tooltipTextFrame, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
BlzFrameSetText(tooltipTextFrame, race.name)
BlzFrameSetTooltip(button, tooltipFrame)
interface.raceTooltip = tooltipFrame
interface.raceTooltipText = tooltipTextFrame
end
function onRaceClick(button, race)
local clickTrigger = CreateTrigger()
TriggerAddAction(clickTrigger, function()
SetRace(race)
end)
BlzTriggerRegisterFrameEvent(clickTrigger, button, FRAMEEVENT_CONTROL_CLICK)
end
function SetRace(race)
local player = GetTriggerPlayer()
local playerId = GetConvertedPlayerId(player)
playerRaces[GetConvertedPlayerId(player)] = race
if(player == GetLocalPlayer()) then
HideChooseRaceInterface()
end
udg_Ready = udg_Ready - 1
if(udg_Ready == 0) then
udg_TimerGameStart = 0
end
end
function InitRaces()
ForForce( GetPlayersAll(), function()
InitRace()
SelectedRaceMessage()
end)
end
function InitAIRace(player)
local compRace = GetPlayerRace(player)
local playerId = GetConvertedPlayerId(player)
if(compRace == RACE_HUMAN) then
playerRaces[playerId] = races[1]
end
if(compRace == RACE_ORC) then
playerRaces[playerId] = races[2]
end
if(compRace == RACE_UNDEAD) then
playerRaces[playerId] = races[3]
end
if(compRace == RACE_NIGHTELF) then
playerRaces[playerId] = races[4]
end
end
function InitRace()
local player = GetEnumPlayer()
local playerId = GetConvertedPlayerId(player)
if(GetPlayerState(player, PLAYER_STATE_OBSERVER) == 1 ) then return end
if(GetPlayerController(player) == MAP_CONTROL_COMPUTER) then
InitAIRace(player)
end
local race = playerRaces[playerId]
if(player == GetLocalPlayer()) then
HideChooseRaceInterface()
HideChooseRaceTitle()
end
if(race == nil or race.name == 'Random') then
local randomRaceIndex = GetRandomInt(1, #races - 1)
race = races[randomRaceIndex]
end
if(race.name == 'Human') then
MeleeStartingUnitsHuman(player, GetPlayerStartLocationLoc(player), true, true, true)
UseCustomConsole(player, 1)
end
if(race.name == 'Orc') then
MeleeStartingUnitsOrc(player, GetPlayerStartLocationLoc(player), true, true, true)
UseCustomConsole(player, 2)
end
if(race.name == 'Undead') then
MeleeStartingUnitsUndead(player, GetPlayerStartLocationLoc(player), true, true, true)
UseCustomConsole(player, 3)
end
if(race.name == 'Night Elf') then
MeleeStartingUnitsNightElf(player, GetPlayerStartLocationLoc(player), true, true, true)
UseCustomConsole(player, 4)
end
if(race.name == 'Naga') then
MeleeStartingUnitsNaga(race, player)
UseCustomConsole(player, 5)
end
if(race.name == 'Nerubian') then
MeleeStartingUnitsCustomRace(race, player)
UseCustomConsole(player, 6)
end
end
function ReplaceToCustomRace(player, race)
unit = GetEnumUnit()
if (GetUnitTypeId(unit) == FourCC('hpea') and GetOwningPlayer(unit) == player) then
ReplaceUnitBJ(unit, race.worker, bj_UNIT_STATE_METHOD_RELATIVE)
workerLoc = GetUnitLoc(GetLastReplacedUnitBJ())
end
if GetUnitTypeId(unit) == FourCC('htow') and GetOwningPlayer(unit) == player then
ReplaceUnitBJ(unit, race.mainBuilding, bj_UNIT_STATE_METHOD_RELATIVE)
end
end
function MeleeStartingUnitsNaga(race, player)
MeleeStartingUnitsHuman(player, GetPlayerStartLocationLoc(player), true, true, true)
ForGroupBJ( GetUnitsInRectOfPlayer(GetPlayableMapRect(), player), function() ReplaceToCustomRace(player, race) end)
CreateNUnitsAtLoc(1, race.overseer, player, workerLoc, bj_UNIT_FACING)
workerLoc=nil
end
function MeleeStartingUnitsCustomRace(race, player)
MeleeStartingUnitsHuman(player, GetPlayerStartLocationLoc(player), true, true, true)
ForGroupBJ( GetUnitsInRectOfPlayer(GetPlayableMapRect(), player), function() ReplaceToCustomRace(player, race) end)
workerLoc=nil
end
function Trig_Unit_Indexer_Func005Func002C()
if ( not ( udg_UnitIndexLock[udg_UDex] == 0 ) ) then
return false
end
return true
end
function Trig_Unit_Indexer_Func005C()
if ( not ( GetUnitUserData(udg_UDexUnits[udg_UDex]) == 0 ) ) then
return false
end
return true
end
function Trig_Unit_Indexer_Func014Func003C()
if ( not ( udg_UDexWasted == 32 ) ) then
return false
end
return true
end
function Trig_Unit_Indexer_Func014Func005C()
if ( not ( udg_UDexRecycle == 0 ) ) then
return false
end
return true
end
function Trig_Unit_Indexer_Func014C()
if ( not ( udg_UnitIndexerEnabled == true ) ) then
return false
end
if ( not ( GetUnitUserData(GetFilterUnit()) == 0 ) ) then
return false
end
return true
end
function ClearUnitIndex()
if ( Trig_Unit_Indexer_Func005C() ) then
udg_UnitIndexLock[udg_UDex] = ( udg_UnitIndexLock[udg_UDex] - 1 )
if ( Trig_Unit_Indexer_Func005Func002C() ) then
udg_UDexNext[udg_UDexPrev[udg_UDex]] = udg_UDexNext[udg_UDex]
udg_UDexPrev[udg_UDexNext[udg_UDex]] = udg_UDexPrev[udg_UDex]
udg_UDexPrev[udg_UDex] = 0
udg_UnitIndexEvent = 0.00
udg_UnitIndexEvent = 2.00
udg_UnitIndexEvent = 0.00
udg_UDexUnits[udg_UDex] = nil
udg_UDexNext[udg_UDex] = udg_UDexRecycle
udg_UDexRecycle = udg_UDex
else
end
else
end
end
function IndexUnit()
local pdex = udg_UDex
local ndex
-- -
-- You can customize the following block - if conditions are false the (Matching unit) won't be indexed.
-- -
if ( Trig_Unit_Indexer_Func014C() ) then
udg_UDexWasted = ( udg_UDexWasted + 1 )
if ( Trig_Unit_Indexer_Func014Func003C() ) then
udg_UDexWasted = 0
udg_UDex = udg_UDexNext[0]
while udg_UDex == 0 do
ndex = udg_UDexNext[udg_UDex]
ClearUnitIndex()
udg_UDex = ndex
end
end
if ( Trig_Unit_Indexer_Func014Func005C() ) then
udg_UDex = ( udg_UDexGen + 1 )
udg_UDexGen = udg_UDex
else
udg_UDex = udg_UDexRecycle
udg_UDexRecycle = udg_UDexNext[udg_UDex]
end
udg_UDexUnits[udg_UDex] = GetFilterUnit()
SetUnitUserData( udg_UDexUnits[udg_UDex], udg_UDex )
udg_UDexPrev[udg_UDexNext[0]] = udg_UDex
udg_UDexNext[udg_UDex] = udg_UDexNext[0]
udg_UDexNext[0] = udg_UDex
udg_UnitIndexLock[udg_UDex] = 1
udg_UnitIndexEvent = 0.00
udg_UnitIndexEvent = 1.00
udg_UnitIndexEvent = 0.00
udg_UDex = pdex
end
return false
end
function InitializeUnitIndexer()
local b = Filter(IndexUnit)
local re = CreateRegion()
local t = GetTriggeringTrigger()
local r = GetWorldBounds()
RegionAddRect(re, r)
TriggerRegisterEnterRegion(t, re, b)
TriggerClearActions(t)
TriggerAddAction(t, ClearUnitIndex)
udg_UnitIndexerEnabled = true
for i=bj_MAX_PLAYER_SLOTS, 0, -1 do
GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
end
RemoveRect(r)
re = nil
r = nil
t = nil
b = nil
udg_UnitIndexEvent = 3.00
udg_UnitIndexEvent = 0.00
end
do
--[[
Doubly-Linked List v1.3.0.0 by Wrda, Eikonium and Bribe
------------------------------------------------------------------------------
A script that allows the possibility to create a sequence of any object
linked together.
------------------------------------------------------------------------------
API:
LinkedList.create(head) -> LinkedList
- Creates or resets a table as a LinkedList head.
- Allows a user-specified head or generates a new one.
list:insert([node_or_value, after]) -> listNode
- Inserts *before* the given list/node unless "after" is true.
- If a "node or value" is passed, the system will check if the node is
a table. If the table isn't yet part of a LinkedList structure, it
will be converted into the node that is returned at the end of this
function. If the table is a part of the LinkedList structure, or a
different type of value than a table, then it will be assigned as a
generic "value" (mapped to node.value)
- Returns the inserted node that was added to the list (if addition was successful).
list:remove(node) -> boolean
- Removes a node from whatever list it is a part of and calls self:onRemove().
- Returns true if it was sucessful.
for node in list:loop([backwards]) do [stuff] end
- Iterates over all nodes in "list".
fromList:merge(intoList[, backwardsFrom, backwardsInto])
- Removes all nodes from one list and adds them into another.
list:reset() -> boolean
- Removes all nodes from the given linked list, calling node:onRemove() on each.
- Returns true if sucessful.
- readonly list.n : integer -> the number of nodes in the list.
]]
---@class LinkedList:table
---@field head LinkedList
---@field next listNode|LinkedList
---@field prev listNode|LinkedList
---@field n integer
LinkedList = {}
LinkedList.__index = LinkedList
---@class listNode:LinkedList
---@field remove fun(node:listNode)->boolean
---@field onRemove fun(self:listNode)
---Creates or resets a table as a LinkedList head.
---@param head? LinkedList allows a user-specified head or generates a new one.
---@return LinkedList
function LinkedList.create(head)
if head and type(head) == "table" then
local h = head.head
if h then
if h ~= head then
return --user passed an active ListNode. This is not allowed.
end
if h.n > 0 then --first empty any lists that still have nodes.
for node in head:loop() do node:onRemove() end
end
end
else
head = {}
end
setmetatable(head, LinkedList)
head.next = head
head.prev = head
head.head = head
head.n = 0
return head
end
---Node can be an existing table, or a new table will be created to represent the
---node. "list" can either be the head, or any point where you want the node to be
---inserted. It will insert *before* the given head/node, unless "backward" is true.
---@param list listNode|LinkedList
---@param node_or_value? any
---@param insertAfter? boolean
---@return listNode node that was added to the list (if addition was successful)
function LinkedList.insert(list, node_or_value, insertAfter)
if not list then return end
local head = list.head
if not head then return end
local node, value
if node_or_value then
if type(node_or_value) == "table" then
if node_or_value.head then --table is already part of a linked list. Treat it as a "value"
value = node_or_value
else
node = node_or_value --table will be transmuted into the linked list node itself.
end
else
--User passed a non-table value.
value = node_or_value
end
end
if insertAfter then list = list.next end
node = node or {} ---@type listNode
setmetatable(node, LinkedList)
list.prev.next = node
node.prev = list.prev
list.prev = node
node.next = list
node.head = head
head.n = head.n + 1
node.value = value
node.onRemove = function() node.head = nil end
return node
end
---Removes a node from whatever list it is a part of. A node cannot be a part of
---more than one list at a time, so there is no need to pass the containing list as
---an argument.
---@param node listNode
---@return boolean wasRemoved
function LinkedList:remove(node)
node = node or self
if node then
local head = node.head
if head and head ~= node then
node.prev.next = node.next
node.next.prev = node.prev
head.n = head.n - 1
node:onRemove()
return true
end
end
end
---Enables the generic for-loop for LinkedLists.
---Syntax: "for node in LinkedList.loop(list) do print(node) end"
---Alternative Syntax: "for node in list:loop() do print(node) end"
---@param list LinkedList
---@param backward? boolean
function LinkedList.loop(list, backward)
list = list.head
local loopNode = list ---@type listNode
local direction = backward and "prev" or "next"
return function()
loopNode = loopNode[direction]
return loopNode ~= list and loopNode or nil
end
end
---Merges LinkedList "from" to another LinkedList "into"
---@param from LinkedList|listNode
---@param into LinkedList|listNode
---@param backwardFrom boolean
---@param backwardInto boolean
function LinkedList.merge(from, into, backwardFrom, backwardInto)
if from and from.head and into and into.head then
local directionFrom = backwardFrom and "prev" or "next"
local n, v
local node = from[directionFrom]
from = from.head
while node ~= from do
n, v = node[directionFrom], node.value
node:remove()
into:insert(node, backwardInto).value = v
node = n
end
end
end
---Removes all nodes from the given linked list.
---@param list LinkedList
---@return boolean was_reset
function LinkedList.reset(list)
return list:create() ~= nil
end
end
if LinkedList then --https://www.hiveworkshop.com/threads/definitive-doubly-linked-list.339392/
--[[--------------------------------------------------------------------------------------
Hook v4.1.0.0 by Bribe, with very special thanks to:
Eikonium and Jampion for bug reports, feature improvements, teaching me new things.
MyPad for teaching me new things
Wrda and Eikonium for the better LinkedList approach
----------------------------------------------------------------------------------------]]
Hook = {}
local _LOW_PRIO = -0.1 -- a number to represent what should be the lowest priority for a before-hook (lower values run first).
local _HIGH_PRIO = 9001 -- a number to represent what should be the lowest priority for an after-hook (lower values run first).
local _SKIP_HOOK = "skip hook" --when this is returned from a Hook.addSimple function, the hook will stop.
local hookBefore = {} ---@type Hook[] --stores a list of functions that are called prior to a hooked function.
local hookAfter = {} ---@type Hook[] --stores a list of functions that are called after a hooked function.
local hookedFunc = {} ---@type function[] --stores a list of overriden functions
---@class Hook:LinkedList
---@field add function
---@field addSimple function
---@field flush function
---@field func function
---@class hookNode :listNode
---@field weight number
---@field head Hook
---@field func fun(hook:Hook)
---@class hookInstance:table
---@field args table
---@field call function
---@field skip boolean
---@field returned table
--[[--------------------------------------------------------------------------------------
Internal functions
----------------------------------------------------------------------------------------]]
---@param oldFunc string
---@param parent? table
---@return table
---@return table hookedFuncParent
---@return function? hooked_func_or_nil
---@return function hooked_func
local function parseArgs(oldFunc, parent)
parent = parent or _G
local hfp = hookedFunc[parent]
local hf = hfp and hfp[oldFunc]
return parent, hfp, hf, hf or parent[oldFunc]
end
--[[--------------------------------------------------------------------------------------
Hook.add
Args: string oldFunc, function userFunc[, number weight, table parent, function default]
@ oldFunc is a string that represents the name of a function (e.g. "CreateUnit")
@ userFunc is the function you want to be called when the original function is
called*.
@ weight is an optional parameter that determines whether your hook takes place
"before" the original function is called, or after. Broken down like this:
(a) if "weight" is "nil", "false" or a "negative number", it is treated as a
"before hook". If "nil" or "false", "_LOW_PRIO" will be assigned as the weight.
(b) if "weight" is "true", "0" or a "positive number", it is treated as an
"after hook". If "true",
@ parent is an optional parameter for where the oldFunc is hosted. By default,
it assumes a global (_G table) such as "BJDebugMsg".
@ default is a function that you can inject into the table in case that variable
is not found. If the variable is not found and a function is not passed as a
default, the addition will fail.
Returns two items:
1. The original function you are hooking (if successful) or nil (if failed).
2. A table to represent your hook registry. This is part of a linked list belonging
to the function you hooked and aligned with whether it is a "before" or "after"
hook. Its most relevant use would be to be passed to "Hook.remove(userHookTable)",
as that is the way to remove a single hook in version 4.0.
*The function you specify in Hook.add can take exactly one argument: a table. That
table has the following properties within itself:
args
(table)
Contains the original arguments passed during a hook. Useful for referencing in an
"after hook". Can be modified by a "before hook".
returned
(table or nil)
Contains a table of the return value(s) from "before" hooks and (if applicable) the
original function. This is either "nil", or usually only holds a single index. To
initialize this correctly, use table.pack(returnVal[, returnVal2, returnVal3, ...]).
old
(function)
The original, native function that has been hooked (in case you want to call it).
skip
(boolean)
Note: Set this to "true" from within a before-hook callback function to prevent the
original function from being called. Users can check if this is set to true if
they want to change the behavior of their own hooks accordingly.
----------------------------------------------------------------------------------------]]
---@param oldFunc string
---@param userFunc fun(hook:table)
---@param weight? number
---@param parent? table
---@param default? function
---@return function original_function
---@return hookNode newUserNode
function Hook.add(oldFunc, userFunc, weight, parent, default)
if type(oldFunc) ~= "string" or type(userFunc) ~= "function" then
--print "Hook.add Error: The first argument must be a string, the second must be a function."
return
end
local parent, hfp, hf, old = parseArgs(oldFunc, parent)
if not old or type(old) ~= "function" then
if default then
old = default
parent[oldFunc] = default
else
--print("Hook.add Error: Tried to hook a function that doesn't exist: " .. oldFunc .. ".\nTry calling Hook.add from a Global Initialization function.")
return
end
end
if not hf then
if not hfp then
hfp = {}
hookedFunc[parent] = hfp
end
hfp[oldFunc] = old ---@type function
local hb = LinkedList.create() ---@type Hook
hookBefore[old] = hb
hb.func = old
local ha = LinkedList.create() ---@type Hook
hookAfter[old] = ha
ha.func = old
parent[oldFunc] =
function(...)
local this = {args = table.pack(...), call = old, skip = false } ---@type hookInstance
for userNode in hb:loop() do userNode.func(this) end
local r
if not this.skip then
r = table.pack(old(table.unpack(this.args, 1, this.args.n)))
if r.n > 0 then this.returned = r end
end
r = this.returned
if not (r and type(r) == "table" and r.n and r.n > 0) then
r = nil; this.returned = nil
--else
--print("Hook report: returning " .. r.n .. " values.")
end
for userNode in ha:loop() do userNode.func(this) end
if r then return table.unpack(r, 1, r.n) end
end
end
weight = weight or _LOW_PRIO
if weight == true then weight = _HIGH_PRIO end
--This creates and inserts newUserNode into the corresponding table with taking into consideration the weight of each item.
local tab = weight < 0 and hookBefore[old] or hookAfter[old]
local insertPoint = tab.head
local newUserNode
for node in tab:loop() do
if node.weight > weight then insertPoint = node; break end
end
newUserNode = insertPoint:insert(nil, true) ---@type hookNode
newUserNode.func = userFunc
newUserNode.weight = weight
newUserNode.remove = Hook.remove
--print("indexing")
return old, newUserNode
end
---Remove a registered hook by passing the node returned from the second
---return value of Hook.add.
---@param node hookNode
---@return integer number_of_hooks_remaining
function Hook.remove(node)
local r = 0
local head = node.head
if head then
node:remove()
r = hookBefore[head.func].n + hookAfter[head.func].n
if r == 0 then
Hook.flush(head.func)
end
end
return r
end
--[[--------------------------------------------------------------------------------------
Hook.flush
Args: string oldFunc[, table parent]
Desc: Purges all hooks associated with the given function string and sets the original
function back inside of the parent table.
----------------------------------------------------------------------------------------]]
---Hook.flush
---@param oldFunc string
---@param parent? table
function Hook.flush(oldFunc, parent)
local parent, hfp, hf, old = parseArgs(oldFunc, parent)
if hf then
parent[oldFunc] = old
hookBefore[old] = nil
hookAfter[old] = nil
hfp[oldFunc] = nil
end
end
--[[--------------------------------------------------------------------------------------
The user-function parameters and behavior are different from Hook.add. This uses
the original format I wanted for hook-behavior, but it became clear that there
were scenarios where the user should be able to do more.
"Before hook" parameters are the arguments of the original function call. This is
useful in a situation where you don't want to unpack the args yourself to see them in
an intuitive way, and don't need the additional complexities of the table to determine
what you want to do.
Return: If anything other than "nil" is returned, it will prevent any additional
"before" hooks with a lower priority from running, as well as prevent the
original function from being called. If returning a value other than "nil"
would break the expectations of the original function, return the string
"stop hook" instead.
"After hook"
------------
Args: Takes the return value(s) as parameter(s), if there was any return value.
----------------------------------------------------------------------------------------]]
---@param oldFunc string
---@param userFunc function
---@param weight? number
---@param parent? table
---@param default? function
---@return function original_function
---@return hookNode newUserNode
function Hook.addSimple(oldFunc, userFunc, weight, parent, default)
return Hook.add(oldFunc,
function(hook)
local r = hook.returned
if weight and (weight == true or weight >= 0) then
if r then
userFunc(table.unpack(r, 1, r.n))
else
userFunc()
end
elseif not hook.skip and not r then
r = userFunc(table.unpack(hook.args, 1, hook.args.n))
if r and #r > 0 then
if r[1] ~= _SKIP_HOOK then
hook.returned = table.pack(r)
end
hook.skip = true
end
end
end, weight, parent, default)
end
end
if Hook then --https://www.hiveworkshop.com/threads/hook.339153
-- Global Initialization 2.2.2.0 by Bribe, with special thanks to Tasyen, Forsakn and Troll-Brain
local sFuncs
local function Flush()
if sFuncs then return end
sFuncs = {}
Hook.add("InitBlizzard",
function()
local t = CreateTimer()
TimerStart(t, 0.00, false,
function()
DestroyTimer(t)
for _, f in ipairs(sFuncs) do f() end
sFuncs = nil
OnGlobalInit = nil
OnTrigInit = nil
OnMapInit = nil
OnGameStart = nil
Hook.flush("InitBlizzard")
Hook.flush("InitGlobals")
Hook.flush("InitCustomTriggers")
Hook.flush("RunInitializationTriggers")
end)
end)
end
local function Init(str, backup, func, priority)
if not func or type(func) == "number" then
func, priority = priority, func or true
end
if not Hook.add(str, func, priority) then
backup(priority, func)
end
Flush()
end
---@param priority number | function
---@param func? function
function OnGlobalInit(priority, func) -- Runs once all GUI variables are instantiated.
Init("InitGlobals", function(priority, func) Hook.add("InitBlizzard", func, priority) end, func, priority)
end
---@param priority number | function
---@param func? function
function OnTrigInit(priority, func) -- Runs once all InitTrig_ are called
Init("InitCustomTriggers", OnGlobalInit, func, priority)
end
---@param priority number | function
---@param func? function
function OnMapInit(priority, func) -- Runs once all Map Initialization triggers are run
Init("RunInitializationTriggers", OnTrigInit, func, priority)
end
---@param func function
function OnGameStart(func) -- Runs once the game has actually started
Flush()
sFuncs[#sFuncs + 1] = func
end
end
if Hook then --https://www.hiveworkshop.com/threads/hook.339153
--[[--------------------------------------------------------------------------------------
Global Variable Remapper v1.0.1.1 by Bribe
- Intended to empower the GUI user-base and those who design systems for them.
API:
GlobalRemap(variableStr, getterFunc, setterFunc)
@variableStr is a string such as "udg_MyVariable"
@getterFunc is a function that takes nothing but returns the expected value when
"udg_MyVariable" is referenced.
@setterFunc is a function that takes a single argument (the value that is being
assigned) and allows you to do what you want when someone uses "Set MyVariable = SomeValue".
The function doesn't need to do anything nor return anything. Enables read-only
GUI variables for the first time in WarCraft 3 history.
Systems that use this should call GlobalRemap via Global Initialization or later:
https://www.hiveworkshop.com/threads/global-initialization.317099/
----------------------------------------------------------------------------------------]]
local getters, setters, skip
---GlobalRemap
---@param var string
---@param getFunc? fun() ->value?
---@param setFunc? fun(value)
function GlobalRemap(var, getFunc, setFunc)
if not skip then
getters, setters, skip = {}, {}, DoNothing
local mt = getmetatable(_G)
if not mt then
mt = {}
setmetatable(_G, mt)
end
--hook.args = {1:table, 2:index}
Hook.add("__index",
function(hook)
local func = getters[hook.args[2]]
if func then
hook.skip = true
hook.returned = table.pack(func())
end
end, nil, mt,
function(a, b)
return rawget(a, b)
end)
--hook.args = {1:table, 2:index, 3:value}
Hook.add("__newindex",
function(hook)
local func = setters[hook.args[2]]
if func then
hook.skip = true
func(hook.args[3])
end
end, nil, mt,
function(a, b, c)
rawset(a, b, c)
end)
end
_G[var] = nil --Delete the variable from the global table.
getters[var] = getFunc or skip --Assign a function that returns what should be returned when this variable is referenced.
setters[var] = setFunc or skip --Assign a function that captures the value the variable is attempting to be set to.
end
end
if LinkedList then --https://www.hiveworkshop.com/threads/definitive-doubly-linked-list.339392
--[[--------------------------------------------------------------------------------------
Timed Call and Echo v1.2.1.0, code structure credit to Eikonium and Jesus4Lyf
Timed.call([delay, ]userFunc)
-> Call userFunc after 'delay' seconds. Delay defaults to 0 seconds.
Timed.echo(userFunc[, timeout, userTable])
-> Returns userTable or a new table.
-> calls userFunc every "timeout" seconds until userFunc returns true or you call
userTable:remove()
Node API (for the tables returned by Timed.echo):
node.elapsed -> the number of seconds that 'node' has been iterating for.
----------------------------------------------------------------------------------------]]
local _TIMEOUT = 0.03125 --default echo timeout
Timed = {}
---@class timedNode:listNode
---@field elapsed number
--[[--------------------------------------------------------------------------------------
Internal
----------------------------------------------------------------------------------------]]
local zeroList, _ZERO_TIMER
--[[--------------------------------------------------------------------------------------
Name: Timed.call
Args: [delay, ]userFunc
Desc: After "delay" seconds, call "userFunc".
----------------------------------------------------------------------------------------]]
---Core function by Eikonium; zero-second expiration is a simple list by Bribe
---@param delay number|function
---@param userFunc? function|number
function Timed.call(delay, userFunc)
if not userFunc or delay == 0.00 then
if not zeroList then
zeroList = {}
_ZERO_TIMER = _ZERO_TIMER or CreateTimer()
TimerStart(_ZERO_TIMER, 0.00, false,
function()
local tempList = zeroList
zeroList = nil
for _, func in ipairs(tempList) do func() end
end)
end
zeroList[#zeroList + 1] = userFunc or delay
return
end
local t = CreateTimer()
TimerStart(t, delay, false,
function()
DestroyTimer(t)
userFunc()
end)
end
local lists = {}
--[[--------------------------------------------------------------------------------------
Timed.echo is reminiscent of Jesus4Lyf's Timer32 module. It borrows from it with the
LinkedList syntax and "exitwhen true" nature of the original T32 module.
Desc: Calls userFunc every timeout seconds (by default, every 0.03125 seconds). If
your own node should be specified but you want to use the default timeout, you
can use Timed.echo(yourFunc, nil, myTable).
Warn: This merges all timeouts of the same value together, so large numbers can cause
expirations to occur too early on.
----------------------------------------------------------------------------------------]]
---@param userFunc fun(node:timedNode):boolean -- if true, echo will stop
---@param timeout? number
---@param node? timedNode
---@return timedNode new_node
function Timed.echo(userFunc, timeout, node)
timeout = timeout or _TIMEOUT
local list = lists[timeout]
local t
node = node or {} ---@type timedNode
if list then
t = list.timer
local r = TimerGetRemaining(t)
if r < timeout * 0.50 then --the merge uses rounding to determine if
local q = list.queue --the first expiration should be skipped
if not q then
q = LinkedList.create()
list.queue = q
end
node.elapsed = r --add the remaining timeout to the elapsed time for this node.
node.func = userFunc
return q:insert(node)
end
node.elapsed = r - timeout --the instance will be called on the next tick, despite not being around for the full tick.
else
list = LinkedList.create()
lists[timeout] = list
t = CreateTimer() --one timer per timeout interval
list.timer = t
TimerStart(t, timeout, true,
function()
for tNode in list:loop() do
tNode.elapsed = tNode.elapsed + timeout
if tNode.func(tNode) then --function can return true to remove itself from the list.
tNode:remove()
end
end
-- delayed add to list
if list.queue then
list.queue:merge(list)
list.queue = nil
end
--
if list.n == 0 then --list is empty; delete it.
lists[timeout] = nil
PauseTimer(t)
DestroyTimer(t)
end
end)
node.elapsed = 0.00
end
node.func = userFunc
return list:insert(node)
end
end
if Hook -- https://www.hiveworkshop.com/threads/hook.339153
and Timed then -- https://www.hiveworkshop.com/threads/timed-call-and-echo.339222/
--[[--------------------------------------------------------------------------------------
Lua Damage Engine Version 2.0.0.0
Documentation is found in the code, not in this header.
I'd like to give very special thanks to Eikonium for equipping me with the debugging
tools I needed to get Lua Damage Engine published. I'd also like to thank MindWorX and
Eikonium for getting me started with VSCode, which has changed my (programming) life.
If you want GUI functionality, you also will need the following library:
Global Variable Remapper - https://www.hiveworkshop.com/threads/global-variable-remapper
----------------------------------------------------------------------------------------]]
OnGlobalInit(1, function() Damage = {}
---@class damageEvent:LinkedList
---@class damageEventRegistry:listNode
---@class damageInstance:table
--[[--------------------------------------------------------------------------------------
Configurable variables are listed below
----------------------------------------------------------------------------------------]]
local _USE_GUI = GlobalRemap
local _USE_EXTRA = _USE_GUI --If you don't use DamageEventLevel/DamageEventAOE/SourceDamageEvent, set this to false
local _USE_ARMOR_MOD = true --If you do not modify nor detect armor/defense, set this to false
local _USE_MELEE_RANGE = true --If you do not detect melee nor ranged damage, set this to false
local _LIMBO = 16 --When manually-enabled recursion is enabled via Damage.recurion, the engine will never go deeper than LIMBO.
local _DEATH_VAL = 0.405 --In case M$ or Bliz ever change this, it'll be a quick fix here.
local _TYPE_CODE = 1 --Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
local _TYPE_PURE = 2 --Must be the same as udg_DamageTypePure
--These variables coincide with Blizzard's "limitop" type definitions.
local _FILTER_ATTACK = 0 --LESS_THAN
local _FILTER_MELEE = 1 --LESS_THAN_OR_EQUAL
local _FILTER_OTHER = 2 --EQUAL
local _FILTER_RANGED = 3 --GREATER_THAN_OR_EQUAL
local _FILTER_SPELL = 4 --GREATER_THAN
local _FILTER_CODE = 5 --NOT_EQUAL
local CheckUnitType = IsUnitType
local t1, t2, t3 ---@type trigger
local current = nil ---@type damageInstance
local userIndex = nil ---@type damageEventRegistry
local checkConfig
do
local GetUnitItem = UnitItemInSlot
local GetItemType = GetItemTypeId
local GUTI = GetUnitTypeId
local GUAL = GetUnitAbilityLevel
local GRR = GetRandomReal
local function checkItem(u, id)
if CheckUnitType(u, UNIT_TYPE_HERO) then
for i = 0, UnitInventorySize(u) - 1 do
if GetItemType(GetUnitItem(u, i)) == id then return true end
end
end
end
checkConfig = function() if not userIndex.configured then return true
--[[--------------------------------------------------------------------------------------
Mapmakers should comment-out any of the below lines that they will never need to check
for, and move the most common checks to the top of the list.
----------------------------------------------------------------------------------------]]
elseif userIndex.sourceType and GUTI(current.source) ~= userIndex.sourceType then
elseif userIndex.targetType and GUTI(current.target) ~= userIndex.targetType then
elseif userIndex.sourceBuff and GUAL(current.source, userIndex.sourceBuff) == 0 then
elseif userIndex.targetBuff and GUAL(current.target, userIndex.targetBuff) == 0 then
elseif userIndex.failChance and GRR(0.00, 1.00) <= userIndex.failChance then
elseif userIndex.userType and current.userType ~= userIndex.userType then
elseif userIndex.source and userIndex.source ~= current.source then
elseif userIndex.target and userIndex.target ~= current.target then
elseif userIndex.attackType and userIndex.attackType ~= current.attackType then
elseif userIndex.damageType and userIndex.damageType ~= current.damageType then
elseif userIndex.sourceItem and not checkItem(current.source, userIndex.sourceItem) then
elseif userIndex.targetItem and not checkItem(current.target, userIndex.targetItem) then
elseif userIndex.sourceClass and not CheckUnitType(current.source, userIndex.sourceClass) then
elseif userIndex.targetClass and not CheckUnitType(current.target, userIndex.targetClass) then
elseif current.damage >= userIndex.damageMin then
--[[--------------------------------------------------------------------------------------
Configuration section is over. The rest of the library is hard-coded.
----------------------------------------------------------------------------------------]]
--print("Configuration passed")
return true
end
--print("Checking failed")
end
end
--[[--------------------------------------------------------------------------------------
Readonly variables are defined below.
----------------------------------------------------------------------------------------]]
local readonly = {}
readonly.index = function() return current end --Damage.index is the currently-running damage table that contains properties like source/target/damage.
local lastRegistered = nil ---@type damageEventRegistry
readonly.lastRegistered = function() return lastRegistered end --Damage.lastRegistered identifies whatever damage event was most recently added.
readonly.userIndex = function() return userIndex end --Damage.userIndex identifies the registry table for the damage function that's currently running.
local sourceStacks = 1
readonly.sourceStacks = function() return sourceStacks end --Damage.sourceStacks holds how many times a single unit was hit from the same source using the same attack. AKA udg_DamageEventLevel.
local sourceAOE = 1
readonly.sourceAOE = function() return sourceAOE end --Damage.sourceAOE holds how many units were hit by the same source using the same attack. AKA udg_DamageEventAOE.
local originalSource
readonly.originalSource = function() return originalSource end --Damage.originalSource tracks whatever source unit started the current series of damage event(s). AKA udg_AOEDamageSource.
local originalTarget
readonly.originalTarget = function() return originalTarget end --Damage.originalTarget tracks whatever target unit was first hit by the original source. AKA udg_EnhancedDamageTarget.
local _DAMAGING = LinkedList.create() ---@type damageEvent
readonly.damagingEvent = function() return _DAMAGING end
local _ARMOR = LinkedList.create() ---@type damageEvent
readonly.armorEvent = function() return _ARMOR end
local _DAMAGED = LinkedList.create() ---@type damageEvent
readonly.damagedEvent = function() return _DAMAGED end
local _ZERO = LinkedList.create() ---@type damageEvent
readonly.zeroEvent = function() return _ZERO end
local _AFTER = LinkedList.create() ---@type damageEvent
readonly.afterEvent = function() return _AFTER end
local _LETHAL = LinkedList.create() ---@type damageEvent
readonly.lethalEvent = function() return _LETHAL end
local _SOURCE = LinkedList.create() ---@type damageEvent
readonly.sourceEvent = function() return _SOURCE end
local GetUnitLife = GetWidgetLife
local SetUnitLife = SetWidgetLife
local Alive = UnitAlive
local disableT = DisableTrigger
local enableT = EnableTrigger
local hasLethal ---@type boolean
local hasSource ---@type boolean
---@class damageEvent
---@class damageEventRegistry
---@field minAOE integer
---@field filters boolean[]
---@field targetClass unittype
---@field sourceClass unittype
---@field targetItem itemtype
---@field sourceItem itemtype
---@field sourceType unittype
---@field targetType unittype
---@field targetBuff integer
---@field sourceBuff integer
---@field source unit
---@field target unit
---@field attackType attacktype
---@field damageType damagetype
---@field weaponType weapontype
---@field damageMin number
---@field userType integer
---@field trig trigger
---@field eFilter integer
---@field trigFrozen boolean
---@field levelsDeep integer
---@class damageInstance
---@field source unit
---@field target unit
---@field damage real
---@field prevAmt real
---@field isAttack boolean
---@field isRanged boolean
---@field isMelee boolean
---@field attackType attacktype
---@field damageType damagetype
---@field weaponType weapontype
---@field isCode boolean
---@field isSpell boolean
---@field recursiveFunc damageEventRegistry[]
---@field userType integer
---@field armorPierced real
---@field prevArmorT integer
---@field armorType integer
---@field prevDefenseT integer
---@field defenseType integer
local dreaming ---@type boolean
---Turn on (true) or off (false or nil) Damage Engine
---@param on boolean
function Damage.enable(on)
if on then
if dreaming then enableT(t3)
else enableT(t1); enableT(t2) end
else
if dreaming then disableT(t3)
else disableT(t1); disableT(t2) end
end
end
local breakCheck = {} ---@type function[]
local override ---@type boolean
breakCheck[_DAMAGING] = function() return override or current.userType == _TYPE_PURE end
breakCheck[_ARMOR] = function() return current.damage <= 0.00 end
breakCheck[_LETHAL] = function() return hasLethal and Damage.life > _DEATH_VAL end
---@return boolean
local function damageOrAfter() return current.damageType == DAMAGE_TYPE_UNKNOWN end
breakCheck[_DAMAGED] = damageOrAfter
breakCheck[_AFTER] = damageOrAfter
local function defaultCheck() end
---Common function to run any major event in the system.
---@param head damageEventRegistry
---@return boolean ran_yn
local function runEvent(head)
local check = breakCheck[head] or defaultCheck
if dreaming or check() then
return
end
userIndex = head.next
if userIndex ~= head then
Damage.enable(false)
enableT(t3)
dreaming = true
--print("Start of event running")
repeat
if not userIndex.trigFrozen and userIndex.filters[userIndex.eFilter] and checkConfig() and not hasSource or (head ~= _SOURCE or (userIndex.minAOE and sourceAOE > userIndex.minAOE)) then
userIndex.func()
end
userIndex = userIndex.next
until userIndex == head or check()
--print("End of event running")
dreaming = nil
Damage.enable(true)
disableT(t3)
end
return true
end
--[[--------------------------------------------------------------------------------------
Creates a new table for the damage properties for each particular event sequence.
----------------------------------------------------------------------------------------]]
---Create a new damage instance
---@param src unit
---@param tgt unit
---@param amt number
---@param a boolean
---@param r boolean
---@param at attacktype
---@param dt damagetype
---@param wt weapontype
---@param fromCode boolean
---@return damageInstance
local function create(src, tgt, amt, a, r, at, dt, wt, fromCode)
local d = { ---@type damageInstance
source = src,
target = tgt,
damage = amt,
isAttack = a or _USE_GUI and udg_NextDamageIsAttack,
isRanged = r,
attackType = at,
damageType = dt,
weaponType = wt,
prevAmt = amt,
userAmt = amt
}
d.isSpell = at == ATTACK_TYPE_NORMAL and not d.isAttack
if fromCode or Damage.nextType or d.damageType == DAMAGE_TYPE_MIND or (d.damageType == DAMAGE_TYPE_UNKNOWN and d.damage ~= 0.00) or (_USE_GUI and (udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or udg_NextDamageWeaponT)) then
d.isCode = true
d.userType = Damage.nextType or _TYPE_CODE
Damage.nextType = nil
if _USE_MELEE_RANGE and not d.isSpell then
d.isMelee = _USE_GUI and udg_NextDamageIsMelee or (a and not r)
d.isRanged = _USE_GUI and udg_NextDamageIsRanged or (a and r)
end
d.eFilter = _FILTER_CODE
if _USE_GUI then
udg_NextDamageIsAttack = nil
if udg_NextDamageWeaponT then
d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
udg_NextDamageWeaponT = nil
end
if _USE_MELEE_RANGE then
udg_NextDamageIsMelee = nil
udg_NextDamageIsRanged = nil
end
end
else
d.userType = 0
end
return d
end
local GetDamage = GetEventDamage
local createFromEvent
do
local GetSource = GetEventDamageSource
local GetTarget = GetTriggerUnit
local GetIsAttack = BlzGetEventIsAttack
local GetAttackType = BlzGetEventAttackType
local GetDamageType = BlzGetEventDamageType
local GetWeaponType = BlzGetEventWeaponType
---Create a damage event from a naturally-occuring event.
---@param isCode? boolean
---@return damageInstance
function createFromEvent(isCode)
local d = create(GetSource(), GetTarget(), GetDamage(), GetIsAttack(), false, GetAttackType(), GetDamageType(), GetWeaponType(), isCode)
if not d.isCode then
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
if _USE_MELEE_RANGE then
d.isMelee = CheckUnitType(d.source, UNIT_TYPE_MELEE_ATTACKER)
d.isRanged = CheckUnitType(d.source, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
d.isMelee = d.weaponType -- Melee units play a sound when damaging. In naturally-occuring cases where a
d.isRanged = not d.isMelee -- unit is both ranged and melee, the ranged attack plays no sound.
end
if d.isMelee then
d.eFilter = _FILTER_MELEE
elseif d.isRanged then
d.eFilter = _FILTER_RANGED
else
d.eFilter = _FILTER_ATTACK
end
else
d.eFilter = _FILTER_ATTACK
end
else
if d.isSpell then
d.eFilter = _FILTER_SPELL
else
d.eFilter = _FILTER_OTHER
end
end
end
return d
end
end
local alarmSet
Damage.targets = udg_DamageEventAOEGroup
local function onAOEEnd()
if _USE_EXTRA then
runEvent(_SOURCE)
sourceAOE = 1
sourceStacks = 1
originalTarget = nil
originalSource = nil
GroupClear(Damage.targets)
end
end
---Handle any desired armor modification.
---@param reset? boolean
local function setArmor(reset)
if _USE_ARMOR_MOD then
local pierce ---@type real
local at ---@type integer
local dt ---@type integer
if reset then
pierce = current.armorPierced
at = current.prevArmorT
dt = current.prevDefenseT
else
pierce = -current.armorPierced
at = current.armorType
dt = current.defenseType
end
if pierce ~= 0.00 then --Changed condition thanks to bug reported by BLOKKADE
BlzSetUnitArmor(current.target, BlzGetUnitArmor(current.target) + pierce)
end
if current.prevArmorT ~= current.armorType then
BlzSetUnitIntegerField(current.target, UNIT_IF_ARMOR_TYPE, at)
end
if current.prevDefenseT ~= current.defenseType then
BlzSetUnitIntegerField(current.target, UNIT_IF_DEFENSE_TYPE, dt)
end
end
end
local proclusGlobal = {} ---@type boolean[]
local fischerMorrow = {} ---@type boolean[]
local SetEventDamage = BlzSetEventDamage
local doPreEvents
do
local SetEventAttackType = BlzSetEventAttackType
local SetEventDamageType = BlzSetEventDamageType
local SetEventWeaponType = BlzSetEventWeaponType
---Setup pre-events before running any user-facing damage events.
---@param d damageInstance
---@param natural? boolean
---@return boolean isZeroDamage_yn
doPreEvents = function(d, natural)
if _USE_ARMOR_MOD then
d.armorType = BlzGetUnitIntegerField(d.target, UNIT_IF_ARMOR_TYPE)
d.defenseType = BlzGetUnitIntegerField(d.target, UNIT_IF_DEFENSE_TYPE)
d.prevArmorT = d.armorType
d.prevDefenseT = d.defenseType
d.armorPierced = 0.00
end
current = d
proclusGlobal[d.source] = true
fischerMorrow[d.target] = true
if d.damage == 0.00 then
return true
end
override = d.damageType == DAMAGE_TYPE_UNKNOWN
runEvent(_DAMAGING)
if natural then
SetEventAttackType(d.attackType)
SetEventDamageType(d.damageType)
SetEventWeaponType(d.weaponType)
SetEventDamage(d.damage)
end
setArmor()
end
end
local function afterDamage()
if current then
runEvent(_AFTER)
current = nil
end
override = nil
end
local canKick = true
local sleepLevel = 0
local totem, kicking, eventsRun
local prepped = nil ---@type damageInstance
local recursiveStack = {} ---@type damageInstance[]
local UDT = UnitDamageTarget
local function finish()
if eventsRun then
eventsRun = nil
afterDamage()
end
current = nil
override = nil
if canKick and not kicking then
if #recursiveStack > 0 then
kicking = true
local i = 1
local exit
repeat
sleepLevel = sleepLevel + 1
exit = #recursiveStack
repeat
prepped = recursiveStack[i]
if Alive(prepped.target) then
doPreEvents(prepped) --don't evaluate the pre-event
if prepped.damage > 0.00 then
disableT(t1) --Force only the after armor event to run.
enableT(t2) --in case the user forgot to re-enable this
totem = true
UDT(prepped.source, prepped.target, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
runEvent(_DAMAGED)
if prepped.damage < 0.00 then
--No need for BlzSetEventDamage here
SetUnitLife(prepped.target, GetUnitLife(prepped.target) - prepped.damage)
end
setArmor(true)
end
afterDamage()
end
i = i + 1
until (i >= exit)
until (i >= #recursiveStack)
end
for i = 1, #recursiveStack do
recursiveStack[i].recursiveFunc.trigFrozen = nil
recursiveStack[i].recursiveFunc.levelsDeep = 0
recursiveStack[i] = nil
end
sleepLevel = 0
prepped, kicking, dreaming = nil, nil, nil
Damage.enable(true)
proclusGlobal = {} ---@type boolean[]
fischerMorrow = {} ---@type boolean[]
--print("Cleared up the groups")
end
end
local function failsafeClear()
setArmor(true)
canKick = true
kicking, totem = nil, nil
runEvent(_DAMAGED)
eventsRun = true
finish()
end
local lastInstance ---@type damageInstance
local attacksImmune = {} ---@type boolean[]
local damagesImmune = {} ---@type boolean[]
t1 = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
TriggerAddCondition(t1, Filter(function()
local d = createFromEvent()
--print("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
lastInstance = current
totem = nil
canKick = nil
else
failsafeClear() --Not an overlapping event - just wrap it up
end
else
finish() --wrap up any previous damage index
end
if _USE_EXTRA then
if d.source ~= originalSource then
onAOEEnd()
originalSource = d.source
originalTarget = d.target
elseif d.target == originalTarget then
sourceStacks = sourceStacks + 1
elseif not IsUnitInGroup(d.target, Damage.targets) then
sourceAOE = sourceAOE + 1
end
end
else
alarmSet = true
Timed.call(
function()
alarmSet, dreaming = nil, nil
Damage.enable(true)
if totem then
failsafeClear() --WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
canKick = true
kicking = nil
finish()
end
onAOEEnd()
current = nil
--print("Timer wrapped up")
end)
if _USE_EXTRA then
originalSource = d.source
originalTarget = d.target
end
end
if _USE_EXTRA then GroupAddUnit(Damage.targets, d.target) end
if doPreEvents(d, true) then
runEvent(_ZERO)
canKick = true
finish()
end
totem = not lastInstance or attacksImmune[d.attackType] or damagesImmune[d.damageType] or not CheckUnitType(d.target, UNIT_TYPE_MAGIC_IMMUNE)
end))
t2 = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
TriggerAddCondition(t2, Filter(function()
local r = GetDamage()
local d = current
--print("Second damage event running for " .. GetUnitName(GetTriggerUnit()))
if prepped then prepped = nil
elseif dreaming or d.prevAmt == 0.00 then return
elseif totem then totem = nil
else
afterDamage()
d = lastInstance
current = d
lastInstance = nil
canKick = true
end
setArmor(true)
d.userAmt = d.damage
d.damage = r
if r > 0.00 then
runEvent(_ARMOR)
if hasLethal or d.userType < 0 then
Damage.life = GetUnitLife(d.target) - d.damage
if Damage.life <= _DEATH_VAL then
if hasLethal then
runEvent(_LETHAL)
d.damage = GetUnitLife(d.target) - Damage.life
end
if d.userType < 0 and Damage.life <= _DEATH_VAL then
SetUnitExploded(d.target, true)
end
end
end
end
if d.damageType ~= DAMAGE_TYPE_UNKNOWN then runEvent(_DAMAGED) end
SetEventDamage(d.damage)
eventsRun = true
if d.damage == 0.00 then finish() end
end))
--Call to enable recursive damage on your trigger.
function Damage.inception() userIndex.inceptionTrig = true end
---add a recursive damage instance
---@param d damageInstance
local function addRecursive(d)
if d.damage ~= 0.00 then
d.recursiveFunc = userIndex
if kicking and proclusGlobal[d.source] and fischerMorrow[d.target] then
if not userIndex.inceptionTrig then
userIndex.trigFrozen = true
elseif not userIndex.trigFrozen and userIndex.levelsDeep < sleepLevel then
userIndex.levelsDeep = userIndex.levelsDeep + 1
userIndex.trigFrozen = userIndex.levelsDeep >= _LIMBO
end
end
recursiveStack[#recursiveStack + 1] = d
--print("recursiveStack: " .. #recursiveStack .. " levelsDeep: " .. userIndex.levelsDeep .. " sleepLevel: " .. sleepLevel)
end
end
t3 = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
TriggerAddCondition(t3, Filter(function()
addRecursive(createFromEvent(true))
SetEventDamage(0.00)
end))
disableT(t3)
---register a new damage event
---@param head damageEvent
---@param func function
---@param lbs number
---@param filt? integer
---@param trig? trigger
---@return damageEventRegistry
function Damage.register(head, func, lbs, filt, trig)
filt = filt or _FILTER_OTHER
if trig and lastRegistered and lastRegistered.trig and lastRegistered.trig == trig then
lastRegistered.filters[filt]= true
return
end
hasLethal = hasLethal or head == _LETHAL
hasSource = hasSource or head == _SOURCE
local id = {} ---@type damageEventRegistry
lastRegistered = id
id.filters = {}
if filt == _FILTER_OTHER then
id.filters[_FILTER_ATTACK] = true
id.filters[_FILTER_MELEE] = true
id.filters[_FILTER_OTHER] = true
id.filters[_FILTER_RANGED] = true
id.filters[_FILTER_SPELL] = true
id.filters[_FILTER_CODE] = true
elseif filt == _FILTER_ATTACK then
id.filters[_FILTER_ATTACK] = true
id.filters[_FILTER_MELEE] = true
id.filters[_FILTER_RANGED] = true
else
id.filters[filt] = true
end
id.levelsDeep = 0
id.trig = trig
lbs = lbs or 1.00
id.weight = lbs
id.func = func
local insertAt = head
for node in head:loop() do if node.weight > lbs then insertAt = node; break end end
insertAt:insert(id)
--print("Registered new event to " .. var)
return lastRegistered
end
---Remove registered damage event by index
---@param index damageEventRegistry
---@return boolean removed_yn
function Damage.remove(index)
if lastRegistered == index then lastRegistered = nil end
return index:remove()
end
Hook.addSimple("TriggerRegisterVariableEvent",
function(whichTrig, varName, opCode, limitVal)
local index = ((varName == "udg_DamageModifierEvent" and limitVal < 4) or varName == "udg_PreDamageEvent") and _DAMAGING or
(varName == "udg_DamageModifierEvent" or varName == "udg_ArmorDamageEvent") and _ARMOR or
((varName == "udg_DamageEvent" and limitVal == 2 or limitVal == 0) or varName == "udg_ZeroDamageEvent") and _ZERO or
(varName == "udg_DamageEvent" or varName == "udg_OnDamageEvent") and _DAMAGED or
varName == "udg_AfterDamageEvent" and _AFTER or
varName == "udg_LethalDamageEvent" and _LETHAL or
(varName == "udg_AOEDamageEvent" or varName == "udg_SourceDamageEvent") and _SOURCE
if index then
local id = Damage.register(index, function() if IsTriggerEnabled(whichTrig) then ConditionalTriggerExecute(whichTrig) end end, limitVal, GetHandleId(opCode), whichTrig)
if index == _SOURCE then
id.minAOE = (varName == "udg_AOEDamageEvent" and 1) or (varName == "udg_SourceDamageEvent" and 0)
end
return "skip hook"
end
end)
for i = 0, 26 do udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i) end
--For filling an array with values from a table.
---@param arr table
---@param tbl table
---@param offset? integer
local function fillArray(arr, tbl, offset)
for i, v in ipairs(tbl) do arr[i + (offset or -1)] = v end
end
--For filling a group of similarly-named variables.
---@param prefix string
---@param tbl table
---@param offset? integer
local function fillVars(prefix, tbl, offset)
for i, v in ipairs(tbl) do _G[prefix .. v] = i + (offset or -1) end
end
local list
if _USE_GUI then
udg_DamageTypeDebugStr[0] = "UNKNOWN"
udg_DamageTypeDebugStr[4] = "NORMAL"
udg_DamageTypeDebugStr[5] = "ENHANCED"
udg_DAMAGE_TYPE_UNKNOWN = 0
udg_DAMAGE_TYPE_NORMAL = 4
udg_DAMAGE_TYPE_ENHANCED = 5
end
damagesImmune[0] = true
damagesImmune[4] = true
damagesImmune[5] = true
fillArray(damagesImmune, {false, false, false, true, true, false, false, false, true, false, false, false, false, false, true, true, false, false, true}, 7)
if _USE_GUI then
list = {"FIRE", "COLD", "LIGHTNING", "POISON", "DISEASE", "DIVINE", "MAGIC", "SONIC", "ACID", "FORCE", "DEATH", "MIND", "PLANT", "DEFENSIVE", "DEMOLITION", "SLOW_POISON", "SPIRIT_LINK", "SHADOW_STRIKE", "UNIVERSAL"}
fillArray(udg_DamageTypeDebugStr, list, 7)
fillVars("udg_DAMAGE_TYPE_", list, 7)
end
fillArray(attacksImmune, { false, true, true, true, false, true, true})
if _USE_GUI then
list = {"SPELLS", "NORMAL", "PIERCE", "SIEGE", "MAGIC", "CHAOS", "HERO"}
fillArray(udg_AttackTypeDebugStr, list)
fillVars("udg_ATTACK_TYPE_", list)
fillArray(udg_WeaponTypeDebugStr, {"NONE", "METAL_LIGHT_CHOP", "METAL_MEDIUM_CHOP", "METAL_HEAVY_CHOP", "METAL_LIGHT_SLICE", "METAL_MEDIUM_SLICE", "METAL_HEAVY_SLICE", "METAL_MEDIUM_BASH", "METAL_HEAVY_BASH", "METAL_MEDIUM_STAB", "METAL_HEAVY_STAB", "WOOD_LIGHT_SLICE", "WOOD_MEDIUM_SLICE", "WOOD_HEAVY_SLICE", "WOOD_LIGHT_BASH", "WOOD_MEDIUM_BASH", "WOOD_HEAVY_BASH", "WOOD_LIGHT_STAB", "WOOD_MEDIUM_STAB", "CLAW_LIGHT_SLICE", "CLAW_MEDIUM_SLICE", "CLAW_HEAVY_SLICE", "AXE_MEDIUM_CHOP", "ROCK_HEAVY_BASH"})
fillVars("udg_WEAPON_TYPE_", {"NONE", "ML_CHOP", "MM_CHOP", "MH_CHOP", "ML_SLICE", "MM_SLICE", "MH_SLICE", "MM_BASH", "MH_BASH", "MM_STAB", "MH_STAB", "WL_SLICE", "WM_SLICE", "WH_SLICE", "WL_BASH", "WM_BASH", "WH_BASH", "WL_STAB", "WM_STAB", "CL_SLICE", "CM_SLICE", "CH_SLICE", "AM_CHOP", "RH_BASH"})
list = {"LIGHT", "MEDIUM", "HEAVY", "FORTIFIED", "NORMAL", "HERO", "DIVINE", "UNARMORED"}
fillArray(udg_DefenseTypeDebugStr, list)
fillVars("udg_DEFENSE_TYPE_", list)
list = {"NONE", "FLESH", "METAL", "WOOD", "ETHEREAL", "STONE"}
fillArray(udg_ArmorTypeDebugStr, list)
fillVars("udg_ARMOR_TYPE_", list)
fillVars("udg_UNIT_CLASS_", {"HERO", "DEAD", "STRUCTURE", "FLYING", "GROUND", "ATTACKS_FLYING", "ATTACKS_GROUND", "MELEE", "RANGED", "GIANT", "SUMMONED", "STUNNED", "PLAGUED", "SNARED", "UNDEAD", "MECHANICAL", "PEON", "SAPPER", "TOWNHALL", "ANCIENT", "TAUREN", "POISONED", "POLYMORPHED", "SLEEPING", "RESISTANT", "ETHEREAL", "MAGIC_IMMUNE"})
for i = 0, 6 do udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i) end
end
---Apply damage directly via Damage Engine
---@param src unit
---@param tgt unit
---@param amt real
---@param a boolean
---@param r boolean
---@param at attacktype
---@param dt damagetype
---@param wt weapontype
---@return damageInstance
function Damage.apply(src, tgt, amt, a, r, at, dt, wt)
local d ---@type damageInstance
if dreaming then
d = create(src, tgt, amt, a, r, at, dt, wt, true)
addRecursive(d)
else
UDT(src, tgt, amt, a, r, at, dt, wt)
d = current
finish()
end
return d
end
---Deal spell damage using the below simple criteria
---@param src unit
---@param tgt unit
---@param amt real
---@param dt damagetype
---@return damageInstance
function Damage.applySpell(src, tgt, amt, dt)
return Damage.apply(src, tgt, amt, nil, nil, nil, dt, nil)
end
function Damage.applyAttack(src, tgt, amt, ranged, at, wt)
return Damage.apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
end
--[[--------------------------------------------------------------------------------------
The below section defines how GUI interacts with Damage Engine and vice-versa. This is
a breakthrough in coding thanks to the innovation brought forth via Global Variable Remapper.
----------------------------------------------------------------------------------------]]
if _USE_GUI then
---Remap damageInstance types of variables (DamageEventSource/Target/Amount/etc)
---@param oldVarStr string
---@param newVarStr string
---@param get? boolean
---@param set? boolean
local function map(oldVarStr, newVarStr, get, set)
GlobalRemap(oldVarStr, get and function() return current[newVarStr] end, set and function(val) current[newVarStr] = val end)
end
map("udg_DamageEventAmount", "damage", true, true)
map("udg_DamageEventType", "userType", true, true)
if _USE_ARMOR_MOD then
map("udg_DamageEventArmorPierced", "armorPierced", true, true)
map("udg_DamageEventArmorT", "armorType", true, true)
map("udg_DamageEventDefenseT", "defenseType", true, true)
end
map("udg_DamageEventSource", "source", true)
map("udg_DamageEventTarget", "target", true)
map("udg_DamageEventPrevAmt", "prevAmt", true)
map("udg_DamageEventUserAmt", "userAmt", true)
map("udg_IsDamageAttack", "isAttack", true)
map("udg_IsDamageCode", "isCode", true)
map("udg_IsDamageSpell", "isSpell", true)
if _USE_MELEE_RANGE then
map("udg_IsDamageMelee", "isMelee", true)
map("udg_IsDamageRanged", "isRanged", true)
end
GlobalRemap("udg_DamageEventAOE", function() return sourceAOE end)
GlobalRemap("udg_DamageEventLevel", function() return sourceStacks end)
GlobalRemap("udg_AOEDamageSource", function() return originalSource end)
GlobalRemap("udg_EnhancedDamageTarget", function() return originalTarget end)
GlobalRemap("udg_LethalDamageHP", function() return Damage.life end, function(var) Damage.life = var end)
GlobalRemap("udg_DamageEventAttackT", function() return GetHandleId(current.attackType) end, function(var) current.attackType = ConvertAttackType(var) end)
GlobalRemap("udg_DamageEventDamageT", function() return GetHandleId(current.damageType) end, function(var) current.damageType = ConvertDamageType(var) end)
GlobalRemap("udg_DamageEventWeaponT", function() return GetHandleId(current.weaponType) end, function(var) current.weaponType = ConvertWeaponType(var) end)
--New GUI vars unique to version 2.0: boolean DamageEngineEnabled, boolean DamageFilterConfigured, real DamageEventUserAmt
GlobalRemap("udg_DamageEngineEnabled", nil, function(val) Damage.enable(val) end)
GlobalRemap("udg_NextDamageType", nil, function(val) Damage.nextType = val end)
GlobalRemap("udg_RemoveDamageEvent", nil, function() Damage.remove(userIndex) end)
GlobalRemap("udg_DamageFilterSourceC", nil, function(val) current.sourceClass = ConvertUnitType(val) end)
GlobalRemap("udg_DamageFilterTargetC", nil, function(val) current.targetClass = ConvertUnitType(val) end)
---Remap damageEventRegistry type variables (DamageFilterSource/Target/MinAmount/etc)
---@param oldVarStr string
---@param newVarStr string
local function configVar(oldVarStr, newVarStr)
GlobalRemap(oldVarStr, nil,
function(val)
userIndex[newVarStr] = val
end)
end
configVar("udg_DamageFilterSource", "source")
configVar("udg_DamageFilterTarget", "target")
configVar("udg_DamageFilterSourceT", "sourceType")
configVar("udg_DamageFilterTargetT", "targetType")
configVar("udg_DamageFilterType", "userType")
configVar("udg_DamageFilterAttackT", "attackType")
configVar("udg_DamageFilterDamageT", "damageType")
configVar("udg_DamageFilterSourceI", "sourceItem")
configVar("udg_DamageFilterTargetI", "targetItem")
configVar("udg_DamageFilterMinAmount", "damageMin")
configVar("udg_DamageFilterSourceA", "sourceBuff")
configVar("udg_DamageFilterSourceB", "sourceBuff")
configVar("udg_DamageFilterTargetA", "targetBuff")
configVar("udg_DamageFilterTargetB", "targetBuff")
configVar("udg_DamageFilterFailChance", "failChance")
GlobalRemap("udg_DamageFilterRunChance", nil,
function(val)
userIndex.failChance = 1.00 - val
end)
GlobalRemap("udg_DamageFilterConfigured",
function()
local c = userIndex.configured
if not c then
userIndex.configured = 0
return false
elseif c == 0 then
userIndex.configured = 1
return checkConfig()
end
return true
end)
--[[--------------------------------------------------------------------------------------
Set references to readonly variables for public use.
----------------------------------------------------------------------------------------]]
setmetatable(Damage, {
__index =
function(tbl, key)
local index = readonly[key]
if index then return index() end
return rawget(tbl, key)
end,
__newindex =
function(tbl, key, val)
if readonly[key] then return end
rawset(tbl, key, val)
end
})
end
end)
end