Name | Type | is_array | initial_value |
FilePath | string | No | |
Unit | unit | No | |
UnitType | unitcode | No |
library GetMainSelectedUnit initializer init_function // By Tasyen
globals
private trigger LoadBugTrigger = CreateTrigger()
private framehandle containerFrame
private framehandle array frames
private group Group = CreateGroup()
private unit array units
private integer unitsCount = 0
private filterfunc filter
endglobals
function GetUnitOrderValue takes unit u returns integer
//heroes use the handleId
if IsUnitType(u, UNIT_TYPE_HERO) then
return GetHandleId(u)
else
//units use unitCode
return GetUnitTypeId(u)
endif
endfunction
private function FilterFunction takes nothing returns boolean
local unit u = GetFilterUnit()
local real prio = BlzGetUnitRealField(u, UNIT_RF_PRIORITY)
local boolean found = false
local integer loopA = 1
local integer loopB = 0
// compare the current u with allready found, to place it in the right slot
loop
exitwhen loopA > unitsCount
if BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) < prio then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
// equal prio and better colisions Value
elseif BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) == prio and GetUnitOrderValue(units[loopA]) > GetUnitOrderValue(u) then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
endif
set loopA = loopA + 1
endloop
// not found add it at the end
if not found then
set unitsCount = unitsCount + 1
set units[unitsCount] = u
endif
set u = null
return false
endfunction
function GetSelectedUnitIndex takes nothing returns integer
local integer i = 0
// local player is in group selection?
if BlzFrameIsVisible(containerFrame) then
// find the first visible yellow Background Frame
loop
exitwhen i > 11
if BlzFrameIsVisible(frames[i]) then
return i
endif
set i = i + 1
endloop
endif
return -1
endfunction
function GetMainSelectedUnit takes player whichPlayer, integer index returns unit
if index >= 0 then
call GroupEnumUnitsSelected(Group, whichPlayer, filter)
set bj_groupRandomCurrentPick = units[index + 1]
//clear table
loop
exitwhen unitsCount <= 0
set units[unitsCount] = null
set unitsCount = unitsCount - 1
endloop
return bj_groupRandomCurrentPick
else
call GroupEnumUnitsSelected(Group, whichPlayer, null)
return FirstOfGroup(Group)
endif
endfunction
// returns the local current main selected unit, using it in a sync gamestate relevant manner breaks the game.
function GetMainSelectedUnitEx takes nothing returns unit
return GetMainSelectedUnit(GetLocalPlayer(), GetSelectedUnitIndex())
endfunction
private function init_functionAt0s takes nothing returns nothing
local integer i = 0
local framehandle console = BlzGetFrameByName("ConsoleUI", 0)
local framehandle bottomUI = BlzFrameGetChild(console, 1)
local framehandle groupframe = BlzFrameGetChild(bottomUI, 5)
local framehandle buttonContainer
//globals
set containerFrame = BlzFrameGetChild(groupframe, 0)
set Group = CreateGroup()
// give this frames a handleId
loop
exitwhen i >= BlzFrameGetChildrenCount(containerFrame) - 1
set buttonContainer = BlzFrameGetChild(containerFrame, i)
set frames[i] = BlzFrameGetChild(buttonContainer, 0)
set i = i + 1
endloop
call DestroyTimer(GetExpiredTimer())
endfunction
private function init_function takes nothing returns nothing
set filter = Filter(function FilterFunction)
call TimerStart(CreateTimer(), 0, false, function init_functionAt0s)
call TriggerRegisterGameEvent(LoadBugTrigger, EVENT_GAME_LOADED)
call TriggerAddAction(LoadBugTrigger, function init_functionAt0s)
endfunction
endlibrary
library GetMainSelectedUnitForPlayer initializer Init requires GetMainSelectedUnit
globals
public constant real SYNC_INTERVAL = 0.01
private trigger syncTrigger = CreateTrigger()
private integer array syncGetSelectedUnitIndex
endglobals
private function TriggerConditionSync takes nothing returns boolean
if (BlzGetTriggerSyncPrefix() == "GetSelectedUnitIndex") then
set syncGetSelectedUnitIndex[GetPlayerId(GetTriggerPlayer())] = S2I(BlzGetTriggerSyncData())
endif
return false
endfunction
function GetSelectedUnitIndexForPlayer takes player whichPlayer returns integer
return syncGetSelectedUnitIndex[GetPlayerId(whichPlayer)]
endfunction
function GetMainSelectedUnitForPlayer takes player whichPlayer returns unit
return GetMainSelectedUnit(whichPlayer, GetSelectedUnitIndexForPlayer(whichPlayer))
endfunction
private function TimerFunctionSync takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
if (GetLocalPlayer() == Player(i)) then
call BlzSendSyncData("GetSelectedUnitIndex", I2S(GetSelectedUnitIndex()))
endif
set i = i + 1
endloop
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
call TriggerRegisterPlayerEvent(syncTrigger, Player(i), EVENT_PLAYER_SYNC_DATA)
set syncGetSelectedUnitIndex[i] = -1
set i = i + 1
endloop
call TriggerAddCondition(syncTrigger, Condition(function TriggerConditionSync))
call TimerStart(CreateTimer(), SYNC_INTERVAL, true, function TimerFunctionSync)
endfunction
endlibrary
library UnitSoundSets initializer Init requires GetMainSelectedUnitForPlayer, optional UnitSoundSetsFakeBars, optional UnitSoundSetsPerUnit
/**
* Baradé's Unit Sound Sets 1.0
*
* Allows using custom unit sound sets without replacing existing ones or using a custom SLK file.
*
* Usage:
* - Disable the sound set of your unit type and then register the sounds using this system.
* - Import custom soundset files into your map.
* - Call this JASS code during the map initialization:
* call AddUnitSoundSetFromFiles('H0F2', "war3Imported\\HeroPaladin")
*
* 'H0F2' should be the raw code of your custom hero unit type.
* "war3Imported\\HeroPaladin" should be the prefix for all unit sound set files.
* The extensions "mp3", "flac" and "wav" are used automatically.
* You can use the JASS function AddUnitSoundSetFromFilesEx if you want to specify the exact extension.
*
* - Optional: If you have shop buildings which should play custom sounds when selected by other
* players, use the following JASS code to register them:
* call AddUnitShopSoundSet('ngme')
*
* Replace the raw code with the one of your shop building type.
*
* The following suffixes for sound files are supported:
* Death1
* What1
* What2
* What3
* What4
* What5
* What6
* What7
* What8
* What9
* Yes1
* Yes2
* Yes3
* Yes4
* Yes5
* Yes6
* Yes7
* Yes8
* Yes9
* YesAttack1
* YesAttack2
* YesAttack3
* YesAttack4
* YesAttack5
* YesAttack6
* YesAttack7
* YesAttack8
* YesAttack9
* Ready1
* WarCry1
* Pissed1
* Pissed2
* Pissed3
* Pissed4
* Pissed5
* Pissed6
* Pissed7
* Pissed8
* Pissed9
*
* Disable cinematic sub titles with ForceCinematicSubtitles or in the game settings.
* Selecting the same unit again will not play the next sound immediately but wait for the current sound
* to be finished. Selecting another unit will immediately play the sound of the other unit. This seems to be
* Warcraft's behavior.
*/
globals
// You will hear the pissed sounds after this number of clicks on the same unit.
constant integer PISSED_COUNTER = 3
// Percentage chance to play the Warcry sound when attacking a hero.
constant integer WARCRY_CHANCE = 20
// Death : Whenver the unit dies, the Death Sound will be played.
constant integer SOUND_DEATH_1 = 0
// What : Occurs when you click on the unit only. Replaced by Pissed Sounds if you click multiple times on the unit in a short time.
constant integer SOUND_WHAT_1 = 1
constant integer SOUND_WHAT_2 = 2
constant integer SOUND_WHAT_3 = 3
constant integer SOUND_WHAT_4 = 4
constant integer SOUND_WHAT_5 = 5
constant integer SOUND_WHAT_6 = 6
constant integer SOUND_WHAT_7 = 7
constant integer SOUND_WHAT_8 = 8
constant integer SOUND_WHAT_9 = 9
// Yes : Occurs when you order the unit to do a "Friendly" Action.
constant integer SOUND_YES_1 = 10
constant integer SOUND_YES_2 = 11
constant integer SOUND_YES_3 = 12
constant integer SOUND_YES_4 = 13
constant integer SOUND_YES_5 = 14
constant integer SOUND_YES_6 = 15
constant integer SOUND_YES_7 = 16
constant integer SOUND_YES_8 = 17
constant integer SOUND_YES_9 = 18
// YesAttack : Occurs when you order the unit to "Attack-Move", or an order similar to it.
constant integer SOUND_YES_ATTACK_1 = 19
constant integer SOUND_YES_ATTACK_2 = 20
constant integer SOUND_YES_ATTACK_3 = 21
constant integer SOUND_YES_ATTACK_4 = 22
constant integer SOUND_YES_ATTACK_5 = 23
constant integer SOUND_YES_ATTACK_6 = 24
constant integer SOUND_YES_ATTACK_7 = 25
constant integer SOUND_YES_ATTACK_8 = 26
constant integer SOUND_YES_ATTACK_9 = 27
// Warcry : Occurs when you order the unit to attack a specific unit.
constant integer SOUND_WARCRY_1 = 28
// Ready : Occurs only one time for a single unit, it is played when the unit is spawned by a building (Example : Barracks for Rifleman), or when they got revived by an Altar (Example : Paladin).
constant integer SOUND_READY_1 = 29
// Pissed : When you click a lot of times on the unit, weird sounds will be played instead of normals, which are called Pissed Sounds.
constant integer SOUND_PISSED_1 = 30
constant integer SOUND_PISSED_2 = 31
constant integer SOUND_PISSED_3 = 32
constant integer SOUND_PISSED_4 = 33
constant integer SOUND_PISSED_5 = 34
constant integer SOUND_PISSED_6 = 35
constant integer SOUND_PISSED_7 = 36
constant integer SOUND_PISSED_8 = 37
constant integer SOUND_PISSED_9 = 38
// Attack : Occurs when the unit starts attacking an enemy. (You don't have to click on the unit)
constant integer MAX_SOUND_CATEGORIES = 39
constant integer KEY_HAS_CUSTOM_SOUNDSET = 39
constant integer KEY_HAS_SHOP_SOUNDSET = 40
constant integer KEY_LAST_PLAYED_SOUND = 41
private constant integer ORDER_ID_ATTACK = 851983
private constant integer ORDER_ID_ATTACK_GROUND = 851984
private constant integer ORDER_ID_ATTACK_ONCE = 851985
private constant integer ORDER_ID_MOVE = 851986
private constant integer ORDER_ID_PATROL = 851990
private constant integer ORDER_ID_SMART = 851971
// for unit type IDs
private hashtable h = InitHashtable()
// for handle IDs
private hashtable h2 = InitHashtable()
// all this exists for the local player only and is never synchronized between players
private integer array playerClickCounter
private unit array playerClickTarget
private sound array playerSound
private timer array playerSoundTimer
private unit array playerSpeaker
private trigger selectionTrigger = CreateTrigger()
private trigger deselectionTrigger = CreateTrigger()
private trigger orderTrigger = CreateTrigger()
private trigger revivalTrigger = CreateTrigger()
private trigger trainTrigger = CreateTrigger()
private trigger hireTrigger = CreateTrigger()
private trigger deathTrigger = CreateTrigger()
// avoid reference leaks
private force allies = CreateForce()
private integer soundsCounter = 0
private sound array sounds
endglobals
private function IsUnitMainSelectedUnitForPlayer takes unit whichUnit, player whichPlayer returns boolean
local unit mainSelected = GetMainSelectedUnitForPlayer(whichPlayer)
//call BJDebugMsg("Main selected " + GetUnitName(mainSelected))
return (mainSelected != null and mainSelected == whichUnit) or (mainSelected == null and IsUnitSelected(whichUnit, whichPlayer))
endfunction
function RemoveAllUnitSoundSets takes nothing returns nothing
call FlushParentHashtable(h)
endfunction
function RemoveUnitSoundSet takes integer unitTypeId returns nothing
call FlushChildHashtable(h, unitTypeId)
endfunction
function AddUnitSoundSet takes integer unitTypeId, integer soundType, sound whichSound returns nothing
if (whichSound != null) then
call SaveSoundHandle(h, unitTypeId, soundType, whichSound)
call SaveBoolean(h, unitTypeId, KEY_HAS_CUSTOM_SOUNDSET, true)
endif
endfunction
function HasUnitSoundSet takes integer unitTypeId returns boolean
return LoadBoolean(h, unitTypeId, KEY_HAS_CUSTOM_SOUNDSET)
endfunction
private function CreateSoundFromFile takes string filePath, string eaxSetting returns sound
local sound soundHandle = null
local integer duration = GetSoundFileDuration(filePath)
// the duration should be 0 if the file does not exist
if (duration > 0) then
set soundHandle = CreateSound(filePath, false, false, true, 12700, 12700, eaxSetting)
//call SetSoundChannel(soundHandle, 1) // SOUND_VOLUMEGROUP_UNITSOUNDS
call SetSoundDuration(soundHandle, duration)
//call SetSoundVolume(soundHandle, 127)
//else
//call BJDebugMsg("Missing sound file " + filePath)
endif
return soundHandle
endfunction
function AddUnitSoundSetFromFilesType takes integer unitTypeId, string filePath, string extension, integer start, integer max, string prefix, string eaxSetting returns nothing
local integer i = 0
loop
exitwhen (start >= max)
call AddUnitSoundSet(unitTypeId, start, CreateSoundFromFile(filePath + prefix + I2S(i) + "." + extension, eaxSetting))
set start = start + 1
set i = i + 1
endloop
endfunction
function AddUnitSoundSetFromFilesEx takes integer unitTypeId, string filePath, string extension returns nothing
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, 0, SOUND_WHAT_1, "Death", "DefaultEAXON")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_WHAT_1, SOUND_YES_1, "What", "HeroAcksEAX")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_YES_1, SOUND_YES_ATTACK_1, "Yes", "HeroAcksEAX")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_YES_ATTACK_1, SOUND_WARCRY_1, "YesAttack", "HeroAcksEAX")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_WARCRY_1, SOUND_READY_1, "WarCry", "HeroAcksEAX")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_READY_1, SOUND_PISSED_1, "Ready", "HeroAcksEAX")
call AddUnitSoundSetFromFilesType(unitTypeId, filePath, extension, SOUND_PISSED_1, MAX_SOUND_CATEGORIES, "Pissed", "HeroAcksEAX")
endfunction
function AddUnitSoundSetFromFiles takes integer unitTypeId, string filePath returns nothing
call AddUnitSoundSetFromFilesEx(unitTypeId, filePath, "mp3")
call AddUnitSoundSetFromFilesEx(unitTypeId, filePath, "flac")
call AddUnitSoundSetFromFilesEx(unitTypeId, filePath, "wav")
endfunction
function HasUnitShopSoundSet takes integer unitTypeId returns boolean
return LoadBoolean(h, unitTypeId, KEY_HAS_SHOP_SOUNDSET)
endfunction
function AddUnitShopSoundSet takes integer unitTypeId returns nothing
call SaveBoolean(h, unitTypeId, KEY_HAS_SHOP_SOUNDSET, true)
endfunction
function RemoveUnitShopSoundSet takes integer unitTypeId returns nothing
call SaveBoolean(h, unitTypeId, KEY_HAS_SHOP_SOUNDSET, false)
endfunction
function GetUnitSoundSetLastPlayedSound takes integer unitTypeId returns sound
return LoadSoundHandle(h, unitTypeId, KEY_LAST_PLAYED_SOUND)
endfunction
function SetUnitSoundSetLastPlayedSound takes integer unitTypeId, sound whichSound returns nothing
call SaveSoundHandle(h, unitTypeId, KEY_LAST_PLAYED_SOUND, whichSound)
endfunction
private function HasControl takes player whichPlayer, unit whichUnit returns boolean
return GetOwningPlayer(whichUnit) == whichPlayer or GetPlayerAlliance(whichPlayer, GetOwningPlayer(whichUnit), ALLIANCE_SHARED_CONTROL)
endfunction
private function AlliesWithSharedControl takes player whichPlayer returns force
local integer i = 0
call ForceClear(allies)
loop
exitwhen (i == bj_MAX_PLAYERS)
if (whichPlayer == Player(i) or GetPlayerAlliance(whichPlayer, Player(i), ALLIANCE_SHARED_CONTROL)) then
call ForceAddPlayer(allies, Player(i))
endif
set i = i + 1
endloop
return allies
endfunction
private function IsUnitSpeakingForPlayer takes unit whichUnit, player whichPlayer returns boolean
local integer playerId = GetPlayerId(whichPlayer)
local boolean sameUnit = playerSpeaker[playerId] == whichUnit
return sameUnit and playerSound[playerId] != null and TimerGetRemaining(playerSoundTimer[playerId]) > 0.0 // This would desync: GetSoundIsPlaying(playerSound[playerId])
endfunction
private function UpdatePlayerSound takes player whichPlayer, sound whichSound, unit whichUnit returns boolean
local integer playerId = GetPlayerId(whichPlayer)
// only update if it is a different speaker or the current unit is not speaking
if (playerSpeaker[playerId] == whichUnit and IsUnitSpeakingForPlayer(playerSpeaker[playerId], whichPlayer)) then
return false
endif
set playerSound[playerId] = whichSound
set playerSpeaker[playerId] = whichUnit
call SetUnitSoundSetLastPlayedSound(GetUnitTypeId(whichUnit), whichSound)
call TimerStart(playerSoundTimer[playerId], GetSoundDurationBJ(whichSound), false, null)
if (GetLocalPlayer() == whichPlayer) then
call StartSound(whichSound)
endif
return true
endfunction
private function GetRandomSoundEx takes player whichPlayer, unit whichUnit, integer soundTypeFirst, integer soundTypeLast returns sound
local integer playerId = GetPlayerId(whichPlayer)
local integer unitTypeId = GetUnitTypeId(whichUnit)
local integer speakerUnitTypeId = GetUnitTypeId(playerSpeaker[playerId])
local sound lastPlayedSound = GetUnitSoundSetLastPlayedSound(unitTypeId)
local sound whichSound = null
set soundsCounter = 0
loop
exitwhen (soundTypeFirst > soundTypeLast)
static if (LIBRARY_UnitSoundSetsPerUnit) then
set whichSound = GetUnitSoundSetPerUnit(whichUnit, soundTypeFirst)
if (whichSound == null) then
set whichSound = LoadSoundHandle(h, GetUnitTypeId(whichUnit), soundTypeFirst)
endif
else
set whichSound = LoadSoundHandle(h, GetUnitTypeId(whichUnit), soundTypeFirst)
endif
// never play the same sound twice if there are multiple sounds
if (whichSound != null and whichSound != lastPlayedSound) then
//call BJDebugMsg("Last played sound ID " + I2S(GetHandleId(lastPlayedSound)) + " and current sound ID " + I2S(GetHandleId(whichSound)) + " for unit type " + GetObjectName(unitTypeId))
set sounds[soundsCounter] = whichSound
set soundsCounter = soundsCounter + 1
endif
set soundTypeFirst = soundTypeFirst + 1
endloop
if (soundsCounter > 0) then
return sounds[GetRandomInt(0, soundsCounter - 1)]
endif
return null
endfunction
private function GetSingleSound takes unit whichUnit, integer soundType returns sound
static if (LIBRARY_UnitSoundSetsPerUnit) then
if (GetUnitSoundSetPerUnit(whichUnit, soundType) == null) then
return LoadSoundHandle(h, GetUnitTypeId(whichUnit), soundType)
else
return GetUnitSoundSetPerUnit(whichUnit, soundType)
endif
else
return LoadSoundHandle(h, GetUnitTypeId(whichUnit), soundType)
endif
endfunction
private function GetRandomSound takes player whichPlayer, unit whichUnit, integer soundTypeFirst, integer soundTypeLast returns sound
if (soundTypeFirst == soundTypeLast) then
return GetSingleSound(whichUnit, soundTypeFirst)
endif
return GetRandomSoundEx(whichPlayer, whichUnit, soundTypeFirst, soundTypeLast)
endfunction
private function UpdatePlayerSelect takes player whichPlayer, unit whichUnit returns nothing
local integer playerId = GetPlayerId(whichPlayer)
if (playerClickTarget[playerId] == whichUnit) then
set playerClickCounter[playerId] = playerClickCounter[playerId] + 1
else
set playerClickCounter[playerId] = 1
endif
set playerClickTarget[playerId] = whichUnit
endfunction
private function IsPlayerSelectionPissed takes player whichPlayer, unit whichUnit returns boolean
local integer playerId = GetPlayerId(whichPlayer)
return playerClickTarget[playerId] == whichUnit and playerClickCounter[playerId] > PISSED_COUNTER
endfunction
private function GetUnitPlayerColor takes player whichPlayer, unit whichUnit returns playercolor
local integer filterState = GetAllyColorFilterState()
if (filterState == 2) then // mode 3
if (GetOwningPlayer(whichUnit) == whichPlayer) then
return PLAYER_COLOR_BLUE
elseif (IsUnitAlly(whichUnit, whichPlayer)) then
return PLAYER_COLOR_TURQUOISE
else
return PLAYER_COLOR_RED
endif
endif
return GetPlayerColor(GetOwningPlayer(whichUnit))
endfunction
private function PortraitAnimation takes player whichPlayer, unit whichUnit, sound whichSound returns nothing
local integer unitTypeId = GetUnitTypeId(whichUnit)
if (GetLocalPlayer() == whichPlayer) then
call SetCinematicScene(unitTypeId, GetUnitPlayerColor(whichPlayer, whichUnit), null, null, GetSoundDurationBJ(whichSound), GetSoundDurationBJ(whichSound))
endif
static if (LIBRARY_UnitSoundSetsFakeBars) then
call CinematicSceneFakeBars(whichPlayer, whichSound)
endif
endfunction
private function PlayRandomSound takes player whichPlayer, unit whichUnit, integer soundTypeFirst, integer soundTypeLast returns nothing
local sound whichSound = GetRandomSound(whichPlayer, whichUnit, soundTypeFirst, soundTypeLast)
if (whichSound != null) then
if (UpdatePlayerSound(whichPlayer, whichSound, whichUnit)) then
if (soundTypeFirst == SOUND_WHAT_1) then
call UpdatePlayerSelect(whichPlayer, whichUnit)
endif
if (IsUnitSelected(whichUnit, whichPlayer)) then
call PortraitAnimation(whichPlayer, whichUnit, whichSound)
endif
endif
set whichSound = null
// update selected unit for pissed even if it has no sound
elseif (soundTypeFirst == SOUND_WHAT_1) then
call UpdatePlayerSelect(whichPlayer, whichUnit)
endif
endfunction
private function PlaySingleSound takes player whichPlayer, unit whichUnit, integer soundType returns nothing
local sound whichSound = GetSingleSound(whichUnit, soundType)
if (whichSound != null) then
if (UpdatePlayerSound(whichPlayer, whichSound, whichUnit)) then
if (soundType == SOUND_WHAT_1) then
call UpdatePlayerSelect(whichPlayer, whichUnit)
endif
if (IsUnitSelected(whichUnit, whichPlayer)) then
call PortraitAnimation(whichPlayer, whichUnit, whichSound)
endif
endif
set whichSound = null
// update selected unit for pissed even if it has no sound
elseif (soundType == SOUND_WHAT_1) then
call UpdatePlayerSelect(whichPlayer, whichUnit)
endif
endfunction
private function PlaySingleSoundForForce takes force whichForce, unit whichUnit, integer soundType returns nothing
local player slotPlayer = null
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
set slotPlayer = Player(i)
if (IsPlayerInForce(slotPlayer, whichForce)) then
call PlaySingleSound(slotPlayer, whichUnit, soundType)
endif
set slotPlayer = null
set i = i + 1
endloop
endfunction
function PlaySingleSoundForAlliesWithSharedControl takes unit whichUnit, integer soundType returns nothing
call PlaySingleSoundForForce(AlliesWithSharedControl(GetOwningPlayer(whichUnit)), whichUnit, soundType)
endfunction
private function StopUnitSound takes player whichPlayer, unit whichUnit returns nothing
// the death sound will stop any currently played sound from the unit
if (IsUnitSpeakingForPlayer(whichUnit, whichPlayer)) then
if (GetLocalPlayer() == whichPlayer) then
call StopSound(playerSound[GetPlayerId(whichPlayer)], false, false)
endif
endif
endfunction
private function PlayRandom3DDeathSound takes unit whichUnit returns nothing
local sound soundHandle = GetSingleSound(whichUnit, SOUND_DEATH_1)
if (soundHandle != null) then
call StartSound(soundHandle)
call AttachSoundToUnit(soundHandle, whichUnit)
set soundHandle = null
endif
endfunction
private function TimerFunctionSelect takes nothing returns nothing
local timer expiredTimer = GetExpiredTimer()
local integer handleId = GetHandleId(expiredTimer)
local unit triggerUnit = LoadUnitHandle(h2, handleId, 0)
local player triggerPlayer = LoadPlayerHandle(h2, handleId, 1)
local boolean hasControl = HasControl(triggerPlayer, triggerUnit) or HasUnitShopSoundSet(GetUnitTypeId(triggerUnit)) // don't do this in async code
if (hasControl and IsUnitMainSelectedUnitForPlayer(triggerUnit, triggerPlayer)) then
if (IsPlayerSelectionPissed(triggerPlayer, triggerUnit)) then // do this in async code to get if it is pissed for the local player
call PlayRandomSound(triggerPlayer, triggerUnit, SOUND_PISSED_1, SOUND_PISSED_9)
else
call PlayRandomSound(triggerPlayer, triggerUnit, SOUND_WHAT_1, SOUND_WHAT_9)
endif
endif
set triggerUnit = null
set triggerPlayer = null
call FlushChildHashtable(h, handleId)
call PauseTimer(expiredTimer)
call DestroyTimer(expiredTimer)
set expiredTimer = null
endfunction
private function TriggerActionSelect takes nothing returns nothing
local timer whichTimer = CreateTimer()
local integer handleId = GetHandleId(whichTimer)
call SaveUnitHandle(h2, handleId, 0, GetTriggerUnit())
call SavePlayerHandle(h2, handleId, 1, GetTriggerPlayer())
// some delay to determine the main selected unit
call TimerStart(whichTimer, 0.0, false, function TimerFunctionSelect)
endfunction
private function EndUnitTalkPortrait takes player whichPlayer, unit whichUnit returns nothing
local integer unitTypeId = GetUnitTypeId(whichUnit)
local integer playerId = GetPlayerId(whichPlayer)
if (HasUnitSoundSet(GetUnitTypeId(whichUnit)) and playerSpeaker[playerId] == whichUnit) then
if (GetLocalPlayer() == whichPlayer) then
// Do not end talk animations for native sound sets.
// TODO Deslecting a unit with custom sound set and selecting a unit with a native sound set seems to stop the talk animation because of this.
call EndCinematicScene()
endif
static if (LIBRARY_UnitSoundSetsFakeBars) then
call HideCinematicSceneFakeBars(whichPlayer)
endif
endif
endfunction
private function TriggerConditionDeselect takes nothing returns boolean
call EndUnitTalkPortrait(GetTriggerPlayer(), GetTriggerUnit())
return false
endfunction
// GetMainSelectedUnitForPlayer can only be used in a trigger action not trigger condition
private function TriggerActionOrder takes nothing returns nothing
local unit triggerUnit = GetTriggerUnit()
local integer orderId = GetIssuedOrderId()
local player slotPlayer = null
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
set slotPlayer = Player(i)
if (HasControl(slotPlayer, triggerUnit) and IsUnitMainSelectedUnitForPlayer(triggerUnit, slotPlayer)) then // TODO get the ordering player with some new native.
//call BJDebugMsg("Ordering selected " + GetUnitName(triggerUnit) + " for player " + GetPlayerName(GetLocalPlayer()) + " with order ID " + I2S(orderId) + " and order name " + OrderId2String(orderId))
// attack orders (smart order is used against creeps)
if (orderId == ORDER_ID_ATTACK or orderId == ORDER_ID_ATTACK_ONCE or (orderId == ORDER_ID_SMART and GetOrderTargetUnit() != null and IsUnitEnemy(GetOrderTargetUnit(), slotPlayer))) then
if (IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_HERO)) then
if (GetRandomInt(0, 100) <= WARCRY_CHANCE) then // chance for Warcry if the target is a hero no matter if it is an enemy or not
call PlaySingleSound(slotPlayer, triggerUnit, SOUND_WARCRY_1)
else
call PlayRandomSound(slotPlayer, triggerUnit, SOUND_YES_ATTACK_1, SOUND_YES_ATTACK_9)
endif
else
call PlayRandomSound(slotPlayer, triggerUnit, SOUND_YES_ATTACK_1, SOUND_YES_ATTACK_9)
endif
// TODO what about attack orders to non-enemy units.
// move orders
elseif (orderId == ORDER_ID_MOVE or orderId == ORDER_ID_PATROL or orderId == ORDER_ID_SMART or orderId == ORDER_ID_ATTACK_GROUND) then
call PlayRandomSound(slotPlayer, triggerUnit, SOUND_YES_1, SOUND_YES_9)
endif
endif
set slotPlayer = null
set i = i + 1
endloop
set triggerUnit = null
endfunction
private function TriggerConditionReviveFinish takes nothing returns boolean
call PlaySingleSoundForAlliesWithSharedControl(GetRevivingUnit(), SOUND_READY_1)
return false
endfunction
private function TriggerConditionTrainFinish takes nothing returns boolean
call PlaySingleSoundForAlliesWithSharedControl(GetRevivingUnit(), SOUND_READY_1)
return false
endfunction
private function TriggerConditionHire takes nothing returns boolean
call PlaySingleSoundForAlliesWithSharedControl(GetRevivingUnit(), SOUND_READY_1)
return false
endfunction
private function TriggerConditionDeath takes nothing returns boolean
local unit triggerUnit = GetDyingUnit()
local force whichForce = AlliesWithSharedControl(GetOwningPlayer(triggerUnit))
local player slotPlayer = null
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
set slotPlayer = Player(i)
if (IsPlayerInForce(slotPlayer, whichForce)) then
call EndUnitTalkPortrait(slotPlayer, triggerUnit)
endif
set slotPlayer = null
set i = i + 1
endloop
call StopUnitSound(GetOwningPlayer(triggerUnit), triggerUnit)
call PlayRandom3DDeathSound(triggerUnit)
set triggerUnit = null
return false
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
if (GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
set playerSoundTimer[i] = CreateTimer()
call TriggerRegisterPlayerUnitEvent(selectionTrigger, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
call TriggerRegisterPlayerUnitEvent(deselectionTrigger, Player(i), EVENT_PLAYER_UNIT_DESELECTED, null)
endif
set i = i + 1
endloop
call TriggerAddAction(selectionTrigger, function TriggerActionSelect)
call TriggerAddCondition(deselectionTrigger, Condition(function TriggerConditionDeselect))
call TriggerRegisterAnyUnitEventBJ(orderTrigger, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(orderTrigger, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(orderTrigger, EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER)
call TriggerRegisterAnyUnitEventBJ(orderTrigger, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddAction(orderTrigger, function TriggerActionOrder)
call TriggerRegisterAnyUnitEventBJ(revivalTrigger, EVENT_PLAYER_HERO_REVIVE_FINISH)
call TriggerAddCondition(revivalTrigger, Condition(function TriggerConditionReviveFinish))
call TriggerRegisterAnyUnitEventBJ(trainTrigger, EVENT_PLAYER_UNIT_TRAIN_FINISH)
call TriggerAddCondition(trainTrigger, Condition(function TriggerConditionTrainFinish))
call TriggerRegisterAnyUnitEventBJ(hireTrigger, EVENT_PLAYER_UNIT_SELL)
call TriggerAddCondition(hireTrigger, Condition(function TriggerConditionHire))
call TriggerRegisterAnyUnitEventBJ(deathTrigger, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(deathTrigger, Condition(function TriggerConditionDeath))
endfunction
endlibrary
library UnitSoundSetsFakeBars initializer Init requires GetMainSelectedUnitForPlayer
globals
// Timer interval in which the HP and mana of the fake text frames is updated.
public constant real UPDATE_INTERVAL = 0.01
// Hides the HP and mana text if it is longer than this.
public constant integer FAKE_BAR_CHARACTERS_LIMIT = 11
public constant boolean HIDE_HP_INVULNERABLE_STRUCTURE = true
public constant real FAKE_BAR_X = 0.2135
public constant real FAKE_HP_BAR_Y = 0.0275
public constant real FAKE_MANA_BAR_Y = 0.0135
public constant real FAKE_BAR_WIDTH = 0.08
public constant real FAKE_BAR_HEIGHT = 0.05
public constant real FAKE_BAR_TEXT_SCALE = 1.16
private framehandle playerHP = null
private framehandle playerMana = null
private timer array playerAnimationTimer
private timer array playerUpdateCinematicSceneBarsTimer
private trigger gameLoadedTrigger = CreateTrigger()
// for handle IDs
private hashtable h2 = InitHashtable()
endglobals
function HideCinematicSceneFakeBars takes player whichPlayer returns nothing
if (GetLocalPlayer() == whichPlayer) then
call BlzFrameSetVisible(playerHP, false)
call BlzFrameSetVisible(playerMana, false)
endif
endfunction
private function TimerFunctionEndCinematicSceneBars takes nothing returns nothing
local integer playerId = LoadInteger(h2, GetHandleId(GetExpiredTimer()), 0)
if (GetLocalPlayer() == Player(playerId)) then
call BlzFrameSetVisible(playerHP, false)
call BlzFrameSetVisible(playerMana, false)
call EndCinematicScene()
endif
call PauseTimer(playerUpdateCinematicSceneBarsTimer[playerId])
endfunction
// Does not divide by 100.
private function GetUniLifePercent takes real value, real maxValue returns real
// Return 0 for null units.
if (maxValue == 0) then
return 0.0
endif
return value / maxValue
endfunction
private function I2X takes integer int returns string
local string hexas = "0123456789abcdef"
local string hex = ""
local integer dev
loop
if int > 15 then
set dev = int - (int / 16) * 16
set int = int / 16
set hex = SubString(hexas, dev, dev + 1) + hex
else
set hex = SubString(hexas, int, int + 1) + hex
return hex
endif
endloop
return hex
endfunction
private function I2XW takes integer int, integer width returns string
local string hex = I2X(int)
local integer i = StringLength(hex)
loop
exitwhen (i >= width)
set hex = "0" + hex
set i = i + 1
endloop
return hex
endfunction
private function GetHPTextEx takes real life, real maxLife returns string
local real lifePercent = GetUniLifePercent(life, maxLife)
local integer red = 255
local integer green = 255
local string lifeStr = I2S(R2I(life))
local string maxLifeStr = I2S(R2I(maxLife))
local integer lifeTextLength = StringLength(lifeStr)
local integer fullTextLength = lifeTextLength + StringLength(maxLifeStr) + 3 // / and the two spaces
if (lifePercent > 0.6) then
/*
BYTE2(v53) = (signed int)(255.0 - ((lifePercent - 0.5) * 255.0 + (lifePercent - 0.5) * 255.0));
y = 255 - ((x - 0.5) * 255 + (x - 0.5) * 255)
y = 255 - 255 * ((x - 0.5) + (x - 0.5))
y = 255 - 255 * (x - 0.5 + x - 0.5)
y = 255 - 255 * (2x - 1)
y = 255 - (510x - 255)
y = 255 - 510x + 255
y = 510 - 510x
*/
set red = R2I(510 - 510 * lifePercent)
elseif (lifePercent > 0.3) then
set green = R2I(lifePercent / 0.6 * 255.0)
else
set green = R2I(lifePercent / 0.8 * 255.0)
endif
// show nothing
if (lifeTextLength > FAKE_BAR_CHARACTERS_LIMIT) then
return ""
// only show life without maximum life
elseif (fullTextLength > FAKE_BAR_CHARACTERS_LIMIT) then
return "|cff" + I2XW(red, 2) + I2XW(green, 2) + "00" + lifeStr + "|r"
endif
return "|cff" + I2XW(red, 2) + I2XW(green, 2) + "00" + lifeStr + " / " + maxLifeStr + "|r"
endfunction
private function GetHPText takes unit whichUnit returns string
if (HIDE_HP_INVULNERABLE_STRUCTURE and IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE) and GetUnitAbilityLevel(whichUnit, 'Avul') > 0) then
return ""
endif
return GetHPTextEx(GetUnitState(whichUnit, UNIT_STATE_LIFE), GetUnitState(whichUnit, UNIT_STATE_MAX_LIFE))
endfunction
private function GetManaTextEx takes real mana, real maxMana returns string
local string manaStr = I2S(R2I(mana))
local string maxManaStr = I2S(R2I(maxMana))
local integer manaTextLength = StringLength(manaStr)
local integer fullTextLength = manaTextLength + StringLength(maxManaStr) + 3 // / and the two spaces
// show nothing
if (manaTextLength > FAKE_BAR_CHARACTERS_LIMIT) then
return ""
// only show mana without maximum mana
elseif (fullTextLength > FAKE_BAR_CHARACTERS_LIMIT) then
return "|cffc3dbff" + manaStr + "|r"
endif
return "|cffc3dbff" + manaStr + " / " + maxManaStr + "|r"
endfunction
private function GetManaText takes unit whichUnit returns string
return GetManaTextEx(GetUnitState(whichUnit, UNIT_STATE_MANA), GetUnitState(whichUnit, UNIT_STATE_MAX_MANA))
endfunction
// Use with GetLocalPlayer() only.
private function UpdateCinematicSceneFakeBars takes nothing returns nothing
local unit selected = GetMainSelectedUnitEx()
if (selected == null) then
call BlzFrameSetVisible(playerHP, false)
call BlzFrameSetVisible(playerMana, false)
else
if (GetUnitState(selected, UNIT_STATE_MAX_LIFE) > 0.0) then
call BlzFrameSetVisible(playerHP, true)
call BlzFrameSetText(playerHP, GetHPText(selected))
else
call BlzFrameSetVisible(playerHP, false)
endif
if (GetUnitState(selected, UNIT_STATE_MAX_MANA) > 0.0) then
call BlzFrameSetVisible(playerMana, true)
call BlzFrameSetText(playerMana, GetManaText(selected))
else
call BlzFrameSetVisible(playerMana, false)
endif
endif
endfunction
private function TimerFunctionUpdateCinematicSceneBars takes nothing returns nothing
local integer playerId = LoadInteger(h2, GetHandleId(GetExpiredTimer()), 0)
local unit selected = null
if (GetLocalPlayer() == Player(playerId)) then
call UpdateCinematicSceneFakeBars()
endif
endfunction
function CinematicSceneFakeBars takes player whichPlayer, sound whichSound returns nothing
local integer playerId = GetPlayerId(whichPlayer)
if (GetLocalPlayer() == whichPlayer) then
call BlzFrameSetVisible(playerHP, true)
call BlzFrameSetVisible(playerMana, true)
call UpdateCinematicSceneFakeBars()
endif
call PauseTimer(playerAnimationTimer[playerId])
call SaveInteger(h2, GetHandleId(playerAnimationTimer[playerId]), 0, playerId)
call TimerStart(playerAnimationTimer[playerId], GetSoundDurationBJ(whichSound), false, function TimerFunctionEndCinematicSceneBars)
call SaveInteger(h2, GetHandleId(playerUpdateCinematicSceneBarsTimer[playerId]), 0, playerId)
call TimerStart(playerUpdateCinematicSceneBarsTimer[playerId], UPDATE_INTERVAL, true, function TimerFunctionUpdateCinematicSceneBars)
endfunction
private function TimerFunctionCreatePlayerPortraits takes nothing returns nothing
set playerHP = BlzCreateFrameByType("Text", "HP", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
call BlzFrameSetAbsPoint(playerHP, FRAMEPOINT_TOPLEFT, FAKE_BAR_X, FAKE_HP_BAR_Y)
call BlzFrameSetAbsPoint(playerHP, FRAMEPOINT_BOTTOMRIGHT, FAKE_BAR_X + FAKE_BAR_WIDTH, FAKE_HP_BAR_Y - FAKE_BAR_HEIGHT)
call BlzFrameSetScale(playerHP, FAKE_BAR_TEXT_SCALE)
call BlzFrameSetTextAlignment(playerHP, TEXT_JUSTIFY_TOP, TEXT_JUSTIFY_CENTER)
call BlzFrameSetVisible(playerHP, false)
set playerMana = BlzCreateFrameByType("Text", "Mana", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
call BlzFrameSetAbsPoint(playerMana, FRAMEPOINT_TOPLEFT, FAKE_BAR_X, FAKE_MANA_BAR_Y)
call BlzFrameSetAbsPoint(playerMana, FRAMEPOINT_BOTTOMRIGHT, FAKE_BAR_X + FAKE_BAR_WIDTH, FAKE_MANA_BAR_Y - FAKE_BAR_HEIGHT)
call BlzFrameSetScale(playerMana, FAKE_BAR_TEXT_SCALE)
call BlzFrameSetTextAlignment(playerMana, TEXT_JUSTIFY_TOP, TEXT_JUSTIFY_CENTER)
call BlzFrameSetVisible(playerMana, false)
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endfunction
private function TriggerConditionGameLoaded takes nothing returns boolean
call TimerStart(CreateTimer(), 0.0, false, function TimerFunctionCreatePlayerPortraits)
return false
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
if (GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
set playerAnimationTimer[i] = CreateTimer()
set playerUpdateCinematicSceneBarsTimer[i] = CreateTimer()
endif
set i = i + 1
endloop
call TriggerRegisterGameEvent(gameLoadedTrigger, EVENT_GAME_LOADED)
call TriggerAddCondition(gameLoadedTrigger, Condition(function TriggerConditionGameLoaded))
call TimerStart(CreateTimer(), 0.0, false, function TimerFunctionCreatePlayerPortraits)
endfunction
endlibrary
library UnitSoundSetsPerUnit
/**
* Extension for Baradé's Unit Sound Sets
*
* Allows registering sound sets per unit instead of only per unit type.
*/
globals
private hashtable h = InitHashtable()
endglobals
function RemoveAllUnitSoundSetsPerUnit takes nothing returns nothing
call FlushParentHashtable(h)
endfunction
function RemoveUnitSoundSetPerUnit takes unit whichUnit returns nothing
call FlushChildHashtable(h, GetHandleId(whichUnit))
endfunction
function GetUnitSoundSetPerUnit takes unit whichUnit, integer soundType returns sound
return LoadSoundHandle(h, GetHandleId(whichUnit), soundType)
endfunction
function AddUnitSoundSetPerUnit takes unit whichUnit, integer soundType, sound whichSound returns nothing
if (whichSound != null) then
call SaveSoundHandle(h, GetHandleId(whichUnit), soundType, whichSound)
call SaveBoolean(h, GetHandleId(whichUnit), KEY_HAS_CUSTOM_SOUNDSET, true)
endif
endfunction
function HasUnitSoundSetPerUnit takes unit whichUnit returns boolean
return LoadBoolean(h, GetHandleId(whichUnit), KEY_HAS_CUSTOM_SOUNDSET)
endfunction
private function CreateSoundFromFile takes string filePath, string eaxSetting returns sound
local sound soundHandle = null
local integer duration = GetSoundFileDuration(filePath)
// the duration should be 0 if the file does not exist
if (duration > 0) then
set soundHandle = CreateSound(filePath, false, false, true, 12700, 12700, eaxSetting)
//call SetSoundChannel(soundHandle, 1) // SOUND_VOLUMEGROUP_UNITSOUNDS
call SetSoundDuration(soundHandle, duration)
//call SetSoundVolume(soundHandle, 127)
//else
//call BJDebugMsg("Missing sound file " + filePath)
endif
return soundHandle
endfunction
function AddUnitSoundSetFromFilesTypePerUnit takes unit whichUnit, string filePath, string extension, integer start, integer max, string prefix, string eaxSetting returns nothing
local integer i = 0
loop
exitwhen (start >= max)
call AddUnitSoundSetPerUnit(whichUnit, start, CreateSoundFromFile(filePath + prefix + I2S(i) + "." + extension, eaxSetting))
set start = start + 1
set i = i + 1
endloop
endfunction
function AddUnitSoundSetFromFilesPerUnitEx takes unit whichUnit, string filePath, string extension returns nothing
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, 0, SOUND_WHAT_1, "Death", "DefaultEAXON")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_WHAT_1, SOUND_YES_1, "What", "HeroAcksEAX")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_YES_1, SOUND_YES_ATTACK_1, "Yes", "HeroAcksEAX")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_YES_ATTACK_1, SOUND_WARCRY_1, "YesAttack", "HeroAcksEAX")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_WARCRY_1, SOUND_READY_1, "WarCry", "HeroAcksEAX")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_READY_1, SOUND_PISSED_1, "Ready", "HeroAcksEAX")
call AddUnitSoundSetFromFilesTypePerUnit(whichUnit, filePath, extension, SOUND_PISSED_1, MAX_SOUND_CATEGORIES, "Pissed", "HeroAcksEAX")
endfunction
function AddUnitSoundSetFromFilesPerUnit takes unit whichUnit, string filePath returns nothing
call AddUnitSoundSetFromFilesPerUnitEx(whichUnit, filePath, "mp3")
call AddUnitSoundSetFromFilesPerUnitEx(whichUnit, filePath, "flac")
call AddUnitSoundSetFromFilesPerUnitEx(whichUnit, filePath, "wav")
endfunction
function HasUnitShopSoundSetPerUnit takes unit whichUnit returns boolean
return LoadBoolean(h, GetHandleId(whichUnit), KEY_HAS_SHOP_SOUNDSET)
endfunction
function AddUnitShopSoundSetPerUnit takes unit whichUnit returns nothing
call SaveBoolean(h, GetHandleId(whichUnit), KEY_HAS_SHOP_SOUNDSET, true)
endfunction
function RemoveUnitShopSoundSetPerUnit takes unit whichUnit returns nothing
call SaveBoolean(h, GetHandleId(whichUnit), KEY_HAS_SHOP_SOUNDSET, false)
endfunction
hook RemoveUnit RemoveUnitSoundSetPerUnit
endlibrary
library PrintFrameInfo
function PrintFrameInfo takes framehandle f returns nothing
call BJDebugMsg("Name " + BlzFrameGetName(f))
call BJDebugMsg("Width " + R2S(BlzFrameGetWidth(f)))
call BJDebugMsg("Height " + R2S(BlzFrameGetHeight(f)))
call BJDebugMsg("Text " + BlzFrameGetText(f))
endfunction
function PrintFramePortraitInfo takes nothing returns nothing
call PrintFrameInfo(BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT_HP_TEXT, 0))
call PrintFrameInfo(BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT_MANA_TEXT, 0))
endfunction
endlibrary