Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
all | group | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
APORAR | dialog | No | |
APORARbutt | button | Yes | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
CCSS_3rdPersonCamMode | boolean | No | |
CCSS_AddUnitHeightToCamera | boolean | No | |
CCSS_AlignmentLeft | boolean | No | |
CCSS_AngleOfAttackDefault | real | No | |
CCSS_AngleOfAttackEnabled | boolean | No | |
CCSS_AngleOfAttackMax | real | No | |
CCSS_AngleOfAttackMin | real | No | |
CCSS_AngleOfAttackShow | boolean | No | |
CCSS_AngleOfAttackStep | real | No | |
CCSS_CamUpdateInterval | real | No | |
CCSS_CheckBoxShow | boolean | No | |
CCSS_CheckBoxText | string | No | |
CCSS_CheckBoxTextOnLeft | boolean | No | |
CCSS_DistanceDefault | real | No | |
CCSS_DistanceEnabled | boolean | No | |
CCSS_DistanceMax | real | No | |
CCSS_DistanceMin | real | No | |
CCSS_DistanceShow | boolean | No | |
CCSS_DistanceStep | real | No | |
CCSS_HeightDefault | real | No | |
CCSS_HeightEnabled | boolean | No | |
CCSS_HeightMax | real | No | |
CCSS_HeightMin | real | No | |
CCSS_HeightShow | boolean | No | |
CCSS_HeightStep | real | No | |
CCSS_HorizontalArrowMoveLimit | real | No | |
CCSS_HorizontalReturnSpeed | real | No | |
CCSS_HorizontalSpeed | real | No | |
CCSS_InvertHorizontalMovement | boolean | No | |
CCSS_InvertVerticalMovement | boolean | No | |
CCSS_PositionCheckBoxX | real | No | |
CCSS_PositionCheckBoxY | real | No | |
CCSS_PositionSlidersX | real | No | |
CCSS_PositionSlidersY | real | No | |
CCSS_ResetButtonSizeX | real | No | |
CCSS_ResetButtonSizeY | real | No | |
CCSS_ResetButtonText | string | No | |
CCSS_RotationDefault | real | No | |
CCSS_RotationEnabled | boolean | No | |
CCSS_RotationMax | real | No | |
CCSS_RotationMin | real | No | |
CCSS_RotationShow | boolean | No | |
CCSS_RotationStep | real | No | |
CCSS_SButton180Turn | boolean | No | |
CCSS_SButtonOrder | string | No | |
CCSS_ShowValues | boolean | No | |
CCSS_SliderGap | real | No | |
CCSS_TargetUnit | unit | Yes | |
CCSS_UseArrowKeys | boolean | No | |
CCSS_UseNumpadKeys | boolean | No | |
CCSS_UseWASDKeys | boolean | No | |
CCSS_VerticalReturnSpeed | real | No | |
CCSS_VerticalSpeed | real | No | |
CCSS_WASDMoveMinDistance | real | No | |
CCSS_WASDMoveOrderInterval | real | No | |
CCSS_WASDMoveSpeedModifier | real | No | |
CCSS_WASDStationaryTurnSpeed | real | No | |
CCSS_WASDTurnSpeed | real | No | |
CCSS_XButton180Turn | boolean | No | |
CleanedItem | item | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
Count | integer | No | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
Difficulty | dialog | No | |
DifficultyButt | button | Yes | |
DifficultyNumber | integer | No | |
DmgStr | string | No | |
EnhancedDamageTarget | unit | No | |
Final | timer | No | |
Finale | timerdialog | No | |
Finalex | timerdialog | No | |
Finalx | timer | No | |
giveGoldString | string | No | |
giveGoldTax | real | No | |
HeroA | unitcode | Yes | |
HeroAll | unitcode | Yes | |
HeroI | unitcode | Yes | |
HeronumberA | integer | No | 10 |
HeronumberAll | integer | No | 30 |
HeronumberI | integer | No | 10 |
HeronumberS | integer | No | 10 |
HeroS | unitcode | Yes | |
HeroSelectorEvent | real | No | |
HeroSelectorEventIsRandom | boolean | No | |
HeroSelectorEventPlayer | player | No | |
HeroSelectorEventUnit | unit | No | |
HeroSelectorEventUnitCode | unitcode | No | |
HeroSelectorRandomOnly | unitcode | Yes | |
HeroSelectorUnitCode | unitcode | Yes | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
ItemCleanupFlag | boolean | No | |
ItemCleanupTimer | timer | No | |
ItemsToClean | integer | No | |
kill1 | real | No | |
Kills1 | integer | No | |
Kills2 | integer | No | |
Kills3 | integer | No | |
Kills4 | integer | No | |
Kills5 | integer | No | |
Kills6 | integer | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
Loop | integervar | No | |
Malt | multiboard | No | |
NextDamageType | integer | No | |
Player1 | unit | No | |
Player2 | unit | No | |
Player3 | unit | No | |
Playernumber | integer | No | |
Players | force | No | |
RC_ButtonNo | button | No | |
RC_ButtonYes | button | No | |
RC_Clock | timer | No | |
RC_Dialog | dialog | No | |
RC_Event | real | No | |
RC_Integer | integervar | No | |
RC_MaxDuration | real | No | |
RC_No_Count | integer | No | |
RC_Player | player | No | |
RC_Run | trigger | No | |
RC_Total_Count | integer | No | |
RC_Yes_Count | integer | No | |
ReportLife | real | No | |
RV_Vote | integer | Yes | |
TempInteger | integer | No | |
theeend | timer | No | |
theend | timerdialog | No | |
Timestamp | timer | No | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes |
// Arcing Text Tag v1.0.0.3 by Maker
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.018 // Minimum size of text
private constant real SIZE_BONUS = 0.012 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 50 // Height above unit
private constant real Z_OFFSET_BON = 50 // How much extra height the text gains
private constant real VELOCITY = 2 // How fast the text move in x/y plane
private constant real ANGLE = bj_PI/2 // Movement angle of the text. Does not apply if
// ANGLE_RND is true
private constant boolean ANGLE_RND = true // Is the angle random or fixed
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real ah // arc height
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*.t)
set .t = .t - 0.03125
set .x = .x + .ac
set .y = .y + .as
call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON * p)
call SetTextTagText(.tt, .s, SIZE_MIN + SIZE_BONUS * p)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method create takes string s, unit u returns thistype
local thistype this = rn[0]
static if ANGLE_RND then
local real a = GetRandomReal(0, 2*bj_PI)
else
local real a = ANGLE
endif
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .s = s
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .t = TIME_LIFE
set .as = Sin(a)*VELOCITY
set .ac = Cos(a)*VELOCITY
set .ah = 0.
if IsUnitVisible(u, GetLocalPlayer()) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE)
call SetTextTagFadepoint(.tt, TIME_FADE)
call SetTextTagText(.tt, s, SIZE_MIN)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
return this
endmethod
endstruct
endlibrary
//===========================================================================
//
// Damage Engine 5.5.0.0 - update requires copying of the Damage Engine folder.
//
//===========================================================================
library DamageEngine initializer Init
globals
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private boolean canKick = true
private boolean totem = false
private real lastAmount = 0.00
private real lastPrevAmt = 0.00
private integer lastType = 0
private boolean lastCode = false
private real lastPierced = 0.00
private integer armorType = 0
private integer lastArmor = 0
private boolean lastAttack = false
private integer lastPrevArmor = 0
private integer defenseType = 0
private integer lastDefense = 0
private integer lastPrevDefense = 0
//Stuff to track recursive UnitDamageTarget calls.
private boolean eventsRun = false
private boolean kicking = false
private integer damageStack = 0
private unit array sourceStack
private unit array targetStack
private real array amountStack
private attacktype array attackTStack
private damagetype array damageTStack
private weapontype array weaponTStack
private integer array userTrigStack
private integer array typeStack
//Added in 5.4 to silently eliminate infinite recursion.
private integer userTrigs = 9
private integer eventTrig = 0
private integer array nextTrig
private trigger array userTrig
private boolean array trigFrozen
//Added/re-tooled in 5.4.1 to allow forced recursion (for advanced users only).
private constant integer LIMBO = 16 //Recursion will never go deeper than LIMBO.
private integer array levelsDeep //How deep the user recursion currently is.
public boolean inception = false //You must set DamageEngine_inception = true before dealing damage to utlize this.
//When true, it allows your trigger to potentially go recursive up to LIMBO.
private boolean dreaming = false
private boolean array inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
//Improves readability in the code to have these as named constants.
private constant integer MOD_EVENT = 1
private constant integer SHIELD_EVENT = 4
private constant integer DAMAGE_EVENT = 5
private constant integer ZERO_EVENT = 6
private constant integer AFTER_EVENT = 7
private constant integer LETHAL_EVENT = 8
private constant integer AOE_EVENT = 9
//private string crashStr = ""
endglobals
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
*/
private function RunTrigs takes integer i returns nothing
local integer cat = i
if dreaming then
//call BJDebugMsg("Tried to run triggers while triggers were already running.")
return
endif
set dreaming = true
//call BJDebugMsg("Start of event running")
loop
set i = nextTrig[i]
exitwhen i == 0
exitwhen cat == MOD_EVENT and (udg_DamageEventOverride or udg_DamageEventType*udg_DamageEventType == 4)
exitwhen cat == SHIELD_EVENT and udg_DamageEventAmount <= 0.00
exitwhen cat == LETHAL_EVENT and udg_LethalDamageHP > 0.405
//set crashStr = "Bout to inspect " + I2S(i)
if not trigFrozen[i] and IsTriggerEnabled(userTrig[i]) then
set eventTrig = i
//set crashStr = "Bout to evaluate " + I2S(i)
if TriggerEvaluate(userTrig[i]) then
//set crashStr = "Bout to execute " + I2S(i)
call TriggerExecute(userTrig[i])
endif
//set crashStr = "Ran " + I2S(i)
//call BJDebugMsg("Ran " + I2S(i))
//if not (udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 or udg_DamageEventAmount == 0.00) then
// if cat == MOD_EVENT then
// set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
// elseif cat == SHIELD_EVENT then
// set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
// endif
//elseif udg_DamageEventPrevAmt == 0.00 then
// call BJDebugMsg("Prev amount 0.00 and User Amount " + R2S(udg_DamageEventAmount))
//elseif udg_DamageEventAmount == 0.00 then
// call BJDebugMsg("User amount 0.00 and Prev Amount " + R2S(udg_DamageEventPrevAmt))
//elseif udg_DamageScalingWC3 == 0.00 then
// call BJDebugMsg("WC3 amount somehow 0.00")
//endif
//set crashStr = "Filtered " + I2S(i)
//elseif i > 9 then
// if trigFrozen[i] then
// call BJDebugMsg("User Trigger is frozen")
// else
// call BJDebugMsg("User Trigger is off")
// endif
endif
endloop
//call BJDebugMsg("End of event running")
set dreaming = false
endfunction
private function OnAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call RunTrigs(AOE_EVENT)
set udg_DamageEventAOE = 1
endif
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endfunction
private function AfterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(AFTER_EVENT)
endif
endfunction
private function Finish takes nothing returns nothing
local integer i = 0
local integer exit
if eventsRun then
//call BJDebugMsg("events ran")
set eventsRun = false
call AfterDamage()
endif
if canKick and not kicking then
//call BJDebugMsg("can kick")
if damageStack > 0 then
set kicking = true
//call BJDebugMsg("Clearing queued damage instances: " + I2S(damageStack))
loop
set exit = damageStack
set sleepLevel = sleepLevel + 1
loop
set udg_NextDamageType = typeStack[i]
//call BJDebugMsg("Stacking on " + R2S(amountStack[i]))
call UnitDamageTarget(sourceStack[i], targetStack[i], amountStack[i], true, false, attackTStack[i], damageTStack[i], weaponTStack[i])
call AfterDamage()
set i = i + 1 //Need to loop bottom to top to make sure damage order is preserved.
exitwhen i == exit
endloop
//call BJDebugMsg("Exit at: " + I2S(i))
exitwhen i == damageStack
endloop
//call BJDebugMsg("Terminate at at: " + I2S(i))
set sleepLevel = 0
loop
set i = i - 1
set trigFrozen[userTrigStack[i]] = false //Only re-enable recursive triggers AFTER all damage is dealt.
set levelsDeep[userTrigStack[i]] = 0 //Reset this stuff if the user tried some nonsense
exitwhen i == 0
endloop
//call BJDebugMsg("Cleared queued damage instances: " + I2S(damageStack))
set damageStack = 0 //Can only be set after all the damage has successfully ended.
set kicking = false
endif
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//elseif kicking then
// call BJDebugMsg("Somehow still kicking")
//else
// call BJDebugMsg("Cannot kick")
endif
endfunction
private function ResetArmor takes nothing returns nothing
if udg_DamageEventArmorPierced != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + udg_DamageEventArmorPierced)
endif
if armorType != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, armorType) //revert changes made to the damage instance
endif
if defenseType != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, defenseType)
endif
endfunction
private function FailsafeClear takes nothing returns nothing
//call BJDebugMsg("Damage from " + GetUnitName(udg_DamageEventSource) + " to " + GetUnitName(udg_DamageEventTarget) + " has been messing up Damage Engine.")
//call BJDebugMsg(R2S(udg_DamageEventAmount) + " " + " " + R2S(udg_DamageEventPrevAmt) + " " + udg_AttackTypeDebugStr[udg_DamageEventAttackT] + " " + udg_DamageTypeDebugStr[udg_DamageEventDamageT])
call ResetArmor()
set canKick = true
set totem = false
set udg_DamageEventAmount = 0.00
set udg_DamageScalingWC3 = 0.00
if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(DAMAGE_EVENT) //Run the normal on-damage event based on this failure.
set eventsRun = true //Run the normal after-damage event based on this failure.
endif
call Finish()
endfunction
private function WakeUp takes nothing returns nothing
set alarmSet = false //The timer has expired. Flag off to allow it to be restarted when needed.
//if dreaming then
// set dreaming= false
// call BJDebugMsg("Timer set dreaming to False")
// call BJDebugMsg(crashStr)
//endif
if totem then
//Something went wrong somewhere; the WarCraft 3 engine didn't run the DAMAGED event despite running the DAMAGING event.
call FailsafeClear()
else
if not canKick and damageStack > 0 then
//call BJDebugMsg("Damage Engine recursion deployment was failing with application of: " + R2S(udg_DamageEventAmount))
set canKick = true
endif
call Finish() //Wrap up any outstanding damage instance
endif
call OnAOEEnd() //Reset things so they don't perpetuate for AoE/Level target detection
set udg_DamageEventPrevAmt = 0.00 //Added in 5.4.2.1 to try to squash the Cold Arrows glitch (failed to do it)
endfunction
private function CalibrateMR takes nothing returns nothing
set udg_IsDamageMelee = false
set udg_IsDamageRanged = false
set udg_IsDamageSpell = udg_DamageEventAttackT == 0 and not udg_IsDamageAttack
if udg_DamageEventDamageT == udg_DAMAGE_TYPE_NORMAL and not udg_IsDamageSpell then //This damage type is the only one that can get reduced by armor.
set udg_IsDamageMelee = IsUnitType(udg_DamageEventSource, UNIT_TYPE_MELEE_ATTACKER)
set udg_IsDamageRanged = IsUnitType(udg_DamageEventSource, UNIT_TYPE_RANGED_ATTACKER)
if udg_IsDamageMelee and udg_IsDamageRanged then
set udg_IsDamageMelee = udg_DamageEventWeaponT > 0// Melee units play a sound when damaging
set udg_IsDamageRanged = not udg_IsDamageMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif // The Huntress has a melee sound for her ranged projectile, however it is only an issue
endif //if she also had a melee attack, because by default she is only UNIT_TYPE_RANGED_ATTACKER.
endfunction
private function OnPreDamage takes nothing returns boolean
local unit src = GetEventDamageSource()
local unit tgt = GetTriggerUnit()
local real amt = GetEventDamage()
local attacktype at = BlzGetEventAttackType()
local damagetype dt = BlzGetEventDamageType()
local weapontype wt = BlzGetEventWeaponType()
//call BJDebugMsg("First damage event running")
if dreaming then
//call BJDebugMsg("Dreaming")
if amt != 0.00 then
//Store recursive damage into a queue from index "damageStack" (0-15)
//This damage will be fired after the current damage instance has wrapped up its events.
//This damage can only be caused by triggers.
set amountStack[damageStack] = amt
set sourceStack[damageStack] = src
set targetStack[damageStack] = tgt
set attackTStack[damageStack] = at
set damageTStack[damageStack] = dt
set weaponTStack[damageStack] = wt
set userTrigStack[damageStack] = eventTrig
if udg_NextDamageType == 0 then
set typeStack[damageStack] = udg_DamageTypeCode
else
set typeStack[damageStack] = udg_NextDamageType
endif
//Next block added in 5.4.1 to allow *some* control over whether recursion should kick
//in. Also it's important to track whether the source and target were both involved at
//some earlier point, so this is a more accurate and lenient method than before.
set inception = inception or inceptionTrig[eventTrig]
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
if kicking and IsUnitInGroup(src, proclusGlobal) and IsUnitInGroup(tgt, fischerMorrow) then
if inception and not trigFrozen[eventTrig] then
set inceptionTrig[eventTrig] = true
if levelsDeep[eventTrig] < sleepLevel then
set levelsDeep[eventTrig] = levelsDeep[eventTrig] + 1
if levelsDeep[eventTrig] >= LIMBO then
set trigFrozen[eventTrig] = true
endif
endif
else
set trigFrozen[eventTrig] = true
endif
endif
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(levelsDeep[eventTrig]) + " sleepLevel: " + I2S(sleepLevel))
call BlzSetEventDamage(0.00) //queue the damage instance instead of letting it run recursively
endif
else
if not kicking then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
if alarmSet then
if totem then
if dt != DAMAGE_TYPE_SPIRIT_LINK and dt != DAMAGE_TYPE_DEFENSIVE and dt != DAMAGE_TYPE_PLANT then
//if 'totem' is still set and it's not due to spirit link distribution or defense retaliation,
//the next function must be called as a debug. This reverts an issue I created in patch 5.1.3.
call FailsafeClear()
else
set totem = false
set lastAmount = udg_DamageEventAmount
set lastPrevAmt = udg_DamageEventPrevAmt //Store the actual pre-armor value.
set lastType = udg_DamageEventType //also store the damage type.
set lastCode = udg_IsDamageCode //store this as well.
set lastAttack = udg_IsDamageAttack //Added after this new Reforged native.
set lastArmor = udg_DamageEventArmorT
set lastPrevArmor = armorType
set lastDefense = udg_DamageEventDefenseT
set lastPrevDefense = defenseType
set lastPierced = udg_DamageEventArmorPierced
set canKick = false
endif
else
call Finish()
endif
if src != udg_AOEDamageSource then //Source has damaged more than once
call OnAOEEnd() //New damage source - unflag everything
set udg_AOEDamageSource = src
elseif tgt == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1 //The number of times the same unit was hit.
elseif not IsUnitInGroup(tgt, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1 //Multiple targets hit by this source - flag as AOE
endif
else
call TimerStart(alarm, 0.00, false, function WakeUp)
set alarmSet = true
set udg_AOEDamageSource = src
set udg_EnhancedDamageTarget= tgt
endif
call GroupAddUnit(udg_DamageEventAOEGroup, tgt)
endif
set udg_DamageEventType = udg_NextDamageType
set udg_IsDamageCode = udg_NextDamageType != 0
set udg_IsDamageAttack = BlzGetEventIsAttack()
set udg_DamageEventOverride = dt == null //Got rid of NextDamageOverride in 5.1 for simplicity
set udg_DamageEventPrevAmt = amt
set udg_DamageEventSource = src
set udg_DamageEventTarget = tgt
set udg_DamageEventAmount = amt
set udg_DamageEventAttackT = GetHandleId(at)
set udg_DamageEventDamageT = GetHandleId(dt)
set udg_DamageEventWeaponT = GetHandleId(wt)
call CalibrateMR() //Set Melee and Ranged settings.
set udg_DamageEventArmorT = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE) //Introduced in Damage Engine 5.2.0.0
set udg_DamageEventDefenseT = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE)
set armorType = udg_DamageEventArmorT
set defenseType = udg_DamageEventDefenseT
set udg_DamageEventArmorPierced = 0.00
set udg_DamageScalingUser = 1.00
set udg_DamageScalingWC3 = 1.00
if amt != 0.00 then
if not udg_DamageEventOverride then
call RunTrigs(MOD_EVENT)
//All events have run and the pre-damage amount is finalized.
call BlzSetEventAttackType(ConvertAttackType(udg_DamageEventAttackT))
call BlzSetEventDamageType(ConvertDamageType(udg_DamageEventDamageT))
call BlzSetEventWeaponType(ConvertWeaponType(udg_DamageEventWeaponT))
if udg_DamageEventArmorPierced != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) - udg_DamageEventArmorPierced)
endif
if armorType != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, udg_DamageEventArmorT) //Introduced in Damage Engine 5.2.0.0
endif
if defenseType != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, udg_DamageEventDefenseT) //Introduced in Damage Engine 5.2.0.0
endif
call BlzSetEventDamage(udg_DamageEventAmount)
endif
//call BJDebugMsg("Ready to deal " + R2S(udg_DamageEventAmount))
set totem = true
else
call RunTrigs(ZERO_EVENT)
set canKick = true
call Finish()
endif
endif
set src = null
set tgt = null
set inception = false
set udg_NextDamageType = 0
return false
endfunction
//The traditional on-damage response, where armor reduction has already been factored in.
private function OnDamage takes nothing returns boolean
local real r = GetEventDamage()
//call BJDebugMsg("Second damage event running")
if dreaming or udg_DamageEventPrevAmt == 0.00 then
//if dreaming then
// call BJDebugMsg("Dreaming")
//else
// call BJDebugMsg("Prev amount is zero")
//endif
return false
endif
if totem then
set totem = false //This should be the case in almost all circumstances
else
call AfterDamage() //Wrap up the outstanding damage instance
set canKick = true
//Unfortunately, Spirit Link and Thorns Aura/Spiked Carapace fire the DAMAGED event out of sequence with the DAMAGING event,
//so I have to re-generate a buncha stuff here.
set udg_DamageEventSource = GetEventDamageSource()
set udg_DamageEventTarget = GetTriggerUnit()
set udg_DamageEventAmount = lastAmount
set udg_DamageEventPrevAmt = lastPrevAmt
set udg_DamageEventAttackT = GetHandleId(BlzGetEventAttackType())
set udg_DamageEventDamageT = GetHandleId(BlzGetEventDamageType())
set udg_DamageEventWeaponT = GetHandleId(BlzGetEventWeaponType())
set udg_DamageEventType = lastType
set udg_IsDamageAttack = lastAttack
set udg_IsDamageCode = lastCode
set udg_DamageEventArmorT = lastArmor
set udg_DamageEventDefenseT = lastDefense
set udg_DamageEventArmorPierced = lastPierced
set armorType = lastPrevArmor
set defenseType = lastPrevDefense
call CalibrateMR() //Apply melee/ranged settings once again.
endif
call ResetArmor()
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
set udg_DamageScalingUser = udg_DamageEventAmount / udg_DamageEventPrevAmt
endif
set udg_DamageEventAmount = udg_DamageEventAmount*udg_DamageScalingWC3
if udg_DamageEventAmount > 0.00 then
//This event is used for custom shields which have a limited hit point value
//The shield here kicks in after armor, so it acts like extra hit points.
call RunTrigs(SHIELD_EVENT)
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= 0.405 then
call RunTrigs(LETHAL_EVENT) //Added 10 May 2019 to detect and potentially prevent lethal damage. Instead of
//modifying the damage, you need to modify LethalDamageHP instead (the final HP of the unit).
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
if udg_DamageEventType < 0 and udg_LethalDamageHP <= 0.405 then
call SetUnitExploded(udg_DamageEventTarget, true) //Explosive damage types should blow up the target.
endif
endif
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
call BlzSetEventDamage(udg_DamageEventAmount) //Apply the final damage amount.
if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(DAMAGE_EVENT)
endif
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call Finish()
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGED) //Thanks to this I no longer have to create an event for every unit in the map.
call TriggerAddCondition(trig, Filter(function OnDamage))
set trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGING) //The new 1.31 event which fires before damage.
call TriggerAddCondition(trig, Filter(function OnPreDamage))
set trig = null
endfunction
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//This function exists mainly to make it easier to switch from another DDS, like PDD.
function UnitDamageTargetEx takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns boolean
if udg_NextDamageType == 0 then
set udg_NextDamageType = udg_DamageTypeCode
endif
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
return dreaming
endfunction
public function SetupEvent takes trigger whichTrig, string var, integer index returns nothing
local integer max = 1
local integer off = 0
local integer exit = 0
local integer i
if var == "udg_DamageModifierEvent" then //MOD_EVENT 1-4 -> Events 1-4
if index < 3 then
set exit = index + 1
endif
if nextTrig[1] == 0 then
set nextTrig[1] = 2
set nextTrig[2] = 3
set trigFrozen[2] = true
set trigFrozen[3] = true
endif
set max = 4
elseif var == "udg_DamageEvent" then //DAMAGE_EVENT 1,2 -> Events 5,6
set max = 2
set off = 4
elseif var == "udg_AfterDamageEvent" then //AFTER_EVENT -> Event 7
set off = 6
elseif var == "udg_LethalDamageEvent" then //LETHAL_EVENT -> Event 8
set off = 7
elseif var == "udg_AOEDamageEvent" then //AOE_EVENT -> Event 9
set off = 8
else
return
endif
set i = IMaxBJ(IMinBJ(index, max), 1) + off
//call BJDebugMsg("Root index: " + I2S(i))
loop
set index = i
set i = nextTrig[i]
exitwhen i == exit
endloop
set userTrigs = userTrigs + 1 //User list runs from index 10 and up
set nextTrig[index] = userTrigs
set nextTrig[userTrigs] = exit
set userTrig[userTrigs] = whichTrig
//call BJDebugMsg("Registered " + I2S(userTrigs) + " to " + I2S(index))
endfunction
private function PreSetup takes trigger whichTrig, string var, limitop op, real value returns nothing
call SetupEvent(whichTrig, var, R2I(value))
endfunction
hook TriggerRegisterVariableEvent PreSetup
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
library ValueIndexing initializer Init
//===========================================================================
// Information:
//==============
// This is a library that allows you to get unique hashvalues for any number you like.
// This also gives the option to be directly added to the struct, so you will have this syntax:
// set Data['some'] = anyValue
//
// But you could also do it with table, right?
// Well that's correct, but in many cases this is faster;
// It is proven that LoadInteger is much faster than SaveInteger.
// When you apply new data to a normal table, SaveInteger is used.
// This system only uses SaveInteger if it hasn't created a hash yet.
//
// But the bad thing is that you should remove the hashvalues after a while, since
// there is a limit of 8191 unique hashnumbers. Also this is not available as a struct,
// just as a module.
//===========================================================================
// FAQ:
// ====
//
// 1. We have a maximum of 8190 possible hashes. And there's no clearHash function.
// Won't this break after a while?
//
// Answer: No, it won't. If the number of hahes reach a critical point, all hashes
// that have been in the game for longer than HASH_DECAY_TIME seconds will
// be removed then.
//
//===========================================================================
globals
private constant real HASH_DECAY_TIME = 500.
private constant integer CLEAR_HASH_COUNT = 8190
endglobals
globals
private hashtable HashTable = InitHashtable()
private integer HashNumber = 0
private integer array HashData
private integer array HashHash
private integer array HashPlace
private real array CreationTime
private integer TempHashNumber = 0
private integer array TempHashHash
private integer array TempHashPlace
private integer array TempHashData
private real array TempCreationTime
private integer LastHashedValue = 0
private integer LastIndex = 0
private real GameTime = 0.
private timer GameTimeTimer = CreateTimer()
private constant real GAMETIME_TIMER_INTERVAL = 30.
private constant integer key = 0
endglobals
private function GetElapsedGameTime takes nothing returns real
return GameTime + TimerGetElapsed(GameTimeTimer)
endfunction
private function UpdateGameTime takes nothing returns nothing
set GameTime = GameTime + GAMETIME_TIMER_INTERVAL
endfunction
// Well, the method to do this that I use in my automatic memory leak destroyer
// is much more efficient, but I think that's not iportant in this library,
// because old Hashes are destroyed very rarely.
private function DestroyHashes takes nothing returns nothing
local real gt = GetElapsedGameTime
local Index ind
// Well, due to the nature of this system, the looking of the code sucks.
loop
exitwhen HashNumber == 0
if gt - CreationTime[HashNumber] > HASH_DECAY_TIME then
set ind = HashHash[HashNumber]
call ind.destroy()
call RemoveSavedInteger(HashTable,key,HashData[HashNumber])
else
set TempHashNumber = TempHashNumber + 1
set TempHashData[TempHashNumber] = HashData[HashNumber]
set TempHashHash[TempHashNumber] = HashHash[HashNumber]
set TempHashPlace[TempHashNumber] = HashPlace[HashNumber]
set TempCreationTime[TempHashNumber] = CreationTime[HashNumber]
endif
set HashData[HashNumber] = 0
set HashHash[HashNumber] = 0
set HashPlace[HashNumber] = 0
set CreationTime[HashNumber] = 0.
set HashNumber = HashNumber - 1
endloop
loop
exitwhen TempHashNumber == 0
set HashNumber = HashNumber + 1
set HashData[HashNumber] = TempHashData[TempHashNumber]
set HashHash[HashNumber] = TempHashHash[TempHashNumber]
set HashPlace[HashNumber] = TempHashPlace[TempHashNumber]
set TempHashData[TempHashNumber] = 0
set TempHashNumber = TempHashNumber - 1
endloop
endfunction
struct Index
static method GetHash takes integer value returns integer
local integer int = LoadInteger(HashTable,key,value)
if int == 0 then
set int = Index.create()
call SaveInteger(HashTable,key,value,int)
set HashNumber = HashNumber + 1
set HashPlace[int] = HashNumber
set HashData[HashNumber] = value
set HashHash[HashNumber] = int
set CreationTime[HashNumber] = GetElapsedGameTime()
if HashNumber >= CLEAR_HASH_COUNT then
call DestroyHashes()
endif
endif
set LastHashedValue = value
set LastIndex = int
return int
endmethod
endstruct
function ProtectHash takes integer value returns nothing
if value == LastHashedValue then
set CreationTime[HashPlace[LastIndex]] = 999999999.
else
set CreationTime[HashPlace[Index.GetHash(value)]] = 999999999.
endif
endfunction
function GetValueIndex takes integer value returns integer
return Index.GetHash(value)
endfunction
private function Init takes nothing returns nothing
call TimerStart(GameTimeTimer,GAMETIME_TIMER_INTERVAL,true,function UpdateGameTime)
endfunction
module ValueIndexing
static integer array Data
static method operator []= takes integer i, integer equals returns nothing
set .Data[Index.GetHash(i)] = equals
endmethod
static method operator [] takes integer i returns thistype
return .Data[Index.GetHash(i)]
endmethod
endmodule
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
//=============================================================
// initialize it all.
//
private static method onInit takes nothing returns nothing
set ht = InitHashtable()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=437
//TESH.alwaysfold=0
library MemoryLeakHelper initializer Init requires Table
// ==================================
// Give credits to Mr.Malte when used!
//===========================================================================
// Information:
//==============
//
// There are things called 'memory Leaks'. When you create a group or use a location
// without destroying it, you will cause lag that stays in the whole game.
// If you implement this library into your map it will automatically fix a big part
// of those memory leaks, so reduce the lag extremely.
// This should mainfully be used by GUI-users because the system is designed for them.
//
// Of course no system can work totally automatically.
// But there is only one thing you have to do in order to prevent bugs:
// If you make groups or locations that have to be filled for more than CLEAN_UP_INTERVAL seconds
// you have to save them with the code:
//
// call ProtectHandle(XXX)
//
// Where XXX is filled with your variable. Otherwise that variable gets destroyed
// automatically. You can also fill in XXX with
//
// GetLastCaughtHandle()
//
// But if you save the things in a variable, I'd recommend to directly put the
// variable into the brackets. Note: GUI variables have the prefix 'udg_' in JASS.
//
// This gives the 'Do Nothing' function in GUI a sense!
// When you call DoNothing, all data that were caught by this system
// will be destroyed in CLEAN_UP_INTERVAL seconds, ignoring how big
// the number of caught handles is. This will not work, if the system is
// already cleaning up.
//===========================================================================
// Implementation:
//===============
//
// The easiest thing is to directly implement this thing into your map, when you start making
// it, so you don't have to look over your globals and use ProtectHandle on them.
// These are the steps you have to do to clear the memory leaks:
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// http://www.wc3c.net/showthread.php?t=90999
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// http://www.wc3c.net/showthread.php?t=101246
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//
// Note: Instead of doing 2 and 3 you can also copy and paste the folder 'MemoryLeakHelper'
// from the example map.
//===========================================================================
// How bad are memory leaks?
//==========================
// If you don't remove memory leaks, they suck memory:
//
// Location: 0.361 kb
// Group: 0.62 kb + 0.040 kb for each unit in the group.
// Effect: 11.631 kb
//
// Both, locations and groups are used very frequently. So when you don't fix those memory leaks,
// you will experience lag.
// When you want to see, how useful this is for your map, implement it
// and write 'call DisplayLeaks()' into a custom script that is fired when
// they game ends.
//===========================================================================
// Changelog:
//===========
// v1.00 --- first version
// v1.01 --- able to detect special effects, too now.
// v1.02 --- made the system safer and reduced the number of variables to protect greatly.
// v1.03 --- Gave a sense to 'DoNothing'* GUI function and made the Pass Data part
// more accurate, so the time until data get destroyed are much more explicit
// now.
// v1.04 --- Added the very important constant MAX_LEAK_INSTANCES
//
// *if you don't want it to be hooked, comment line 350.
//===========================================================================
// FAQ:
// ====
// 1. Why don't you hook functions like GetLocationX or the ForGroup without BJ?
//
// Answer: Well, in jass you would never destroy groups, rather have one global group
// and clear/recycle it. But GUI always creates new groups with the functions.
// So actually, jass groups don't have to be destroyed.
// And special effects are mostly instantly destroyed and locations are never used.
// So I don't want to endanger breaking jass systems, I rather make it for GUI, where it is
// really useful and neccessary
//
// 2. Why should I protect my variables instead of killing my leaks?
//
// Answer: In GUI, unitgroup effect and location variables are actually just used
// for destroying stuff. It is rare that you really want to keep the groups.
// So in fact, it is like one-hundred times less frequent that you want to keep
// your data instead of destroying it.
//
// 3. I can't use jass. How can this system be useful for me?
//
// Answer: This system works mainly automatically; You just have to use jass very rarely (and then a simple function).
// The functions you need are:
//
// ProtectVariable(udg_###)
// GetLastCaughtHandle()
//
// where ProtectVariable saves something you want to keep from getting destroyed. Just replace ### with your
// variable name. NOTE: You don't have to protect the variable, when you want to keep the data inside less than
// CLEAN_UP_INTERVAL seconds.
//
// and where GetLastCaughtHandle responses to the handle* that was used lastly.
// That can be for example the point where you just spawned a unit.
//
// * 'handle' means a specialeffect, a location or a unitgroup
//
// 4. If you give functions like 'DelayMMH', why don't you add functions like 'Disable/EnableMMH'?
//
// Answer: Well, I want to protect the user. You do not need Disable/Enable functions.
// To me the danger is too big, that you forget to activate it again or do
// something like that. DelayMMH is totally enough if you don't want this system
// to affect the code that comes next. Also that prevents, that there are
// spells like 'Trojan Horses' that get too much access to this and can
// change it's infrastructure.
//
//===========================================================================
// Functions:
//==========
// ProtectHandle : Saves a handle from getting destroyed
// ProtectVariable : Same.
// DoNothing() : Destroys all data caught by the system right now in X seconds.
// DelayMMD() : Stops the system working until the trigger ends/next wait *
//
// * This is as fast as an automatic memory leak destroyer can get. Why should
// you want to disable the system? Because it offers the possibilty to make things
// more efficient. I don't want to say, this is unefficient, because it is not.
// But this will destroy leaks like 10% slower.
//
//===========================================================================
globals
// The system fires when you do something that creates a leak.
// The data that cause leak are saved in a variable then.
// And every CLEAN_UP_INTERVAL seconds those data are destroyed.
// This shouldn't be too high, or too low.
private constant real CLEAN_UP_INTERVAL = 120.
// If this is set to true, the system will work more slowly (but you wont notice)
// and count, how much memory this system was able to save.
// This value is display by the function DisplayLeaks() then.
// WARNING: This sucks a lot of performance. I would ONLY use it when you want
// to test, if this is useful for your map. Later set it to false.
private constant boolean DISPLAY_SAVED_MEMORY = false
// The Data are only cleaned up, when that many handles were caught
private constant integer MIN_LEAK_NUMBER = 1750
// How often are data passed to the destroyer?
// Leaks stay for a random time between CLEAN_UP_INTERVAL and CLEAN_UP_INTERVAL+PASS_INTERVAL
// in the game
private constant real PASS_INTERVAL = 2.5
// Memory leaks occur pretty frequently. When a leak is caught it is saved in
// an array. But the array can't have more than MAX_LEAK_INSTANCES instances, so
// if more than MAX_LEAK_INSTANCES memory leaks occur during a destroy interval,
// the system fails.
private constant integer MAX_LEAK_INSTANCES = 60000
endglobals
globals
private HandleTable IndexData
private HandleTable IsSaved
//! textmacro MemoryLeakVars takes NAME, TYPE
private integer Caught$NAME$Leaks = 0
private $TYPE$ array $NAME$LeakData[MAX_LEAK_INSTANCES]
private integer $NAME$DestroyCount = 0
private $TYPE$ array $NAME$DestroyData[MAX_LEAK_INSTANCES]
//! endtextmacro
//! runtextmacro MemoryLeakVars("Location","location")
//! runtextmacro MemoryLeakVars("Effect","effect")
//! runtextmacro MemoryLeakVars("Group","group")
private integer DestroyedLeaks = 0
private integer CaughtLeaks = 0
private integer DestroyedLeaksUser = 0
private handle LastCaught
private timer PassTimer = CreateTimer()
private timer CleanTimer = CreateTimer()
private timer DelayTimer = CreateTimer()
private boolean IsDestroying = false
private real SavedMemory = 0.
private real LastCheckedGroupMemoryUsage = 0.
private boolean DestroyThreadRunning = false
private boolean Disabled = false
// These values were found out in a big leak test by gekko.
private constant real LOCATION_MEMORY_USAGE = 0.361
private constant real GROUP_MEMORY_USAGE = 0.62
private constant real GROUP_UNIT_MEMORY_USAGE = 0.040
private constant real EFFECT_MEMORY_USAGE = 11.631
private constant real REMOVED_EFFECT_MEMORY_USAGE = 0.066
endglobals
// ======================================
// ============= Basic Code =============
// ======================================
function GetLastCaughtHandle takes nothing returns handle
return LastCaught
endfunction
function ProtectHandle takes handle h returns nothing
set IsSaved[h] = 1
endfunction
function ProtectVariable takes handle h returns nothing
set IsSaved[h] = 1
endfunction
private function EnableMMH takes nothing returns nothing
set Disabled = false
endfunction
function DelayMMH takes nothing returns nothing
set Disabled = true
call TimerStart(DelayTimer,0.00,false,function EnableMMH)
endfunction
function DisplayLeaks takes nothing returns nothing
call ClearTextMessages()
call BJDebugMsg("======= MemoryLeakHelper =======")
call BJDebugMsg("Destroyed Leaks: "+I2S(DestroyedLeaks))
call BJDebugMsg("Destroyed Leaks by user: "+I2S(DestroyedLeaksUser))
call BJDebugMsg("Percentage System: "+R2S(I2R(DestroyedLeaks)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Percentage User: "+R2S(I2R(DestroyedLeaksUser)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Leaks until next destroy: "+I2S(MIN_LEAK_NUMBER-CaughtLeaks))
call BJDebugMsg(" === In Destroy Queue === ")
call BJDebugMsg(" Group Leaks: "+I2S(GroupDestroyCount))
call BJDebugMsg(" Location Leaks: "+I2S(LocationDestroyCount))
call BJDebugMsg(" Effect Leaks: "+I2S(EffectDestroyCount))
call BJDebugMsg(" === Not in Destroy Queue yet === ")
call BJDebugMsg(" Group Leaks: "+I2S(CaughtGroupLeaks))
call BJDebugMsg(" Location Leaks: "+I2S(CaughtLocationLeaks))
call BJDebugMsg(" Effect Leaks: "+I2S(CaughtEffectLeaks))
call BJDebugMsg("Time until next PassSequence: "+I2S(R2I(TimerGetRemaining(PassTimer)+0.5))+" seconds.")
call BJDebugMsg(" ")
if DISPLAY_SAVED_MEMORY then
call BJDebugMsg("All in all the MemoryLeakHelper could release "+R2S(SavedMemory)+" kb of memory.")
endif
call BJDebugMsg("================================")
endfunction
private function GroupGetMemoryUsageEnum takes nothing returns nothing
set LastCheckedGroupMemoryUsage = LastCheckedGroupMemoryUsage + GROUP_UNIT_MEMORY_USAGE
endfunction
function GroupGetMemoryUsage takes group g returns real
set LastCheckedGroupMemoryUsage = 0.
call ForGroup(g,function GroupGetMemoryUsageEnum)
return LastCheckedGroupMemoryUsage + GROUP_MEMORY_USAGE
endfunction
//! textmacro ResponseOnLeak takes NAME, VALUE
private function Catch$NAME$ takes $VALUE$ l returns nothing
set LastCaught = l
if Disabled then
return
elseif Caught$NAME$Leaks == MAX_LEAK_INSTANCES then
debug call BJDebugMsg("MemoryLeakHelper: Failed to store leak because of size limitations")
return
endif
if IndexData.exists(l) == false then
//call BJDebugMsg("Caught $NAME$")
set Caught$NAME$Leaks = Caught$NAME$Leaks + 1
set $NAME$LeakData[Caught$NAME$Leaks] = l
set IndexData[l] = Caught$NAME$Leaks
endif
endfunction
private function AddTo$NAME$DestroyQueue takes $VALUE$ l returns nothing
set $NAME$DestroyCount = $NAME$DestroyCount + 1
set $NAME$DestroyData[$NAME$DestroyCount] = l
set IndexData[l] = $NAME$DestroyCount*-1 // Put his to negative, so we know that this is used in the DestroyQueue now.
endfunction
private function Release$NAME$ takes $VALUE$ l returns nothing
local integer index
if IsDestroying == false and IndexData.exists(l) then
set index = IndexData[l]
// If this is true, the index wasn't put to a destroy queue yet.
if index > 0 then
set $NAME$LeakData[index] = $NAME$LeakData[Caught$NAME$Leaks]
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
else
set index = index * -1
set $NAME$DestroyData[index] = $NAME$DestroyData[$NAME$DestroyCount]
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endif
call IndexData.flush(l)
set DestroyedLeaksUser = DestroyedLeaksUser + 1
endif
endfunction
//! endtextmacro
//! runtextmacro ResponseOnLeak("Location","location")
//! runtextmacro ResponseOnLeak("Group","group")
//! runtextmacro ResponseOnLeak("Effect","effect")
private function DestroyMemoryLeaks takes nothing returns nothing
set IsDestroying = true
//call BJDebugMsg("DESTROYING Memory Leaks")
//! textmacro DestroyLeaks takes NAME, DESTROYCALL, MEMORYUSAGE
set DestroyedLeaks = DestroyedLeaks + $NAME$DestroyCount
loop
exitwhen $NAME$DestroyCount == 0
if DISPLAY_SAVED_MEMORY then
set SavedMemory = SavedMemory + $MEMORYUSAGE$
endif
call $DESTROYCALL$($NAME$DestroyData[$NAME$DestroyCount])
call IndexData.flush($NAME$DestroyData[$NAME$DestroyCount])
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endloop
//! endtextmacro
//! runtextmacro DestroyLeaks ("Group","DestroyGroup","GroupGetMemoryUsage(GroupDestroyData[GroupDestroyCount])")
//! runtextmacro DestroyLeaks ("Location","RemoveLocation","LOCATION_MEMORY_USAGE")
//! runtextmacro DestroyLeaks ("Effect","DestroyEffect","EFFECT_MEMORY_USAGE")
set IsDestroying = false
set DestroyThreadRunning = false
//call StartPassTimer.execute() // Strange. This causes bugs sometimes and the function isn't called
// This is slower, but safe.
call ExecuteFunc("StartPassTimer")
endfunction
function StartDestroyThread takes nothing returns nothing
if DestroyThreadRunning == false then
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
call PauseTimer(PassTimer)
endif
endfunction
hook DoNothing StartDestroyThread
// We want that the user doesn't have to protect too many variables, but all the variables that are filled longer
// than CLEAN_UP_INTERVAL seconds. But what, when the handle thing is put into the destroy stack and the next destroy is
// in 5 seconds, because the last one was 15 seconds ago? We can simply avoid something like that by using a 2-step-system
// that goes sure, the handle is only destroyed when it passed the CLEAN_UP_INTERVAL twice.
// Having two kinds of variables is simply easier and more efficient than having another variable that refers to
// how many times the handle passed the timer; If it isn't passed/cleared in the Interval then, we can't loop
// that easily through the data and we'd have to fix gaps later; That would suck a lot of performacne.
private function PassMemoryLeaks takes nothing returns nothing
//call BJDebugMsg("PassMemoryLeaks")
//! textmacro PassLeaks takes NAME
set CaughtLeaks = CaughtLeaks + Caught$NAME$Leaks
//call BJDebugMsg("Caught $NAME$s: "+I2S(Caught$NAME$Leaks))
loop
exitwhen Caught$NAME$Leaks < 1
if IsSaved.exists($NAME$LeakData[Caught$NAME$Leaks]) == false and $NAME$LeakData[Caught$NAME$Leaks] != null then
call AddTo$NAME$DestroyQueue($NAME$LeakData[Caught$NAME$Leaks])
endif
set $NAME$LeakData[Caught$NAME$Leaks] = null
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
endloop
//! endtextmacro
//! runtextmacro PassLeaks ("Group")
//! runtextmacro PassLeaks ("Location")
//! runtextmacro PassLeaks ("Effect")
if CaughtLeaks > MIN_LEAK_NUMBER then
set CaughtLeaks = 0
//call BJDebugMsg("Caught Leaks: "+I2S(MIN_LEAK_NUMBER))
//call BJDebugMsg("Now start Destroy Timer")
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
// We have to pause this timer a bit; Otherwise it would break the CLEAN_UP_INTERVAL rule.
call PauseTimer(PassTimer)
endif
endfunction
// =================================
// ============= Usage =============
// =================================
private function PP takes location source, real dist, real angle returns nothing
call CatchLocation(source)
endfunction
private function CU takes integer count, integer unitId, player p, location l, real face returns nothing
call CatchLocation(l)
endfunction
private function IPO takes unit k, string order, location l returns nothing
call CatchLocation(l)
endfunction
private function SUP takes unit who, location l returns nothing
call CatchLocation(l)
endfunction
private function SUF takes unit who, location l, real dur returns nothing
call CatchLocation(l)
endfunction
private function GUR takes real radius, location l, boolexpr filter returns nothing
call CatchLocation(l)
endfunction
private function CUF takes integer count, integer unitId, player whichPlayer, location loc, location lookAt returns nothing
call CatchLocation(loc)
call CatchLocation(lookAt)
endfunction
hook PolarProjectionBJ PP
hook CreateNUnitsAtLoc CU
hook CreateNUnitsAtLocFacingLocBJ CUF
hook IssuePointOrderLocBJ IPO
hook SetUnitPositionLoc SUP
hook SetUnitFacingToFaceLocTimed SUF
hook GetUnitsInRangeOfLocMatching GUR
hook RemoveLocation ReleaseLocation
private function FG takes group g, code callback returns nothing
call CatchGroup(g)
endfunction
hook ForGroupBJ FG // :D This should catch all GUI usages for groups.
hook GroupPickRandomUnit CatchGroup
hook CountUnitsInGroup CatchGroup
hook DestroyGroup ReleaseGroup
private function ASETU takes string bla, widget d, string blu returns nothing
// We can not catch THIS effect, but the effect that was created before.
// So we can destroy all SpecialEffects excpet one.
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
private function ASE takes location where, string modelName returns nothing
call CatchLocation(where)
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
hook AddSpecialEffectLocBJ ASE
hook AddSpecialEffectTargetUnitBJ ASETU
hook DestroyEffect ReleaseEffect
hook DestroyEffectBJ ReleaseEffect
// When I want to make the timer run the PassMemoryLeaks things, I have to use an .execute command which requires an extra func.
function StartPassTimer takes nothing returns nothing
//call BJDebugMsg("Restarting PassTimer")
call TimerStart(PassTimer,PASS_INTERVAL,true,function PassMemoryLeaks)
endfunction
private function Init takes nothing returns nothing
set IndexData = HandleTable.create()
set IsSaved = HandleTable.create()
call StartPassTimer()
endfunction
endlibrary
library TeamViewer
//TeamViewer 1.3
//Plugin for HeroSelector by Tasyen
//It shows the selection of Teams in groups
//Default setup could be suited for 2 team games
//API
// TeamViewerDestroy()
// destroys Frames created by TeamViewer
// TeamViewerInit()
// creates Frames of TeamViewer, normaly should be called at the end of HeroSelectors Init
globals
private boolean ShowNonAllies = true //show non allies
private boolean UpdateNonAllies = false //update the image of non allies when the select or pick
//position when ShowNonAllies = false or when a TeamPos is not set
//how big are the Faces
private real ButtonSize = 0.03
private integer ButtonAlphaSelected = 150
private string ButtonDefaultIcon = "UI\\Widgets\\EscMenu\\Human\\quest-unknown.blp"
private real CategoryButtonSize = 0.015 //size of the CategoryButtons below an players name
private real CategoryButtonGap = 0.002 // space between 2 CategoryButtons
//used when ShowNonAllies = true
//warcraft 3 Teams start with 0
private real array TeamPosX
private real array TeamPosY
private real array TeamPosGapY
private boolean array TeamPosLeft2Right
private boolean array HasPicked
private framehandle array playerParentFrame
private framehandle array playerFaceButton
private framehandle array playerFaceIcon
private framehandle array playerFaceIconDisabled
private framehandle array playerFaceTooltip
private framehandle array playerFaceName
private framehandle array LastTeamFaceButton
//2D
private framehandle array playerCategoryIcon
private framehandle array playerCategoryButton
private framehandle array playerCategoryTooltip
private string array OriginalHex
endglobals
function TeamViewerSetup takes nothing returns nothing
set TeamPosX[0] = 0.02
set TeamPosY[0] = 0.5
set TeamPosGapY[0] = 0.015
set TeamPosLeft2Right[0] = true
set TeamPosX[1] = 0.75
set TeamPosY[1] = 0.5
set TeamPosGapY[1] = 0.015
set TeamPosLeft2Right[1] = false
//player_Color is Copied from TriggerHappy
set OriginalHex[0] = "|cffff0303"
set OriginalHex[1] = "|cff0042ff"
set OriginalHex[2] = "|cff1ce6b9"
set OriginalHex[3] = "|cff540081"
set OriginalHex[4] = "|cfffffc01"
set OriginalHex[5] = "|cfffe8a0e"
set OriginalHex[6] = "|cff20c000"
set OriginalHex[7] = "|cffe55bb0"
set OriginalHex[8] = "|cff959697"
set OriginalHex[9] = "|cff7ebff1"
set OriginalHex[10] = "|cff106246"
set OriginalHex[11] = "|cff4e2a04"
if (bj_MAX_PLAYERS > 12) then
set OriginalHex[12] = "|cff9B0000"
set OriginalHex[13] = "|cff0000C3"
set OriginalHex[14] = "|cff00EAFF"
set OriginalHex[15] = "|cffBE00FE"
set OriginalHex[16] = "|cffEBCD87"
set OriginalHex[17] = "|cffF8A48B"
set OriginalHex[18] = "|cffBFFF80"
set OriginalHex[19] = "|cffDCB9EB"
set OriginalHex[20] = "|cff282828"
set OriginalHex[21] = "|cffEBF0FF"
set OriginalHex[22] = "|cff00781E"
set OriginalHex[23] = "|cffA46F33"
endif
endfunction
function TeamViewerDestroy takes nothing returns nothing
local player p
local integer playerIndex = 0
local integer buttonIndex
local integer categoryButtonIndex
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
call BlzDestroyFrame(playerFaceButton[playerIndex])
call BlzDestroyFrame(playerFaceName[playerIndex])
call BlzDestroyFrame(playerFaceIcon[playerIndex])
call BlzDestroyFrame(playerFaceIconDisabled[playerIndex])
call BlzDestroyFrame(playerFaceTooltip[playerIndex])
call BlzDestroyFrame(playerParentFrame[playerIndex])
set playerFaceButton[playerIndex] = null
set playerFaceName[playerIndex] = null
set playerFaceIcon[playerIndex] = null
set playerFaceIconDisabled[playerIndex] = null
set playerFaceTooltip[playerIndex] = null
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
call BlzDestroyFrame(playerCategoryButton[categoryButtonIndex])
call BlzDestroyFrame(playerCategoryIcon[categoryButtonIndex])
call BlzDestroyFrame(playerCategoryTooltip[categoryButtonIndex])
set playerCategoryButton[categoryButtonIndex] = null
set playerCategoryIcon[categoryButtonIndex] = null
set playerCategoryTooltip[categoryButtonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
endif
set playerIndex = playerIndex + 1
endloop
endfunction
private function PosFirstFrame takes framehandle movingFrame, framehandle relativFrame, boolean left2Right returns nothing
if left2Right then
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPLEFT, relativFrame, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
else
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPRIGHT, relativFrame, FRAMEPOINT_BOTTOMLEFT, 0, 0)
endif
endfunction
private function PosFrame takes framehandle movingFrame, framehandle relativFrame, boolean left2Right returns nothing
if left2Right then
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_LEFT, relativFrame, FRAMEPOINT_RIGHT, CategoryButtonGap, 0)
else
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_RIGHT, relativFrame, FRAMEPOINT_LEFT, -CategoryButtonGap, 0)
endif
endfunction
function TeamViewerInit takes nothing returns nothing
local player p
local integer playerIndex = 0
local integer teamNr
local boolean left2Right = false
local integer createContext
local integer buttonIndex
local integer categoryButtonIndex
call TeamViewerSetup()
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
set teamNr = GetPlayerTeam(p)
set createContext = 1000 + playerIndex
set playerParentFrame[playerIndex] = BlzCreateFrameByType("FRAME", "TeamViewerPlayerFrame", HeroSelectorBox, "", createContext)
set playerFaceButton[playerIndex] = BlzCreateFrame("HeroSelectorButton", playerParentFrame[playerIndex], 0, createContext)
set playerFaceName[playerIndex] = BlzCreateFrame("HeroSelectorTitle", playerParentFrame[playerIndex], 0, createContext) // do not the buttons child, else it is affected by Alpha change
set playerFaceIcon[playerIndex] = BlzGetFrameByName("HeroSelectorButtonIcon", createContext)
set playerFaceIconDisabled[playerIndex] = BlzGetFrameByName("HeroSelectorButtonIconDisabled", createContext)
set playerFaceTooltip[playerIndex] = BlzCreateFrame("HeroSelectorText", playerFaceButton[playerIndex], 0, createContext)
if ShowNonAllies then
set left2Right = TeamPosLeft2Right[teamNr]
else
set left2Right = TeamPosLeft2Right[0]
endif
call BlzFrameSetSize(playerFaceButton[playerIndex], ButtonSize, ButtonSize)
if LastTeamFaceButton[teamNr] == null then
if ShowNonAllies then
call BlzFrameSetAbsPoint(playerFaceButton[playerIndex], FRAMEPOINT_BOTTOMLEFT, TeamPosX[teamNr], TeamPosY[teamNr])
else
call BlzFrameSetAbsPoint(playerFaceButton[playerIndex], FRAMEPOINT_BOTTOMLEFT, TeamPosX[0], TeamPosY[0])
endif
else
call BlzFrameSetPoint(playerFaceButton[playerIndex], FRAMEPOINT_TOPLEFT, LastTeamFaceButton[teamNr], FRAMEPOINT_BOTTOMLEFT, 0, -TeamPosGapY[teamNr])
endif
set LastTeamFaceButton[teamNr] = playerFaceButton[playerIndex]
call PosFrame(playerFaceName[playerIndex], playerFaceButton[playerIndex], left2Right)
if left2Right then
call BlzFrameSetPoint(playerFaceTooltip[playerIndex], FRAMEPOINT_BOTTOMLEFT, playerFaceButton[playerIndex], FRAMEPOINT_TOPLEFT, 0, 0)
else
call BlzFrameSetPoint(playerFaceTooltip[playerIndex], FRAMEPOINT_BOTTOMRIGHT, playerFaceButton[playerIndex], FRAMEPOINT_TOPRIGHT, 0, 0)
endif
call BlzFrameSetText(playerFaceName[playerIndex], OriginalHex[GetPlayerId(p)] + GetPlayerName(p))
call BlzFrameSetTooltip(playerFaceButton[playerIndex], playerFaceTooltip[playerIndex])
call BlzFrameSetTexture(playerFaceIcon[playerIndex], ButtonDefaultIcon, 0, true)
//print("Pre HeroSelector.Category")
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
//print("playerIndex",key)
set playerCategoryButton[categoryButtonIndex] = BlzCreateFrameByType("BUTTON", "", playerParentFrame[playerIndex], "", 0)
set playerCategoryIcon[categoryButtonIndex] = BlzCreateFrameByType("BACKDROP", "", playerCategoryButton[categoryButtonIndex], "", 0)
set playerCategoryTooltip[categoryButtonIndex] = BlzCreateFrame("HeroSelectorText", playerCategoryButton[categoryButtonIndex], 0, categoryButtonIndex)
call BlzFrameSetText(playerCategoryTooltip[categoryButtonIndex], BlzFrameGetText(HeroSelector_CategoryTooltipFrame[buttonIndex]))
call BlzFrameSetTooltip( playerCategoryButton[categoryButtonIndex], playerCategoryTooltip[categoryButtonIndex])
call BlzFrameSetAllPoints(playerCategoryIcon[categoryButtonIndex], playerCategoryButton[categoryButtonIndex])
call BlzFrameSetPoint(playerCategoryTooltip[categoryButtonIndex], FRAMEPOINT_BOTTOM, playerCategoryButton[categoryButtonIndex], FRAMEPOINT_TOP, 0, 0)
call BlzFrameSetSize( playerCategoryButton[categoryButtonIndex], 0.015, 0.015)
call BlzFrameSetTexture(playerCategoryIcon[categoryButtonIndex], HeroSelector_CategoryTexture[buttonIndex], 0, true)
call BlzFrameSetVisible( playerCategoryButton[categoryButtonIndex], false)
set buttonIndex = buttonIndex + 1
endloop
//When showning only allies, hide non allies
if not ShowNonAllies and not IsPlayerAlly(p, GetLocalPlayer()) then
call BlzFrameSetVisible(playerParentFrame[playerIndex], false)
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function TeamViewerButtonSelected takes player p, integer unitCode returns nothing
local integer playerIndex = GetPlayerId(p)
local integer teamNr = GetPlayerTeam(p)
local framehandle prevCategoryButton = null
local integer category = 1
local boolean left2Right = false
local integer unitCodeIndex = LoadInteger(HeroSelector_Hash, unitCode, 0)
local integer unitCategory = HeroSelector_HeroCategory[unitCodeIndex]
local integer categoryButtonIndex
local integer buttonIndex = 1
if not HasPicked[playerIndex] then
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetText(playerFaceTooltip[playerIndex], GetObjectName(unitCode))
call BlzFrameSetTexture(playerFaceIcon[playerIndex], BlzGetAbilityIcon(unitCode), 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], ButtonAlphaSelected)
if ShowNonAllies then
set left2Right = TeamPosLeft2Right[teamNr]
else
set left2Right = TeamPosLeft2Right[0]
endif
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
call BlzFrameClearAllPoints(playerCategoryButton[categoryButtonIndex])
if BlzBitAnd(category, unitCategory) > 0 then
call BlzFrameSetVisible(playerCategoryButton[categoryButtonIndex], true)
if prevCategoryButton == null then
call PosFirstFrame(playerCategoryButton[categoryButtonIndex], playerFaceButton[playerIndex], left2Right)
else
call PosFrame(playerCategoryButton[categoryButtonIndex], prevCategoryButton, left2Right)
endif
set prevCategoryButton = playerCategoryButton[categoryButtonIndex]
else
call BlzFrameSetVisible(playerCategoryButton[categoryButtonIndex], false)
endif
set category = category + category
set buttonIndex = buttonIndex + 1
endloop
endif
endif
set prevCategoryButton = null
endfunction
function TeamViewerUnitCreated takes player p, unit u, boolean isRandom returns nothing
local integer playerIndex = GetPlayerId(p)
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetTexture(playerFaceIcon[playerIndex], BlzGetAbilityIcon(GetUnitTypeId(u)), 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], 255)
endif
set HasPicked[playerIndex] = true
endfunction
function TeamViewerRepick takes unit u, player p returns nothing
local integer playerIndex = GetPlayerId(p)
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetTexture(playerFaceIcon[playerIndex], ButtonDefaultIcon, 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], 255)
endif
set HasPicked[playerIndex] = false
endfunction
endlibrary
library HeroInfo
// 11
//Plugin for by Tasyen
//This Creates a TextDisplay which displays the name and the Extended tooltip of selected units
globals
private framehandle TextDisplay
private string DescHeroNamePrefix = "|cffffcc00" //added before the Units Name
private string DescHeroNameSufix = "|r" //added after the units Name
private real TextAreaSizeX = 0.2
private real TextAreaSizeY = 0.2
private real TextAreaOffsetX = 0.0
private real TextAreaOffsetY = 0.0
private framepointtype TextAreaPoint = FRAMEPOINT_TOPLEFT //pos the Tooltip with which Point
private framepointtype TextAreaRelativePoint = FRAMEPOINT_TOPRIGHT //pos the Tooltip to which Point of the Relative
private boolean TextAreaRelativeGame = false //(false) relativ to box, (true) relativ to GameUI
endglobals
function HeroInfoDestroy takes nothing returns nothing
call BlzDestroyFrame(TextDisplay)
set TextDisplay = null
endfunction
function HeroInfoInit takes nothing returns nothing
set TextDisplay = BlzCreateFrame("HeroSelectorTextArea", HeroSelectorBox, 0, 0)
call BlzFrameSetSize(TextDisplay , TextAreaSizeX, TextAreaSizeY)
if not TextAreaRelativeGame then
call BlzFrameSetPoint(TextDisplay, TextAreaPoint, HeroSelectorBox, TextAreaRelativePoint, TextAreaOffsetX, TextAreaOffsetY)
else
call BlzFrameSetPoint(TextDisplay, TextAreaPoint, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), TextAreaRelativePoint, TextAreaOffsetX, TextAreaOffsetY)
endif
endfunction
function HeroInfoButtonSelected takes player p, integer unitCode returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetText(TextDisplay, DescHeroNamePrefix + GetObjectName(unitCode) + DescHeroNameSufix)
call BlzFrameAddText(TextDisplay, BlzGetAbilityExtendedTooltip(unitCode,0))
endif
endfunction
endlibrary
library HeroSelector
//HeroSelector V1.3.0
//API
//=====
//HeroSelectorForcePick()
//HeroSelectorForcePickPlayer(player p)
//HeroSelectorForcePickRace(race r)
//HeroSelectorForcePickTeam(integer teamNr)
//HeroSelectorForceRandom()
//HeroSelectorForceRandomRace(race r)
//HeroSelectorForceRandomTeam(integer teamNr)
//HeroSelectorDoPick(player p)
//HeroSelectorDoRandom(player p)
//HeroSelectorShow(boolean flag)
//HeroSelectorShowForce(boolean flag, force f)
//HeroSelectorShowRace(boolean flag, race r)
//HeroSelectorShowPlayer(boolean flag, player p)
//HeroSelectorShowTeam(boolean flag, integer teamNr)
//HeroSelectorEnableBan(boolean flag)
//HeroSelectorEnableBanRace
//HeroSelectorEnableBanTeam
//HeroSelectorEnableBanPlayer
//HeroSelectorEnableBanForce
//HeroSelectorEnablePick(boolean flag)
//HeroSelectorEnablePickForce
//HeroSelectorEnablePickPlayer
//HeroSelectorEnablePickTeam
//HeroSelectorEnablePickRace
//HeroSelectorRollOption(player p, boolean includeRandomOnly, integer exculdedIndex, integer category) returns integer
//HeroSelectorCounterChangeUnitCode(integer unitCode, integer add, player p)
//HeroSelectorEnableButtonIndex(integer unitCode, integer buttonIndex)
//HeroSelectorDisableButtonIndex(integer buttonIndex, integer teamNr)
//HeroSelectorButtonRequirementDone(integer unitCode, player p) returns boolean
//HeroSelectorDeselectButton(integer buttonIndex)
//HeroSelectorAddUnit(integer unitCode, boolean onlyRandom)
//HeroSelectorAddUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitReqPlayer(integer unitCode, player p)
//HeroSelectorSetUnitReqRace(integer unitCode, race r)
//HeroSelectorSetUnitReqForce(integer unitCode, force f)
//HeroSelectorSetUnitReqTeam(integer unitCode, integer teamNr)
//HeroSelectorSetFrameText(framehandle frame, string text)
//HeroSelectorSetFrameTextPlayer
//HeroSelectorSetFrameTextForce
//HeroSelectorSetFrameTextTeam
//HeroSelectorSetFrameTextRace
//HeroSelectorSetTitleText(string text)
//HeroSelectorSetTitleTextRace
//HeroSelectorSetTitleTextPlayer
//HeroSelectorSetTitleTextForce
//HeroSelectorSetTitleTextTeam
//HeroSelectorSetBanButtonText
//HeroSelectorSetBanButtonTextPlayer
//HeroSelectorSetBanButtonTextRace
//HeroSelectorSetBanButtonTextForce
//HeroSelectorSetBanButtonTextTeam
//HeroSelectorSetRandomButtonText
//HeroSelectorSetRandomButtonTextPlayer
//HeroSelectorSetRandomButtonTextForce
//HeroSelectorSetRandomButtonTextTeam
//HeroSelectorSetRandomButtonTextRace
//HeroSelectorSetAcceptButtonText
//HeroSelectorSetAcceptButtonTextPlayer
//HeroSelectorSetAcceptButtonTextForce
//HeroSelectorSetAcceptButtonTextTeam
//HeroSelectorSetAcceptButtonTextRace
//HeroSelectorAddCategory(string icon, string text) //should only be used before the category Buttons are created
//HeroSelectorGetDisabledIcon(string iconPath)
//HeroSelectorUpdate()
//=====
globals
//Setup
//Box
private string BoxFrameName = "EscMenuBackdrop" //this is the background box being created
private real BoxPosX = 0.3
private real BoxPosY = 0.4
private framepointtype BoxPosPoint = FRAMEPOINT_CENTER
private boolean AutoShow = true //(true) shows the box and the Selection at 0.0 for all players
//Unique Picks
private integer UnitCount = 1 //each hero is in total allowed to be picked this amount of times (includes random, repicking allows a hero again).
private integer UnitCountPerTeam = 1 //Each Team is allowed to pick this amount of each unitType
//Ban
private boolean DelayBanUntilPick = false //(true) baning will not be applied instantly, instead it is applied when HeroSelectorEnablePick is called the next time.
//Category
private boolean CategoryAffectRandom = true //(false) random will not care about selected category
private boolean CategoryMultiSelect = false //(false) deselect other category when selecting one, (true) can selected multiple categories and all heroes having any of them are not filtered.
private real CategorySize = 0.02 //the size of the Category Button
private real CategorySpaceX = 0.0008 //space between 2 category Buttons, it is meant to need only one line of Categoryy Buttons.
private integer CategoryFilteredAlpha = 45 // Alpha value of Heroes being filtered by unselected categories
private boolean CategoryAutoDetectHero = true // Will create and remove added Heroes to read and setup the Category for the primary Attribute Str(4) Agi(8) Int(16)
//Icon path, tooltip Text (tries to localize)
//Indicator
private framehandle IndicatorSelected
private string IndicatorPathPick = "UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdl" //this model is used by the indicator during picking
private string IndicatorPathBan = "war3mapImported\\HeroSelectorBan.mdl" //this model is used by the indicator during baning
//Grid
private real SpaceBetweenX = 0.008 //space between 2 buttons in one row
private real SpaceBetweenY = 0.008 //space between 2 rows
private integer ButtonColCount = 6 //amount of buttons in one row
private integer ButtonRowCount = 5 //amount of rows
private boolean ChainedButtons = true //(true) connect to the previous button/ or row, (false) have a offset to the box topLeft in this moving a button has no effect on other buttons.
//Button
private real ButtonSize = 0.036 //size of each button
private boolean ButtonBlendAll = false //(true) when a hero icon uses transparenzy
private string EmptyButtonPath = "UI\\Widgets\\EscMenu\\Human\\blank-background.blp"
//Ban Button
private string BanButtonTextPrefix = "|cffcf2084" //Prefix Text for the Ban Button
private string BanButtonText = "CHAT_ACTION_BAN" //tries to get a Localized String
private real BanButtonSizeX = 0.13
private real BanButtonSizeY = 0.03
//Accept Button
private string AcceptButtonTextPrefix = ""
private string AcceptButtonText = "ACCEPT"
private real AcceptButtonSizeX = 0.085
private real AcceptButtonSizeY = 0.03
private boolean AcceptButtonIsShown = true
private framepointtype AcceptButtonAnchor = FRAMEPOINT_BOTTOMRIGHT //places the Accept button with which Point to the bottom, with right he is at the left
//Random Button
private string RandomButtonTextPrefix = ""
private string RandomButtonText = "RANDOM" //tries Localizing
private real RandomButtonSizeX = 0.085
private real RandomButtonSizeY = 0.03
private boolean RandomButtonIsShown = true
private framepointtype RandomButtonAnchor = FRAMEPOINT_BOTTOMLEFT
private boolean RandomButtonPick = false //(true) pressing the random button will pick the option. (false) pressing the random button will select a button, random only heroes can not be selected, but that does not matter. This weak random and randomonly should not be combined.
//Tooltip
private string TooltipPrefix = "|cffffcc00"
private real TooltipOffsetX = 0
private real TooltipOffsetY = 0
private framepointtype TooltipPoint = FRAMEPOINT_BOTTOM //pos the Tooltip with which Point
private framepointtype TooltipRelativePoint = FRAMEPOINT_TOP //pos the Tooltip to which Point of the Relative
private boolean TooltipRelativIsBox = false //(true) use the box as anchor, (false) use the button as anchor
//System variables, Do not touch
public integer HeroButtonCount = ButtonRowCount*ButtonColCount
private trigger CategoryClickTrigger = CreateTrigger()
private trigger AcceptButtonTrigger = CreateTrigger()
private trigger BanButtonTrigger = CreateTrigger()
private trigger RandomButtonTrigger = CreateTrigger()
private framehandle BanButton
private framehandle AcceptButton
private framehandle RandomButton
private player array DelayBanPlayer
private integer array DelayBanUnitCode
private integer DelayBanCount = 0
public framehandle array CategoryButton
public framehandle array CategoryIconFrame
public framehandle array CategoryTooltipFrame
public string array CategoryText
public string array CategoryTexture
public string array CategoryTextureDisabled
private integer array CategoryButtonValue
public integer CategoryButtonCount = 0
private integer array UsedTeamNr
private integer UsedTeamNrCount = 0
private integer ButtonHeroCount = 0
private integer array ButtonHeroUnitCode
private integer array HeroTotalCount
public integer array HeroCategory
private integer array HeroRegType
private player array HeroRegPlayer
private force array HeroRegForce
private integer array HeroRegTeam
private race array HeroRegRace
private integer HeroCount = 0
private integer array HeroUnitCode
private integer array HeroButtonIndex
public hashtable Hash = InitHashtable()
framehandle HeroSelectorBox
private framehandle HeroSelectorBoxTitle
private integer array HeroButtonUnitCode
private integer HeroButtonUnitCodeCount = 0
private framehandle array HeroButtonIcon
private framehandle array HeroButtonIconDisabled
private framehandle array HeroButtonTooltip
private framehandle array HeroButtonFrame
private trigger HeroButtonClickTrigger = CreateTrigger()
private integer array PlayerSelectedButtonIndex
private integer array PlayerSelectedCategory
private integer array PlayerLastSelectedCategoryIndex
endglobals
private function AutoDetectCategory takes integer unitCode returns integer
local integer value = 0
local unit u
local integer primaryAttribute
if IsUnitIdType(unitCode, UNIT_TYPE_MELEE_ATTACKER) then
set value = 1
elseif IsUnitIdType(unitCode, UNIT_TYPE_RANGED_ATTACKER) then
set value = 2
endif
if CategoryAutoDetectHero and IsUnitIdType(unitCode, UNIT_TYPE_HERO) then
set u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), unitCode, 0, 0, 270)
set primaryAttribute = BlzGetUnitIntegerField(u, UNIT_IF_PRIMARY_ATTRIBUTE)
call RemoveUnit(u)
set u = null
if ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_STR then
set value = value + 4
elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_AGI then
set value = value + 8
elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_INT then
set value = value + 16
endif
endif
return value
endfunction
private function GetBorderSize takes nothing returns real
if GetPlayerRace(GetLocalPlayer()) == RACE_HUMAN then
return 0.025
elseif GetPlayerRace(GetLocalPlayer()) == RACE_ORC then
return 0.029
elseif GetPlayerRace(GetLocalPlayer()) == RACE_UNDEAD then
return 0.035
elseif GetPlayerRace(GetLocalPlayer()) == RACE_NIGHTELF then
return 0.035
elseif GetPlayerRace(GetLocalPlayer()) == RACE_DEMON then
return 0.024
else
return 0.0
endif
endfunction
function HeroSelectorDestroy takes nothing returns nothing
local integer buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
call BlzDestroyFrame(HeroButtonIcon[buttonIndex])
call BlzDestroyFrame(HeroButtonIconDisabled[buttonIndex])
call BlzDestroyFrame(HeroButtonFrame[buttonIndex])
call BlzDestroyFrame(HeroButtonTooltip[buttonIndex])
set HeroButtonTooltip[buttonIndex] = null
set HeroButtonFrame[buttonIndex] = null
set HeroButtonIcon[buttonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
set buttonIndex = 1
loop
exitwhen buttonIndex > CategoryButtonCount
call BlzDestroyFrame(CategoryButton[buttonIndex])
call BlzDestroyFrame(CategoryIconFrame[buttonIndex])
call BlzDestroyFrame(CategoryTooltipFrame[buttonIndex])
set CategoryButton[buttonIndex] = null
set CategoryIconFrame[buttonIndex] = null
set CategoryTooltipFrame[buttonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
call BlzDestroyFrame(HeroSelectorBox)
call BlzDestroyFrame(HeroSelectorBoxTitle)
call BlzDestroyFrame(BanButton)
call BlzDestroyFrame(RandomButton)
call BlzDestroyFrame(AcceptButton)
call BlzDestroyFrame(IndicatorSelected)
set HeroSelectorBox = null
set HeroSelectorBoxTitle = null
set BanButton = null
set RandomButton = null
set AcceptButton = null
set IndicatorSelected = null
call DestroyTrigger(CategoryClickTrigger)
call DestroyTrigger(BanButtonTrigger)
call DestroyTrigger(RandomButtonTrigger)
call DestroyTrigger(HeroButtonClickTrigger)
set CategoryClickTrigger = null
set BanButtonTrigger = null
set RandomButtonTrigger = null
set HeroButtonClickTrigger = null
endfunction
//=====
//code start
//=====
function HeroSelectorGetDisabledIcon takes string icon returns string
//ReplaceableTextures\CommandButtons\BTNHeroPaladin.tga -> ReplaceableTextures\CommandButtonsDisabled\DISBTNHeroPaladin.tga
if SubString(icon, 34, 35) != "\\" then
return icon
endif //this string has not enough chars return it
//string.len(icon) < 34 then return icon end //this string has not enough chars return it
return SubString(icon, 0, 34) + "Disabled\\DIS" + SubString(icon, 35, StringLength(icon))
endfunction
function HeroSelectorAddCategory takes string icon, string text returns nothing
//adds an data category construct
set CategoryButtonCount = CategoryButtonCount + 1
set CategoryText[CategoryButtonCount] = text
set CategoryTexture[CategoryButtonCount] = icon
set CategoryTextureDisabled[CategoryButtonCount] = HeroSelectorGetDisabledIcon(icon)
if CategoryButtonCount > 1 then
set CategoryButtonValue[CategoryButtonCount] = CategoryButtonValue[CategoryButtonCount - 1]*2
else
set CategoryButtonValue[CategoryButtonCount] = 1
endif
endfunction
function HeroSelectorSetFrameText takes framehandle frame, string text returns nothing
call BlzFrameSetText(frame, text)
endfunction
function HeroSelectorSetFrameTextPlayer takes framehandle frame, string text, player p returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextTeam takes framehandle frame, string text, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextRace takes framehandle frame, string text, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextForce takes framehandle frame, string text, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetTitleText takes string text returns nothing
call HeroSelectorSetFrameText(HeroSelectorBoxTitle, text)
endfunction
function HeroSelectorSetTitleTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetBanButtonText takes string text returns nothing
call HeroSelectorSetFrameText(BanButton, text)
endfunction
function HeroSelectorSetBanButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(BanButton, text, who)
endfunction
function HeroSelectorSetRandomButtonText takes string text returns nothing
call HeroSelectorSetFrameText(RandomButton, text)
endfunction
function HeroSelectorSetRandomButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(RandomButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonText takes string text returns nothing
call HeroSelectorSetFrameText(AcceptButton, text)
endfunction
function HeroSelectorSetAcceptButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(AcceptButton, text, who)
endfunction
function HeroSelectorSetUnitCategory takes integer unitCode, integer category returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroCategory[index] = category
endfunction
function HeroSelectorAddUnitCategory takes integer unitCode, integer category returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroCategory[index] = BlzBitOr(category, HeroCategory[index])
endfunction
function HeroSelectorDeselectButton takes integer buttonIndex returns nothing
local integer playerIndex = 0
if buttonIndex > 0 then
if PlayerSelectedButtonIndex[GetPlayerId(GetLocalPlayer())] == buttonIndex then
call BlzFrameSetVisible(IndicatorSelected, false)
endif
loop
exitwhen playerIndex == GetBJMaxPlayers()
if PlayerSelectedButtonIndex[playerIndex] == buttonIndex then
set PlayerSelectedButtonIndex[playerIndex] = 0
endif
set playerIndex = playerIndex + 1
endloop
else
loop
exitwhen playerIndex == GetBJMaxPlayers()
set PlayerSelectedButtonIndex[playerIndex] = 0
set playerIndex = playerIndex + 1
endloop
call BlzFrameSetVisible(IndicatorSelected, false)
endif
endfunction
function HeroSelectorSetUnitReqRace takes integer unitCode, race r returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 1
set HeroRegRace[index] = r
endfunction
function HeroSelectorSetUnitReqForce takes integer unitCode, force f returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 4
set HeroRegForce[index] = f
endfunction
function HeroSelectorSetUnitReqPlayer takes integer unitCode, player p returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 3
set HeroRegPlayer[index] = p
endfunction
function HeroSelectorSetUnitReqTeam takes integer unitCode, integer teamNr returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 2
set HeroRegTeam[index] = teamNr
endfunction
function HeroSelectorButtonRequirementDone takes integer unitCode, player p returns boolean
//true when no requirement is set or the requirment call is successful
local integer index = LoadInteger(Hash, unitCode, 0)
if HeroRegType[index] == 0 then //no requirement
return true
elseif HeroRegType[index] == 1 and HeroRegRace[index] == GetPlayerRace(p) then
return true
elseif HeroRegType[index] == 2 and HeroRegTeam[index] == GetPlayerTeam(p) then
return true
elseif HeroRegType[index] == 3 and HeroRegPlayer[index] == p then
return true
elseif HeroRegType[index] == 4 and BlzForceHasPlayer(HeroRegForce[index], p) then
return true
endif
return false
endfunction
function HeroSelectorDisableButtonIndex takes integer buttonIndex, integer teamNr returns nothing
local integer playerIndex = 0
if buttonIndex > 0 then
if teamNr == -1 or teamNr == GetPlayerTeam(GetLocalPlayer()) then
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
endif
if PlayerSelectedButtonIndex[GetPlayerId(GetLocalPlayer())] == buttonIndex then
call BlzFrameSetVisible(IndicatorSelected, false)
endif
//deselect this Button from all players or the team
loop
exitwhen playerIndex == GetBJMaxPlayers()
if (teamNr == -1 or teamNr == GetPlayerTeam(Player(playerIndex))) and PlayerSelectedButtonIndex[playerIndex] == buttonIndex then
set PlayerSelectedButtonIndex[playerIndex] = 0
endif
set playerIndex = playerIndex + 1
endloop
endif
endfunction
function HeroSelectorEnableButtonIndex takes integer unitCode, integer buttonIndex returns nothing
if buttonIndex > 0 then
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], true and HeroSelectorButtonRequirementDone(unitCode, GetLocalPlayer()))
endif
endfunction
function HeroSelectorCounterChangeUnitCode takes integer unitCode, integer add, player p returns nothing
local integer unitCodeIndex = LoadInteger(Hash, unitCode, 0)
local integer buttonIndex = HeroButtonIndex[unitCodeIndex]
local integer teamNr = GetPlayerTeam(p)
local integer teamKey = StringHash("TeamCount"+I2S(teamNr))
set HeroTotalCount[unitCodeIndex] = HeroTotalCount[unitCodeIndex] + add
call SaveInteger(Hash, unitCode, teamKey, LoadInteger(Hash, unitCode, teamKey) + add)
if HeroTotalCount[unitCodeIndex] >= UnitCount then
//disable for all
call HeroSelectorDisableButtonIndex(buttonIndex, -1)
else
//enable for all
call HeroSelectorEnableButtonIndex(unitCode, buttonIndex)
if LoadInteger(Hash, unitCode, teamKey) >= UnitCountPerTeam then
//disable for this team
call HeroSelectorDisableButtonIndex(buttonIndex, teamNr)
endif
endif
endfunction
function HeroSelectorRollOption takes player p, boolean includeRandomOnly, integer exculdedIndex, integer category returns integer
local integer teamNr = GetPlayerTeam(p)
local integer array options
local integer optionCount = 0
local integer teamKey = StringHash("TeamCount"+I2S(teamNr))
local boolean allowed
local integer index = 1
local integer unitCode
local integer unitCodeIndex
loop
exitwhen index > HeroCount
set unitCode = HeroUnitCode[index]
set unitCodeIndex = LoadInteger(Hash, unitCode, 0)
set allowed = true
//total limited reached?
if HeroTotalCount[unitCodeIndex] >= UnitCount then
set allowed = false
//print(GetObjectName(unitCode))
//print("rejected total limit")
endif
//team limited reached?
if allowed and LoadInteger(Hash, unitCode, teamKey) >= UnitCountPerTeam then
//print(GetObjectName(unitCode))
//print("rejected team limit")
set allowed = false
endif
//allow randomOnly?
if allowed and not includeRandomOnly and HeroButtonIndex[unitCodeIndex] == 0 then
//print(GetObjectName(unitCode))
//print("rejected random only")
set allowed = false
endif
//this index is excluded? This can make sure you get another button.
if allowed and HeroButtonIndex[unitCodeIndex] > 0 and HeroButtonIndex[unitCodeIndex] == exculdedIndex then
//print(GetObjectName(unitCode))
//print("rejected exclude")
set allowed = false
endif
//fullfills the requirement?
if allowed and not HeroSelectorButtonRequirementDone(unitCode, p) then
//print(GetObjectName(unitCode))
//print("rejected requirement")
set allowed = false
endif
//when having an given an category only allow options having that category atleast partly
if allowed and category > 0 and BlzBitAnd(category, HeroCategory[unitCodeIndex]) == 0 then
//print(GetObjectName(unitCode))
//print(" rejected category", category, HeroSelector.UnitData[unitCode].Category)
set allowed = false
endif
if allowed then
set optionCount = optionCount + 1
set options[optionCount] = unitCode
endif
set index = index + 1
endloop
//nothing is allwoed?
if optionCount == 0 then
return 0
else
return options[GetRandomInt(1, optionCount)]
endif
endfunction
function HeroSelectorEnablePickDelayBanAction takes nothing returns nothing
loop
exitwhen DelayBanCount <= 0
call HeroSelectorCounterChangeUnitCode(DelayBanUnitCode[DelayBanCount], UnitCount + 1, DelayBanPlayer[DelayBanCount])
set DelayBanCount = DelayBanCount - 1
endloop
endfunction
function HeroSelectorEnablePickAction takes boolean flag returns nothing
call BlzFrameSetVisible(AcceptButton, true and AcceptButtonIsShown)
call BlzFrameSetVisible(RandomButton, true and RandomButtonIsShown)
call BlzFrameSetVisible(BanButton, false)
call BlzFrameSetEnable(AcceptButton, flag)
call BlzFrameSetEnable(RandomButton, flag)
call BlzFrameSetModel(IndicatorSelected, IndicatorPathPick, 0)
endfunction
function HeroSelectorEnablePick takes boolean flag returns nothing
call HeroSelectorEnablePickDelayBanAction()
call HeroSelectorEnablePickAction(flag)
endfunction
function HeroSelectorEnablePickPlayer takes boolean flag, player p returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetLocalPlayer() == p then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickTeam takes boolean flag, integer teamNr returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickRace takes boolean flag, race r returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetPlayerRace(GetLocalPlayer()) == r then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickForce takes boolean flag, force f returns nothing
call HeroSelectorEnablePickDelayBanAction()
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnableBanPlayerAction takes boolean flag returns nothing
call BlzFrameSetVisible(AcceptButton, false)
call BlzFrameSetVisible(RandomButton, false)
call BlzFrameSetVisible(BanButton, true)
call BlzFrameSetEnable(BanButton, flag)
call BlzFrameSetModel(IndicatorSelected, IndicatorPathBan, 0)
endfunction
function HeroSelectorEnableBanPlayer takes boolean flag, player p returns nothing
if GetLocalPlayer() == p then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanForce takes boolean flag, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanTeam takes boolean flag, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanRace takes boolean flag, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBan takes boolean flag returns nothing
call HeroSelectorEnableBanPlayerAction(flag)
endfunction
function HeroSelectorframeLoseFocus takes framehandle frame returns nothing
if BlzFrameGetEnable(frame) then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
endif
endfunction
function HeroSelectorUpdate takes nothing returns nothing
local integer buttonIndex = 1
local integer unitCodeIndex
local integer teamNr
local integer teamIndex = 1
local integer teamKey
loop
exitwhen buttonIndex > HeroButtonCount
//have data for this button?
if HeroButtonUnitCode[buttonIndex] > 0 then
set unitCodeIndex = LoadInteger(Hash, HeroButtonUnitCode[buttonIndex],0)
if HeroTotalCount[unitCodeIndex] >= UnitCount then
//disable for all
call HeroSelectorDisableButtonIndex(buttonIndex, -1)
else
//enable for all
call HeroSelectorEnableButtonIndex(HeroButtonUnitCode[buttonIndex], buttonIndex)
loop
exitwhen teamIndex > UsedTeamNrCount
set teamNr = UsedTeamNr[teamIndex]
set teamKey = StringHash("TeamCount"+I2S(teamNr))
if LoadInteger(Hash, HeroButtonUnitCode[buttonIndex], teamKey) >= UnitCountPerTeam then
//disable for this team
call HeroSelectorDisableButtonIndex(buttonIndex, teamNr)
endif
set teamIndex = teamIndex + 1
endloop
endif
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex]), 0, ButtonBlendAll)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], HeroSelectorGetDisabledIcon(BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex])), 0, ButtonBlendAll)
call BlzFrameSetText(HeroButtonTooltip[buttonIndex], TooltipPrefix + GetObjectName(HeroButtonUnitCode[buttonIndex]))
else
//no, make it unclickable and empty
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], EmptyButtonPath, 0, true)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], EmptyButtonPath, 0, true)
endif
set buttonIndex = buttonIndex + 1
endloop
endfunction
function HeroSelectorShowFramePlayer takes framehandle frame, boolean flag, player p returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameForce takes framehandle frame, boolean flag, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameTeam takes framehandle frame, boolean flag, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameRace takes framehandle frame, boolean flag, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowPlayer takes boolean flag, player who returns nothing
call HeroSelectorShowFramePlayer(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowTeam takes boolean flag, integer who returns nothing
call HeroSelectorShowFrameTeam(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowRace takes boolean flag, race who returns nothing
call HeroSelectorShowFrameRace(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowForce takes boolean flag, force who returns nothing
call HeroSelectorShowFrameForce(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShow takes boolean flag returns nothing
call BlzFrameSetVisible(HeroSelectorBox, flag)
endfunction
function HeroSelectorAddUnit takes integer unitCode, boolean onlyRandom returns nothing
//no unitCode => empty field
if unitCode == 0 then
set ButtonHeroCount = ButtonHeroCount + 1
else
//Such an object Exist? not unique?
if GetObjectName(unitCode) == "" or HaveSavedBoolean(Hash, unitCode, 0) then
return
endif
set HeroCount = HeroCount + 1
set HeroUnitCode[HeroCount] = unitCode
call SaveBoolean(Hash, unitCode, 0, true)
call SaveInteger(Hash, unitCode, 0, HeroCount)
set HeroCategory[HeroCount] = AutoDetectCategory(unitCode)
if not onlyRandom then
set ButtonHeroCount = ButtonHeroCount + 1
set HeroButtonIndex[HeroCount] = ButtonHeroCount
set ButtonHeroUnitCode[ButtonHeroCount] = unitCode
endif
endif
endfunction
function HeroSelectorDoRandom takes player p returns nothing
local integer category = 0
local integer unitCode
local unit u
if CategoryAffectRandom then
set category = PlayerSelectedCategory[GetPlayerId(p)]
endif
set unitCode = HeroSelectorRollOption(p, true, 0, category)
if unitCode == 0 then
return
endif
set u = CreateUnit(p, unitCode, 0, 0, 0)
call HeroSelectorCounterChangeUnitCode(unitCode, 1, p)
set udg_HeroSelectorEventUnit = u
set udg_HeroSelectorEventIsRandom = true
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 1.0
set udg_HeroSelectorEvent = 0.0
set u = null
endfunction
function HeroSelectorDoPick takes player p returns boolean
local integer unitCode
local unit u
//pick what currently is selected, returns true on success returns false when something went wrong,
local integer buttonIndex = PlayerSelectedButtonIndex[GetPlayerId(p)]
if buttonIndex <= 0 then
return false
endif //reject nothing selected
set unitCode = HeroButtonUnitCode[buttonIndex]
set u = CreateUnit(p, unitCode, 0, 0, 0)
call HeroSelectorCounterChangeUnitCode(unitCode, 1, p)
set udg_HeroSelectorEventUnit = u
set udg_HeroSelectorEventIsRandom = false
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 1.0
set udg_HeroSelectorEvent = 0.0
set u = null
return true
endfunction
function HeroSelectorForceRandom takes nothing returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
call HeroSelectorDoRandom(p)
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForceRandomTeam takes integer who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerTeam(p) == who then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForceRandomRace takes race who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerRace(p) == who then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForcePick takes nothing returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickTeam takes integer who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerTeam(p) == who then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickRace takes race r returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerRace(p) == r then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickPlayer takes player p returns nothing
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endfunction
function HeroSelectorActionPressHeroButton takes nothing returns nothing
local framehandle fh = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local integer buttonIndex = LoadInteger(Hash, GetHandleId(fh), 0)
local integer unitCode = HeroButtonUnitCode[buttonIndex]
set PlayerSelectedButtonIndex[GetPlayerId(p)] = buttonIndex
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if GetLocalPlayer() == p then
call BlzFrameSetVisible(IndicatorSelected, true)
call BlzFrameSetPoint(IndicatorSelected, FRAMEPOINT_TOPLEFT, fh, FRAMEPOINT_TOPLEFT, -0.001, 0.001)
call BlzFrameSetPoint(IndicatorSelected, FRAMEPOINT_BOTTOMRIGHT, fh, FRAMEPOINT_BOTTOMRIGHT, -0.0012, -0.0016)
endif
set udg_HeroSelectorEventUnit = null
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 2.0
set udg_HeroSelectorEvent = 0.0
set fh = null
set p = null
endfunction
function HeroSelectorActionRandomButton takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer unitCode
local integer unitCodeIndex
local integer buttonIndex
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if RandomButtonPick then
call HeroSelectorDoRandom(p)
else
set unitCode = HeroSelectorRollOption(p, false, PlayerSelectedButtonIndex[playerIndex], PlayerSelectedCategory[playerIndex])
if unitCode > 0 and GetLocalPlayer() == p then
set unitCodeIndex = LoadInteger(Hash, unitCode, 0)
set buttonIndex = HeroButtonIndex[unitCodeIndex]
call BlzFrameClick(HeroButtonFrame[buttonIndex])
endif
endif
set p = null
endfunction
function HeroSelectorActionAcceptButton takes nothing returns nothing
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
call HeroSelectorDoPick(GetTriggerPlayer())
endfunction
function HeroSelectorActionBanButton takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer buttonIndex = PlayerSelectedButtonIndex[playerIndex]
local integer unitCode = HeroButtonUnitCode[buttonIndex]
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if buttonIndex > 0 then
if not DelayBanUntilPick then
call HeroSelectorCounterChangeUnitCode(unitCode, UnitCount + 1, p)
else
set DelayBanCount = DelayBanCount + 1
set DelayBanPlayer[DelayBanCount] = p
set DelayBanUnitCode[DelayBanCount] = unitCode
endif
set udg_HeroSelectorEventUnit = null
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 3.0
set udg_HeroSelectorEvent = 0.0
endif
set p = null
endfunction
function HeroSelectorActionCategoryButton takes nothing returns nothing
local integer buttonIndex
local framehandle fh = BlzGetTriggerFrame()
local integer categoryIndex = LoadInteger(Hash, GetHandleId(fh), 0)
local integer lastCategoryIndex
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer unitCodeIndex
call HeroSelectorframeLoseFocus(fh)
//has this category already?
if BlzBitAnd(PlayerSelectedCategory[playerIndex], CategoryButtonValue[categoryIndex]) != 0 then
//yes, unable
set PlayerSelectedCategory[playerIndex] = PlayerSelectedCategory[playerIndex] - CategoryButtonValue[categoryIndex]
if GetLocalPlayer() == p then
call BlzFrameSetTexture(CategoryIconFrame[categoryIndex], CategoryTextureDisabled[categoryIndex], 0, true)
endif
else
if not CategoryMultiSelect and PlayerSelectedCategory[playerIndex] != 0 then
set lastCategoryIndex = PlayerLastSelectedCategoryIndex[playerIndex]
call BlzFrameSetTexture(CategoryIconFrame[lastCategoryIndex], CategoryTextureDisabled[lastCategoryIndex], 0, true)
set PlayerSelectedCategory[playerIndex] = 0
endif
//no, enable
set PlayerSelectedCategory[playerIndex] = PlayerSelectedCategory[playerIndex] + CategoryButtonValue[categoryIndex]
if GetLocalPlayer() == p then
call BlzFrameSetTexture(CategoryIconFrame[categoryIndex], CategoryTexture[categoryIndex], 0, true)
endif
set PlayerLastSelectedCategoryIndex[playerIndex] = categoryIndex
endif
if GetLocalPlayer() == p then
//update all buttons
//buttons not having at least 1 selected category becomes partly transparent
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
if HeroButtonUnitCode[buttonIndex] > 0 then
set unitCodeIndex = LoadInteger(Hash, HeroButtonUnitCode[buttonIndex],0)
if PlayerSelectedCategory[playerIndex] == 0 or BlzBitAnd(HeroCategory[unitCodeIndex], PlayerSelectedCategory[playerIndex]) > 0 then
call BlzFrameSetAlpha(HeroButtonFrame[buttonIndex], 255)
else
call BlzFrameSetAlpha(HeroButtonFrame[buttonIndex], CategoryFilteredAlpha)
endif
endif
set buttonIndex = buttonIndex + 1
endloop
endif
set fh = null
set p = null
endfunction
function HeroSelectorInit takes nothing returns nothing
local integer buttonIndex
local real titleSize = 0.015
local real borderSize = GetBorderSize()
local integer colCount = ButtonColCount
local integer rowCount = ButtonRowCount
local framehandle box = BlzCreateFrame(BoxFrameName, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
local integer rowRemaining = colCount
local real y = -borderSize - titleSize - 0.0125 - CategorySize
local real x = borderSize
local integer playerIndex = 0
local integer teamIndexLoop
local integer teamNr
call ExecuteFunc("HeroSelectorAction_InitHeroes")
call BlzLoadTOCFile("war3mapImported\\HeroSelector.toc") //ex/import also "HeroSelector.fdf"
//for key, value in ipairs(HeroSelector.UnitData)
//do
// print(key, ('>I4'):pack(value), GetObjectName(value))
//end
//find all Teams in usage
loop
exitwhen playerIndex == GetBJMaxPlayers()
set teamNr = GetPlayerTeam(Player(playerIndex))
if teamNr != -1 then
set teamIndexLoop = UsedTeamNrCount
loop
exitwhen teamIndexLoop == 0
exitwhen UsedTeamNr[teamIndexLoop] == teamNr
set teamIndexLoop = teamIndexLoop - 1
endloop
if teamIndexLoop == 0 then
set UsedTeamNrCount = UsedTeamNrCount + 1
set UsedTeamNr[UsedTeamNrCount] = teamNr
endif
endif
set playerIndex = playerIndex + 1
endloop
call TriggerAddAction(HeroButtonClickTrigger, function HeroSelectorActionPressHeroButton)
set HeroSelectorBoxTitle = BlzCreateFrame("HeroSelectorTitle", box, 0, 0)
set IndicatorSelected = BlzCreateFrameByType("SPRITE", "MyHeroIndikator", box, "", 0)
set HeroSelectorBox = box
call BlzFrameSetModel(IndicatorSelected, IndicatorPathPick, 0)
call BlzFrameSetScale(IndicatorSelected, ButtonSize/0.036) //scale the model to the button size.
call BlzFrameSetVisible(IndicatorSelected, false)
call BlzFrameSetAbsPoint(box, BoxPosPoint, BoxPosX, BoxPosY)
call BlzFrameSetSize(box, borderSize*2 + ButtonSize*colCount + SpaceBetweenX*(colCount-1), borderSize*2 + ButtonSize*rowCount + SpaceBetweenY*(rowCount - 1) + titleSize + CategorySize + 0.0145)
call BlzFrameSetPoint(HeroSelectorBoxTitle, FRAMEPOINT_TOP, box, FRAMEPOINT_TOP, 0, -borderSize)
call BlzFrameSetText(HeroSelectorBoxTitle, "Hero Selection")
if colCount*rowCount < ButtonHeroCount then
call BJDebugMsg("FieldCount:"+ I2S(colCount*rowCount) + "HeroCount" + I2S(ButtonHeroCount))
endif
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
set HeroButtonFrame[buttonIndex] = BlzCreateFrame("HeroSelectorButton", box, 0, buttonIndex)
set HeroButtonIcon[buttonIndex] = BlzGetFrameByName("HeroSelectorButtonIcon", buttonIndex)
set HeroButtonIconDisabled[buttonIndex] = BlzGetFrameByName("HeroSelectorButtonIconDisabled", buttonIndex)
set HeroButtonUnitCode[buttonIndex] = ButtonHeroUnitCode[buttonIndex]
call SaveInteger(Hash, GetHandleId(HeroButtonFrame[buttonIndex]), 0, buttonIndex)
set HeroButtonTooltip[buttonIndex] = BlzCreateFrame("HeroSelectorText", box, 0, buttonIndex)
call BlzFrameSetTooltip(HeroButtonFrame[buttonIndex], HeroButtonTooltip[buttonIndex])
if not TooltipRelativIsBox then
call BlzFrameSetPoint(HeroButtonTooltip[buttonIndex], TooltipPoint, HeroButtonFrame[buttonIndex], TooltipRelativePoint, TooltipOffsetX ,TooltipOffsetY)
else
call BlzFrameSetPoint(HeroButtonTooltip[buttonIndex], TooltipPoint, box, TooltipRelativePoint, TooltipOffsetX ,TooltipOffsetY)
endif
call BlzTriggerRegisterFrameEvent(HeroButtonClickTrigger, HeroButtonFrame[buttonIndex], FRAMEEVENT_CONTROL_CLICK)
call BlzFrameSetSize(HeroButtonFrame[buttonIndex], ButtonSize, ButtonSize)
if HeroButtonUnitCode[buttonIndex] > 0 then
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex]), 0, ButtonBlendAll)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], HeroSelectorGetDisabledIcon(BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex])), 0, ButtonBlendAll)
call BlzFrameSetText(HeroButtonTooltip[buttonIndex], TooltipPrefix + GetObjectName(HeroButtonUnitCode[buttonIndex]))
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], HeroSelectorButtonRequirementDone(HeroButtonUnitCode[buttonIndex], GetLocalPlayer()))
else
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], EmptyButtonPath, 0, true)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], EmptyButtonPath, 0, true)
endif
if ChainedButtons then //buttons are connected to the previous one or the previous row
if buttonIndex == 1 then
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, borderSize, y)
elseif rowRemaining <= 0 then
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, HeroButtonFrame[buttonIndex - colCount], FRAMEPOINT_BOTTOMLEFT, 0, -SpaceBetweenY)
set rowRemaining = colCount
else
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_LEFT, HeroButtonFrame[buttonIndex - 1], FRAMEPOINT_RIGHT, SpaceBetweenX, 0)
endif
else //buttons have an offset to the TopLeft of the box
if rowRemaining <= 0 then
set x = borderSize
set rowRemaining = colCount
set y = y - SpaceBetweenY - ButtonSize
elseif buttonIndex != 1 then
set x = x + ButtonSize + SpaceBetweenX
endif
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, x, y)
endif
set rowRemaining = rowRemaining - 1
set buttonIndex = buttonIndex + 1
endloop
set y = -borderSize - titleSize - 0.0105
set x = borderSize
//create category buttons added before the box was created
set buttonIndex = 1
loop
exitwhen buttonIndex > CategoryButtonCount
set CategoryButton[buttonIndex] = BlzCreateFrameByType("BUTTON", "", box, "", 0)
set CategoryIconFrame[buttonIndex] = BlzCreateFrameByType("BACKDROP", "", box, "", 0)
set CategoryTooltipFrame[buttonIndex] = BlzCreateFrame("HeroSelectorText", box, 0, buttonIndex)
call BlzFrameSetText(CategoryTooltipFrame[buttonIndex], GetLocalizedString(CategoryText[buttonIndex]))
call BlzFrameSetPoint(CategoryTooltipFrame[buttonIndex], FRAMEPOINT_BOTTOM, CategoryButton[buttonIndex], FRAMEPOINT_TOP, 0, 0)
call BlzFrameSetTooltip(CategoryButton[buttonIndex], CategoryTooltipFrame[buttonIndex])
call BlzFrameSetAllPoints(CategoryIconFrame[buttonIndex], CategoryButton[buttonIndex])
call BlzFrameSetSize(CategoryButton[buttonIndex], CategorySize, CategorySize)
call BlzFrameSetTexture(CategoryIconFrame[buttonIndex], CategoryTextureDisabled[buttonIndex], 0, true)
call BlzTriggerRegisterFrameEvent(CategoryClickTrigger, CategoryButton[buttonIndex], FRAMEEVENT_CONTROL_CLICK)
if buttonIndex == 1 then
call BlzFrameSetPoint(CategoryButton[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, x, y)
else
call BlzFrameSetPoint(CategoryButton[buttonIndex], FRAMEPOINT_LEFT, CategoryButton[buttonIndex - 1], FRAMEPOINT_RIGHT, CategorySpaceX, 0)
endif
call SaveInteger(Hash, GetHandleId(CategoryButton[buttonIndex]), 0, buttonIndex)
set buttonIndex = buttonIndex + 1
endloop
call TriggerAddAction(CategoryClickTrigger, function HeroSelectorActionCategoryButton)
set AcceptButton = BlzCreateFrameByType("GLUETEXTBUTTON", "OKButton", box, "ScriptDialogButton", 0)
set RandomButton = BlzCreateFrameByType("GLUETEXTBUTTON", "RandomButton", box, "ScriptDialogButton", 0)
set BanButton = BlzCreateFrameByType("GLUETEXTBUTTON", "BanButton", box, "ScriptDialogButton", 0)
call TriggerAddAction(AcceptButtonTrigger, function HeroSelectorActionAcceptButton)
call TriggerAddAction(RandomButtonTrigger, function HeroSelectorActionRandomButton)
call TriggerAddAction(BanButtonTrigger, function HeroSelectorActionBanButton)
call BlzTriggerRegisterFrameEvent(AcceptButtonTrigger, AcceptButton, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(RandomButtonTrigger, RandomButton, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(BanButtonTrigger, BanButton, FRAMEEVENT_CONTROL_CLICK)
call BlzFrameSetSize(AcceptButton, AcceptButtonSizeX, AcceptButtonSizeY)
call BlzFrameSetSize(RandomButton, RandomButtonSizeX, RandomButtonSizeY)
call BlzFrameSetSize(BanButton, BanButtonSizeX, BanButtonSizeY)
//OK, READY, ACCEPT
call BlzFrameSetText(AcceptButton, AcceptButtonTextPrefix + GetLocalizedString(AcceptButtonText))
call BlzFrameSetText(RandomButton, RandomButtonTextPrefix + GetLocalizedString(RandomButtonText))
call BlzFrameSetText(BanButton, BanButtonTextPrefix + GetLocalizedString(BanButtonText))
call BlzFrameSetPoint(AcceptButton, AcceptButtonAnchor, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetPoint(RandomButton, RandomButtonAnchor, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetPoint(BanButton, FRAMEPOINT_BOTTOM, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetVisible(BanButton, false)
call BlzFrameSetVisible(AcceptButton, AcceptButtonIsShown)
call BlzFrameSetVisible(RandomButton, RandomButtonIsShown)
if not AutoShow then
call BlzFrameSetVisible(box, false)
endif
call ExecuteFunc("HeroInfoInit")
call ExecuteFunc("TeamViewerInit")
endfunction
endlibrary
library HeroSelectorAction initializer Init uses HeroSelector, TeamViewer, HeroInfo
//HeroSelectorAction V1.2.1
//what happens to the unit beeing picked, player is the one having pressed the button
function HeroSelectorUnitCreated takes nothing returns nothing
local player p = udg_HeroSelectorEventPlayer
local unit u = udg_HeroSelectorEventUnit
local boolean isRandom = udg_HeroSelectorEventIsRandom
set bj_lastCreatedUnit = u
if isRandom then
//randomed
else
//picked
endif
call SetUnitPosition(u, GetPlayerStartLocationX(p), GetPlayerStartLocationY(p))
if p == Player(1) then
endif
call TeamViewerUnitCreated(p, u, isRandom)
call PanCameraToTimedForPlayer(p, GetUnitX(u), GetUnitY(u),0)
call SelectUnitForPlayerSingle(u, p)
call HeroSelectorEnablePickPlayer(false, p) //only one pick for this player
set p = null
set u = null
endfunction
//happens when the banButton is pressed, player is the one having pressed the button
function HeroSelectorUnitBaned takes nothing returns nothing
local player p = udg_HeroSelectorEventPlayer
local integer unitCode = udg_HeroSelectorEventUnitCode
call HeroSelectorEnableBanPlayer(false, p) //only one ban
set p = null
endfunction
function HeroSelectorButtonSelected takes nothing returns nothing
//player who pressed the button
//unitCode the unitCode selected
//this is not picked.
local player p = udg_HeroSelectorEventPlayer
local integer unitCode = udg_HeroSelectorEventUnitCode
call HeroInfoButtonSelected(p, unitCode)
call TeamViewerButtonSelected(p, unitCode)
set p = null
endfunction
function HeroSelectorRepick takes unit u returns nothing
local integer unitCode
local player p = GetOwningPlayer(u)
call UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, u) //this is done to undo metamorph
set unitCode = GetUnitTypeId(u)
if unitCode == 0 then
return
endif
call HeroSelectorCounterChangeUnitCode(unitCode, -1, p)
call HeroSelectorShowPlayer(true, p)
call HeroSelectorEnablePickPlayer(true, p)
call TeamViewerRepick(u, p)
call RemoveUnit(u)
endfunction
//This runs before the box is created with that the system has the needed data right when it is needed.
//you can add units somewhere else but it is done after the box was created you have to use the update function to update the textures of shown buttons
public function InitHeroes takes nothing returns nothing
//create categories setuped in config
local integer index
local integer categoryMelee = 1 //autodetected
local integer categoryRanged = 2 //autodetected
local integer categoryStr = 4
local integer categoryAgi = 8
local integer categoryInt = 16
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSteelMelee", "MELEE") //1, automatic detected when adding an unit
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNHumanMissileUpOne", "Ranged") //2, automatic detected when adding an unit
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower", "STRENGTH") //4
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility", "AGILITY") //8
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNMantleOfIntelligence", "INTELLECT") //16
//read GUI, when the variable exist
set index = 1
//add from index 1 all random only heroes
loop
exitwhen udg_HeroSelectorRandomOnly[index] == 0
call HeroSelectorAddUnit(udg_HeroSelectorRandomOnly[index], true)
set index = index + 1
endloop
set index = 1
//copy the setuped field
loop
exitwhen index > HeroSelector_HeroButtonCount
call HeroSelectorAddUnit(udg_HeroSelectorUnitCode[index], false)
set index = index + 1
endloop
//adding further units when using the GUI Array does not make much sense, except you would add rows.
call HeroSelectorAddUnit('Hgam', true) //antonidas is an only random Hero that can only be randomed by team 0 (for users 1).
call HeroSelectorAddUnit('Eevi', true) //evil Illidan is an only random Hero that can only be randomed by team 1 (for users 2).
//Adds requirments
//when you have a ban phase it might be better to add the requirments after the ban phase is over, otherwise one can only ban own options.
//human only work for human, as nightelf only for Nightelf
call HeroSelectorSetUnitReqRace('Hpal', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hamg', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hblm', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hmkg', RACE_HUMAN)
//call HeroSelectorSetUnitReqRace('Ofar', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Oshd', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Otch', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Obla', RACE_ORC)
call HeroSelectorSetUnitReqRace('Emoo', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Edem', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Ekee', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Ewar', RACE_NIGHTELF)
//call HeroSelectorSetUnitReqRace('Udea', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Ulic', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Udre', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Ucrl', RACE_UNDEAD)
endfunction
private function Init takes nothing returns nothing
local trigger trig
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 2.0 )
call TriggerAddAction(trig, function HeroSelectorButtonSelected)
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 1.0 )
call TriggerAddAction(trig, function HeroSelectorUnitCreated)
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 3.0 )
call TriggerAddAction(trig, function HeroSelectorUnitBaned)
endfunction
endlibrary
library CombinedCameraSliderSystem
//----------------------------------------------\\
// \\
// Version 1.2 \\
// Written by Sabe / Sabeximus#2923 \\
// \\
//----------------------------------------------\\
globals
private framehandle sliderDistance
private framehandle sliderDistanceLabel
private framehandle sliderAngleOfAttack
private framehandle sliderAngleOfAttackLabel
private framehandle sliderRotation
private framehandle sliderRotationLabel
private framehandle sliderHeight
private framehandle sliderHeightLabel
private framehandle resetButton
private framehandle sliderAbove
private framepointtype framepointVerticalMain
private framepointtype framepointVerticalSecondary
private framepointtype framepointCornerMain
private framepointtype framepointCheckboxMain
private framepointtype framepointCheckboxSecondary
private boolean array leftArrowIsDown
private boolean array upArrowIsDown
private boolean array downArrowIsDown
private boolean array rightArrowIsDown
private boolean array wKeyIsDown
private boolean array aKeyIsDown
private boolean array sKeyIsDown
private boolean array dKeyIsDown
private boolean array xKeyIsDown
private real array horizontalChange
private real array verticalChange
private real array xTarget
private real array yTarget
private real array forward
private real array sideways
private real array orderDelay
private real array fullTurnDelay
private boolean debugMode = false
endglobals
private function LoadToc takes string s returns nothing
if not BlzLoadTOCFile(s) then
call BJDebugMsg("|cffff0000Failed to Load: " + s + "|r \nYou need to import the |cffffcc00templates.toc|r file.")
endif
endfunction
private function UpdateCam takes nothing returns nothing
local integer i = GetPlayerId(GetEnumPlayer())
local unit u = udg_CCSS_TargetUnit[i + 1]
local real facing = GetUnitFacing(u)
local real moveSpeed = GetUnitMoveSpeed(u)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real hDir = 0
local real vDir = 0
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_TARGET_DISTANCE, BlzFrameGetValue(sliderDistance), udg_CCSS_CamUpdateInterval)
if (udg_CCSS_3rdPersonCamMode) then // Check if Third Person Camera mode is enabled
if (((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys)) and (u != null)) then // Unit WASD control. Obviously, run these only if the WASD keys are enabled and there is a Target Unit
if (wKeyIsDown[i]) then
set forward[i] = 1
else
set forward[i] = 0
endif
if (aKeyIsDown[i]) then
set sideways[i] = sideways[i] - 1
endif
if (dKeyIsDown[i]) then
set sideways[i] = sideways[i] + 1
endif
set xTarget[i] = x
set yTarget[i] = y
if ((moveSpeed / udg_CCSS_WASDMoveSpeedModifier) < udg_CCSS_WASDMoveMinDistance) then
set moveSpeed = udg_CCSS_WASDMoveMinDistance
else
set moveSpeed = moveSpeed / udg_CCSS_WASDMoveSpeedModifier
endif
if (forward[i] == 1) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing)) * (moveSpeed)
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing)) * (moveSpeed)
if (sideways[i] < 0) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
if (sideways[i] > 0) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
else
if (sideways[i] == -1) then
call SetUnitFacing(u, facing + (udg_CCSS_WASDStationaryTurnSpeed))
set sideways[i] = 0
endif
if (sideways[i] == 1) then
call SetUnitFacing(u, facing - (udg_CCSS_WASDStationaryTurnSpeed))
set sideways[i] = 0
endif
if (udg_CCSS_SButtonOrder != "") then
if (sKeyIsDown[i]) then
call IssueImmediateOrder(u, udg_CCSS_SButtonOrder)
endif
endif
set fullTurnDelay[i] = fullTurnDelay[i] - udg_CCSS_CamUpdateInterval
if (fullTurnDelay[i] <= 0) then
if (udg_CCSS_SButton180Turn) then
if (sKeyIsDown[i]) then
set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
call SetUnitFacing(u, facing - 180)
endif
endif
if (udg_CCSS_XButton180Turn) then
if (xKeyIsDown[i]) then
set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
call SetUnitFacing(u, facing - 180)
endif
endif
endif
endif
set orderDelay[i] = orderDelay[i] - udg_CCSS_WASDMoveOrderInterval
if (orderDelay[i] <= 0) then
set orderDelay[i] = 1
if ((forward[i] != 0) or (sideways[i] != 0)) then
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
endif
endif
if (udg_CCSS_UseArrowKeys) then // Only run these if the Arrow Keys are used
// Horizontal Key Register
if (leftArrowIsDown[i]) then
if (udg_CCSS_InvertHorizontalMovement) then
if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir - 1
endif
else
if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir + 1
endif
endif
endif
if (rightArrowIsDown[i]) then
if (udg_CCSS_InvertHorizontalMovement) then
if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir + 1
endif
else
if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir - 1
endif
endif
endif
set horizontalChange[i] = horizontalChange[i] + (hDir * udg_CCSS_HorizontalSpeed)
if ((hDir == 0) and (horizontalChange[i] != 0)) then
if (horizontalChange[i] > 0) then
set horizontalChange[i] = horizontalChange[i] - (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
if (horizontalChange[i] < udg_CCSS_HorizontalSpeed) then
set horizontalChange[i] = 0
endif
else
set horizontalChange[i] = horizontalChange[i] + (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
if (horizontalChange[i] > udg_CCSS_HorizontalSpeed) then
set horizontalChange[i] = 0
endif
endif
endif
// Vertical Key Register
if (upArrowIsDown[i]) then
if (udg_CCSS_InvertVerticalMovement) then
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
set vDir = vDir - 1
endif
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then // Don't allow the number to grow if camera had stopped at the limit
set vDir = vDir + 1
endif
endif
endif
if (downArrowIsDown[i]) then
if (udg_CCSS_InvertVerticalMovement) then
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then
set vDir = vDir + 1
endif
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
set vDir = vDir - 1
endif
endif
endif
set verticalChange[i] = verticalChange[i] + (vDir * udg_CCSS_VerticalSpeed)
if ((vDir == 0) and (verticalChange[i] != 0)) then
if (verticalChange[i] > 0) then
set verticalChange[i] = verticalChange[i] - (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
if (verticalChange[i] < udg_CCSS_VerticalSpeed) then
set verticalChange[i] = 0
endif
else
set verticalChange[i] = verticalChange[i] + (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
if (verticalChange[i] > udg_CCSS_VerticalSpeed) then
set verticalChange[i] = 0
endif
endif
endif
endif
// Apply arrow key changes
if (u != null) then // Check if our player has a Target Unit
// Horizontal
if (horizontalChange[i] > udg_CCSS_HorizontalArrowMoveLimit) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval) // Prevent camera from rolling around the unit forever
else
if (horizontalChange[i] < -udg_CCSS_HorizontalArrowMoveLimit) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing - udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval)
else
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + horizontalChange[i], udg_CCSS_CamUpdateInterval)
endif
endif
if (GetLocalPlayer() == Player(i)) then // Lock the rotation bar. Purely cosmetic, can be removed if, for example, causes desync problems. (The bar won't affect rotation even if not locked)
call BlzFrameSetEnable(sliderRotation, false)
endif
// Vertical
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) > (udg_CCSS_AngleOfAttackMax)) then // Prevent camera from overstepping angle of attack slider maximum and minimum.
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMax, udg_CCSS_CamUpdateInterval)
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) < (udg_CCSS_AngleOfAttackMin)) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMin, udg_CCSS_CamUpdateInterval)
else
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i], udg_CCSS_CamUpdateInterval)
endif
endif
// Add Unit Height to Camera
if (udg_CCSS_AddUnitHeightToCamera) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight) + GetUnitFlyHeight(u), udg_CCSS_CamUpdateInterval)
endif
else // If doesn't have Target Unit
// Horizontal
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 Because I want the default rotation angle (90) to be zero for simplicity's sake
if ((GetLocalPlayer() == GetEnumPlayer()) and (udg_CCSS_RotationEnabled)) then
call BlzFrameSetEnable(sliderRotation, true)
endif
// Vertical
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)
// Height
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
endif
else // Only run this if 3rdPC mode is not used
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 so that 0 on the slider is the default WC3 angle
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
endif
set u = null
endfunction
private function HumanPlayersPlaying takes nothing returns boolean
if (GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER) and (GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING) then
return true
else
return false
endif
endfunction
private function PreUpdateCam takes nothing returns nothing
local force f = GetPlayersMatching(Condition(function HumanPlayersPlaying)) // No point in picking computer players
call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
call BlzFrameSetEnable(sliderRotation, udg_CCSS_DistanceEnabled)
call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
if (udg_CCSS_ShowValues) then
call BlzFrameSetText(sliderDistanceLabel, "Distance: " + R2SW(BlzFrameGetValue(sliderDistance), 1, 1))
call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle: " + R2SW(BlzFrameGetValue(sliderAngleOfAttack), 1, 1))
call BlzFrameSetText(sliderRotationLabel, "Rotation: " + R2SW(BlzFrameGetValue(sliderRotation), 1, 1))
call BlzFrameSetText(sliderHeightLabel, "Height: " + R2SW(BlzFrameGetValue(sliderHeight), 1, 1))
else
call BlzFrameSetText(sliderDistanceLabel, "Distance")
call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle")
call BlzFrameSetText(sliderRotationLabel, "Rotation")
call BlzFrameSetText(sliderHeightLabel, "Height")
endif
call ForForce(f, function UpdateCam)
call DestroyForce(f)
endfunction
private function CreateSliders takes nothing returns nothing
local real labelGap
set sliderDistance = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
set sliderDistanceLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderDistance, 0, 0)
set sliderAngleOfAttack = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 1)
set sliderAngleOfAttackLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderAngleOfAttack, 0, 0)
set sliderRotation = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 2)
set sliderRotationLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderRotation, 0, 0)
set sliderHeight = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 3)
set sliderHeightLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderHeight, 0, 0)
set sliderAbove = null
if (udg_CCSS_PositionSlidersX >= 8) then
set udg_CCSS_PositionSlidersX = 0.8
else
if (udg_CCSS_PositionSlidersX < 0) then
set udg_CCSS_PositionSlidersX = 0
else
set udg_CCSS_PositionSlidersX = udg_CCSS_PositionSlidersX / 10 // GUI only allows 2 decimals for reals, so this way I can get 3 decimals for JASS
endif
endif
if (udg_CCSS_PositionSlidersY >= 6) then
set udg_CCSS_PositionSlidersY = 0.6
else
if (udg_CCSS_PositionSlidersY < 0) then
set udg_CCSS_PositionSlidersY = 0
else
set udg_CCSS_PositionSlidersY = udg_CCSS_PositionSlidersY / 10
endif
endif
set udg_CCSS_SliderGap = udg_CCSS_SliderGap / 10
if (udg_CCSS_AlignmentLeft) then
set framepointVerticalMain = FRAMEPOINT_LEFT
set framepointVerticalSecondary = FRAMEPOINT_RIGHT
set framepointCornerMain = FRAMEPOINT_TOPLEFT
set labelGap = 0.005
else
set framepointVerticalMain = FRAMEPOINT_RIGHT
set framepointVerticalSecondary = FRAMEPOINT_LEFT
set framepointCornerMain = FRAMEPOINT_TOPRIGHT
set labelGap = -0.005
endif
//Distance Slider options
call BlzFrameSetAbsPoint(sliderDistance, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
call BlzFrameSetPoint(sliderDistanceLabel, framepointVerticalMain, sliderDistance, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderDistance, udg_CCSS_DistanceMin, udg_CCSS_DistanceMax)
call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
call BlzFrameSetStepSize(sliderDistance, udg_CCSS_DistanceStep)
call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
if (udg_CCSS_DistanceShow) then
set sliderAbove = sliderDistance
endif
call BlzFrameSetVisible(sliderDistance, false)
//Angle of Attack Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderAngleOfAttack, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderAngleOfAttack, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderAngleOfAttackLabel, framepointVerticalMain, sliderAngleOfAttack, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackMin, udg_CCSS_AngleOfAttackMax)
call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
call BlzFrameSetStepSize(sliderAngleOfAttack, udg_CCSS_AngleOfAttackStep)
call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
if (udg_CCSS_AngleOfAttackShow) then
set sliderAbove = sliderAngleOfAttack
endif
call BlzFrameSetVisible(sliderAngleOfAttack, false)
//Rotation Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderRotation, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderRotation, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderRotationLabel, framepointVerticalMain, sliderRotation, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderRotation, udg_CCSS_RotationMin, udg_CCSS_RotationMax)
call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
call BlzFrameSetStepSize(sliderRotation, udg_CCSS_RotationStep)
call BlzFrameSetEnable(sliderRotation, udg_CCSS_RotationEnabled)
if (udg_CCSS_RotationShow) then
set sliderAbove = sliderRotation
endif
call BlzFrameSetVisible(sliderRotation, false)
//Height Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderHeight, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderHeight, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderHeightLabel, framepointVerticalMain, sliderHeight, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderHeight, udg_CCSS_HeightMin, udg_CCSS_HeightMax)
call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
call BlzFrameSetStepSize(sliderHeight, udg_CCSS_HeightStep)
call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
if (udg_CCSS_HeightShow) then
set sliderAbove = sliderHeight
endif
call BlzFrameSetVisible(sliderHeight, false)
endfunction
private function ResetSliders takes nothing returns nothing
if GetLocalPlayer() == GetTriggerPlayer() then
call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
endif
call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
call BlzFrameSetEnable(BlzGetTriggerFrame(), true)
endfunction
private function CreateResetButton takes nothing returns nothing
local trigger t = CreateTrigger()
set resetButton = BlzCreateFrame("ScriptDialogButton", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
set udg_CCSS_ResetButtonSizeX = udg_CCSS_ResetButtonSizeX / 10
set udg_CCSS_ResetButtonSizeY = udg_CCSS_ResetButtonSizeY / 10
if (sliderAbove != null) then
call BlzFrameSetPoint(resetButton, framepointCornerMain, sliderAbove, framepointVerticalMain, 0, -(udg_CCSS_SliderGap * 2))
else
call BlzFrameSetAbsPoint(resetButton, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetSize(resetButton, udg_CCSS_ResetButtonSizeX, udg_CCSS_ResetButtonSizeY)
call BlzFrameSetText(resetButton, udg_CCSS_ResetButtonText)
call BlzFrameSetVisible(resetButton, false)
call TriggerAddAction(t, function ResetSliders)
call BlzTriggerRegisterFrameEvent(t, resetButton, FRAMEEVENT_CONTROL_CLICK)
endfunction
private function CheckBoxLockSliders takes nothing returns nothing
local boolean b = (BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED)
if GetLocalPlayer() == GetTriggerPlayer() then
if (udg_CCSS_DistanceShow) then
call BlzFrameSetVisible(sliderDistance, b)
endif
if (udg_CCSS_AngleOfAttackShow) then
call BlzFrameSetVisible(sliderAngleOfAttack, b)
endif
if (udg_CCSS_RotationShow) then
call BlzFrameSetVisible(sliderRotation, b)
endif
if (udg_CCSS_HeightShow) then
call BlzFrameSetVisible(sliderHeight, b)
endif
call BlzFrameSetVisible(resetButton, b)
endif
endfunction
private function CreateCheckbox takes nothing returns nothing
local trigger t = CreateTrigger()
local framehandle fh = BlzCreateFrame("QuestCheckBox", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
local framehandle label = BlzCreateFrame("EscMenuLabelTextTemplate", fh, 0, 0)
local real labelGap
if (udg_CCSS_PositionCheckBoxX >= 8) then
set udg_CCSS_PositionCheckBoxX = 0.8
else
if (udg_CCSS_PositionCheckBoxX < 0) then
set udg_CCSS_PositionCheckBoxX = 0
else
set udg_CCSS_PositionCheckBoxX = udg_CCSS_PositionCheckBoxX / 10
endif
endif
if (udg_CCSS_PositionCheckBoxY >= 6) then
set udg_CCSS_PositionCheckBoxY = 0.6
else
if (udg_CCSS_PositionCheckBoxY < 0) then
set udg_CCSS_PositionCheckBoxY = 0
else
set udg_CCSS_PositionCheckBoxY = udg_CCSS_PositionCheckBoxY / 10
endif
endif
if (udg_CCSS_CheckBoxTextOnLeft) then
set framepointCheckboxMain = FRAMEPOINT_RIGHT
set framepointCheckboxSecondary = FRAMEPOINT_LEFT
set labelGap = -0.005
else
set framepointCheckboxMain = FRAMEPOINT_LEFT
set framepointCheckboxSecondary = FRAMEPOINT_RIGHT
set labelGap = 0.005
endif
call BlzFrameSetPoint(label, framepointCheckboxMain, fh, framepointCheckboxSecondary, labelGap, 0)
call BlzFrameSetAbsPoint(fh, framepointCheckboxMain, udg_CCSS_PositionCheckBoxX, udg_CCSS_PositionCheckBoxY)
call BlzFrameSetText(label, udg_CCSS_CheckBoxText)
call BlzFrameSetVisible(fh, udg_CCSS_CheckBoxShow)
call TriggerAddAction(t, function CheckBoxLockSliders)
call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_UNCHECKED)
endfunction
// Arrow keys
private function LeftArrowPress takes nothing returns nothing
set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function LeftArrowRelease takes nothing returns nothing
set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function UpArrowPress takes nothing returns nothing
set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function UpArrowRelease takes nothing returns nothing
set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function DownArrowPress takes nothing returns nothing
set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function DownArrowRelease takes nothing returns nothing
set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function RightArrowPress takes nothing returns nothing
set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function RightArrowRelease takes nothing returns nothing
set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function ArrowKeyListeners takes nothing returns nothing
local trigger tLp = CreateTrigger()
local trigger tUp = CreateTrigger()
local trigger tDp = CreateTrigger()
local trigger tRp = CreateTrigger()
local trigger tLr = CreateTrigger()
local trigger tUr = CreateTrigger()
local trigger tDr = CreateTrigger()
local trigger tRr = CreateTrigger()
local integer i
set i = 0
loop
call TriggerRegisterPlayerKeyEventBJ(tLp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_LEFT)
call TriggerRegisterPlayerKeyEventBJ(tLr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_LEFT)
call TriggerRegisterPlayerKeyEventBJ(tUp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_UP)
call TriggerRegisterPlayerKeyEventBJ(tUr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_UP)
call TriggerRegisterPlayerKeyEventBJ(tDp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_DOWN)
call TriggerRegisterPlayerKeyEventBJ(tDr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_DOWN)
call TriggerRegisterPlayerKeyEventBJ(tRp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_RIGHT)
call TriggerRegisterPlayerKeyEventBJ(tRr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_RIGHT)
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(tLp, function LeftArrowPress)
call TriggerAddAction(tLr, function LeftArrowRelease)
call TriggerAddAction(tUp, function UpArrowPress)
call TriggerAddAction(tUr, function UpArrowRelease)
call TriggerAddAction(tDp, function DownArrowPress)
call TriggerAddAction(tDr, function DownArrowRelease)
call TriggerAddAction(tRp, function RightArrowPress)
call TriggerAddAction(tRr, function RightArrowRelease)
endfunction
// WASD keys
private function WKey takes nothing returns nothing
set wKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("W is pressed")
else
call BJDebugMsg("W is released")
endif
endif
endfunction
private function AKey takes nothing returns nothing
set aKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("A is pressed")
else
call BJDebugMsg("A is released")
endif
endif
endfunction
private function SKey takes nothing returns nothing
set sKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("S is pressed")
else
call BJDebugMsg("S is released")
endif
endif
endfunction
private function DKey takes nothing returns nothing
set dKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("D is pressed")
else
call BJDebugMsg("D is released")
endif
endif
endfunction
private function XKey takes nothing returns nothing
set xKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("X is pressed")
else
call BJDebugMsg("X is released")
endif
endif
endfunction
private function WASDKeyListeners takes nothing returns nothing
local trigger tWp = CreateTrigger()
local trigger tAp = CreateTrigger()
local trigger tSp = CreateTrigger()
local trigger tDp = CreateTrigger()
local trigger tWr = CreateTrigger()
local trigger tAr = CreateTrigger()
local trigger tSr = CreateTrigger()
local trigger tDr = CreateTrigger()
local trigger tXp = CreateTrigger()
local trigger tXr = CreateTrigger()
local integer i
set i = 0
loop
if (udg_CCSS_UseNumpadKeys) then
call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_NUMPAD8, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_NUMPAD8, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_NUMPAD4, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_NUMPAD4, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_NUMPAD5, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_NUMPAD5, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_NUMPAD6, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_NUMPAD6, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_NUMPAD2, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_NUMPAD2, 0, false)
else
call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_W, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_W, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_A, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_A, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_S, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_S, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_D, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_D, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_X, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_X, 0, false)
endif
set orderDelay[i] = 0
set fullTurnDelay[i] = 0
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(tWp, function WKey)
call TriggerAddAction(tWr, function WKey)
call TriggerAddAction(tAp, function AKey)
call TriggerAddAction(tAr, function AKey)
call TriggerAddAction(tSp, function SKey)
call TriggerAddAction(tSr, function SKey)
call TriggerAddAction(tDp, function DKey)
call TriggerAddAction(tDr, function DKey)
call TriggerAddAction(tXp, function XKey)
call TriggerAddAction(tXr, function XKey)
endfunction
//=============================================================================
function CreateCamControl takes nothing returns nothing
call LoadToc("war3mapimported\\templates.toc")
call CreateSliders()
call CreateCheckbox()
call CreateResetButton()
if ((udg_CCSS_3rdPersonCamMode) and (udg_CCSS_UseArrowKeys)) then // If 3rd Person Cam and Arrow keys aren't enabled, don't bother to create triggers for listening the keys
call ArrowKeyListeners()
endif
if ((udg_CCSS_3rdPersonCamMode) and ((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys))) then
call WASDKeyListeners()
endif
call TimerStart(CreateTimer(), udg_CCSS_CamUpdateInterval, true, function PreUpdateCam)
set debugMode = false // Turn true for testing purposes
endfunction
endlibrary