-
Are you planning to upload your awesome map to Hive? Please review the rules here.Dismiss Notice
-
Find your way through the deepest dungeon in the 18th Mini Mapping Contest Poll.Dismiss Notice
-
A brave new world lies beyond the seven seas. Join the 34th Modeling Contest today!Dismiss Notice
-
Check out the Staff job openings thread.Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.
Trigger Viewer






































































































































































































































































































































































































































function LoadToc takes string s returns nothing if BlzLoadTOCFile(s) then call PlayMusicBJ("Boss.mp3") else call PlayMusicBJ("Boss.mp3") endif endfunction function UpdateCam takes nothing returns nothing call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, BlzFrameGetValue(BlzGetFrameByName("EscMenuSliderTemplate", 0)), 0) call BlzFrameSetText(BlzGetFrameByName("EscMenuLabelTextTemplate", 0), "Distance: " + R2SW(BlzFrameGetValue(BlzGetFrameByName("EscMenuSliderTemplate", 0)), 1, 1)) endfunction function CreateSliderDistance takes nothing returns nothing local framehandle fh = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0) local framehandle label = BlzCreateFrame("EscMenuLabelTextTemplate", fh, 0, 0) call BlzFrameSetPoint(label, FRAMEPOINT_LEFT, fh, FRAMEPOINT_RIGHT, 0, 0) call BlzFrameSetAbsPoint(fh, FRAMEPOINT_LEFT, 0.01, 0.56) //below the menu, quest buttons //call BlzFrameSetSize(fh, 0.139, 0.012) //default size in the fdf. call BlzFrameSetMinMaxValue(fh, 600, 6000) //limits user can choose call BlzFrameSetValue(fh, 4500) //starting value, should be used after one changed min max call BlzFrameSetStepSize(fh, 50) // endfunction function CreateCamControl takes nothing returns nothing call LoadToc("war3mapimported\\templates.toc") //use the custom function to load the Toc, the custom function prints success/fail loading the toc. call CreateSliderDistance() call TimerStart(CreateTimer(), 0.4, true, function UpdateCam) endfunction function ChangeLumberTextBox takes nothing returns nothing local framehandle fh = BlzGetFrameByName("ResourceBarUpkeepText" , 0) //Load "ResourceBarLumberText" with creationcontext 0 call BlzFrameSetText(fh , "|Cffffff00Prehistory") //Change the text to Lumber set fh = null endfunction
Name | Type | Is Array | Initial Value |
agent | integer | Yes | |
Aleatoire | real | No | |
AleoLivre | integer | No | |
annee_roi | integer | Yes | |
ArmorItem | integer | Yes | |
AutoProduce | group | No | |
batiment1 | unitcode | No | |
batiment2 | unitcode | No | |
batiment3 | unitcode | Yes | |
Bitcoin | integer | Yes | |
Bitcoin2 | real | Yes | |
BitcoinTotal | integer | No | |
BitcoinTotal2 | real | No | |
BitcoinTotal3 | integer | No | |
Boom | timer | No | |
Boom2 | timerdialog | No | |
BootsType | integer | Yes | |
build | location | Yes | |
C_SG_NS_Ability | abilcode | No | |
C_SG_NS_AOE_Add | real | No | |
C_SG_NS_AOE_Base | real | No | |
C_SG_NS_Blink_Interval | integer | No | |
C_SG_NS_Calldown_Sound | sound | No | |
C_SG_NS_Channel_Add | integer | No | |
C_SG_NS_Channel_Base | integer | No | |
C_SG_NS_Delay | integer | No | |
C_SG_NS_DMG_Max_Percent_Add | real | No | |
C_SG_NS_DMG_Max_Percent_Base | real | No | |
C_SG_NS_DMG_Min_Flat_Add | real | No | |
C_SG_NS_DMG_Min_Flat_Base | real | No | |
C_SG_NS_DMG_Structure_Add | real | No | |
C_SG_NS_DMG_Structure_Base | real | No | |
C_SG_NS_Loop_Interval | real | No | |
C_SG_NS_SFX_Hit | string | No | |
C_SG_NS_SFX_Nuke | string | No | |
Capital | unit | No | |
caravan1 | unit | Yes | |
caravan1_Copier | boolean | Yes | |
caravan2 | unit | Yes | |
caravan2_Copier | boolean | Yes | |
caravan3 | unit | Yes | |
caravan3_Copier | boolean | Yes | |
caravan4 | unit | Yes | |
caravan4_Copier | boolean | Yes | |
caravan5 | unit | Yes | |
caravan5_Copier | boolean | Yes | |
Caravans | group | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
choix | timerdialog | No | |
choix_Copier | timer | No | |
continent | button | Yes | |
Currentplayer | player | No | |
Date | string | No | |
Date2 | string | No | |
Date3 | string | No | |
Date4 | string | No | |
Day | integer | No | |
DaysInEachMonth | integer | Yes | |
DeathEvent | real | No | |
Degre | real | Yes | |
Degre2 | real | Yes | |
demande1 | string | No | |
demande2 | string | No | |
Destination | hashtable | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
distance1 | real | Yes | |
distance1_Copier | real | Yes | |
distance2 | real | Yes | |
distance2_Copier | real | Yes | |
distance3 | real | Yes | |
distance3_Copier | real | Yes | |
distance4 | real | Yes | |
distance4_Copier | real | Yes | |
distance5 | real | Yes | |
distance5_Copier | real | Yes | |
donne | unit | No | |
donne_Copier_1 | button | No | |
donne_Copier_10 | button | No | |
donne_Copier_11 | button | No | |
donne_Copier_12 | button | No | |
donne_Copier_2 | button | No | |
donne_Copier_3 | button | No | |
donne_Copier_4 | button | No | |
donne_Copier_5 | button | No | |
donne_Copier_6 | button | No | |
donne_Copier_7 | button | No | |
donne_Copier_8 | button | No | |
donne_Copier_9 | button | No | |
donner | button | Yes | |
Dyson | unit | No | |
ENTIER | integer | No | |
ENTIER2 | integer | No | |
ENTIER_ARRAY1 | integer | Yes | |
ENTIER_ARRAY2 | integer | Yes | |
faveur | integer | Yes | |
Ferme | integer | Yes | |
fh | string | No | |
floatingtext | texttag | No | |
fofo1 | unit | Yes | |
fofo2 | unit | Yes | |
fofo3 | unit | Yes | |
fofo4 | unit | Yes | |
fofo5 | unit | Yes | |
Food_Change | integer | No | |
Food_Value | integer | No | 100 |
Fuel_Change | integer | No | |
Fuel_Value | integer | No | 300 |
GlovesItem | integer | Yes | |
Gold | integer | Yes | |
Handle | handle | Yes | |
HashtableCaravans | hashtable | No | |
HashtableTradeShips | hashtable | No | |
Hints | string | No | |
imposition1 | button | Yes | |
imposition2 | button | Yes | |
imposition3 | button | Yes | |
imposition_Copier | dialog | No | |
inter | player | Yes | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
KillerOfUnit | unit | Yes | |
Lieu | location | Yes | |
Lieu2 | location | Yes | |
lieutenant | dialog | No | |
LimitePanneau | integer | Yes | |
mariage | dialog | No | |
MarketsGroup | group | No | |
Message | string | No | |
meteo | weathereffect | No | |
meveille | boolean | Yes | |
mob | integer | No | |
money | integer | Yes | |
monnaie1 | integer | No | |
monnaie2 | integer | No | |
Month | integer | No | |
mort | integer | No | |
MusicAleo | integer | Yes | |
MusicTime | timer | Yes | |
MyResourceBarCount | integer | No | |
MyResourceBarIcons | imagefile | Yes | |
MyResourceBarTooltipText | string | Yes | |
MyResourceBarTooltipTitle | string | Yes | |
MyResourceValue | string | Yes | |
nation | button | Yes | |
nation2 | button | Yes | |
nation3 | button | Yes | |
nation4 | button | Yes | |
nationalite | player | Yes | |
navire1 | unit | Yes | |
navire1_Copier | boolean | Yes | |
navire2 | unit | Yes | |
navire2_Copier | boolean | Yes | |
navire3 | unit | Yes | |
navire3_Copier | boolean | Yes | |
navire4 | unit | Yes | |
navire4_Copier | boolean | Yes | |
navire5 | unit | Yes | |
navire5_Copier | boolean | Yes | |
nom | string | Yes | |
nom_roi | string | Yes | |
nomm | string | No | |
nonagression | force | Yes | |
NumberOfCaravans | integer | No | |
NumberOfTradeShips | integer | No | |
NumeroBateau | integer | No | 1 |
Oil | integer | Yes | |
OrderAttack | group | Yes | |
OrderBank | group | Yes | |
OrderVillager | group | Yes | |
Parametre_afrique | dialog | No | |
Parametre_amerique | dialog | No | |
Parametre_asie | dialog | No | |
Parametre_continent | dialog | No | |
Parametre_europe | dialog | No | |
Parametre_nom2 | dialog | No | |
Parametre_Tuto | dialog | No | |
period | integer | Yes | |
pla | player | No | |
player | player | No | |
Player_Colour | integer | Yes | |
PlayerIndex | integer | No | |
POINT | location | No | |
Point | location | No | |
Point2 | location | No | |
POINT2 | location | No | |
Point_of_Path | location | No | |
pollute | real | No | |
Pollution | real | No | |
Port | group | No | |
port1 | unit | Yes | |
port2 | unit | Yes | |
port3 | unit | Yes | |
port4 | unit | Yes | |
port5 | unit | Yes | |
pris | boolean | Yes | |
REAL | real | No | |
regence | boolean | Yes | |
regence_Copier | force | Yes | |
regime | string | Yes | |
relation | real | Yes | |
religion | string | Yes | |
roi_nom | force | No | |
satellite | integer | No | 0 |
satelliteN | unit | Yes | |
Saying_Player | force | No | |
SG_NS_AOE | real | Yes | |
SG_NS_Caster | unit | Yes | |
SG_NS_Completed | boolean | Yes | |
SG_NS_Counter | integer | Yes | |
SG_NS_DMG_Flat | real | Yes | |
SG_NS_DMG_Percent | real | Yes | |
SG_NS_DMG_Structure | real | Yes | |
SG_NS_Floating_Text | texttag | Yes | |
SG_NS_Floating_Text_Dot | texttag | Yes | |
SG_NS_MUI_Index_A | integer | No | |
SG_NS_Nuke_SFX | effect | Yes | |
SG_NS_Order | ordercode | Yes | |
SG_NS_Point | location | Yes | |
SG_NS_Temp_Integer_A | integer | No | |
SG_NS_Temp_Integer_B | integer | No | |
SG_NS_Vision | fogmodifier | Yes | |
ShieldType | integer | Yes | |
ShipyardsGroup | group | No | |
son | sound | Yes | |
SortieBateau | location | Yes | |
SpaceMaxX | real | No | |
SpaceMaxY | real | No | |
SpaceMinX | real | No | |
SpaceMinY | real | No | |
SpaceObject | string | Yes | |
SpaceObjectMaxSize | real | Yes | |
SpaceObjectMinSize | real | Yes | |
SpaceObjectsMax | integer | No | |
SpaceObjectsMax2 | integer | No | |
SpaceObjectSpawnChance | real | Yes | |
spawn_mob | location | No | |
start | force | No | |
street1 | unit | Yes | |
street2 | unit | Yes | |
SummonerOfUnit | unit | Yes | |
Target | player | No | |
tele | group | No | |
Tem | group | Yes | |
Temp | group | No | |
Temp_Group | group | No | |
Temp_PickedUnit | unit | No | |
Text | string | No | |
time | integer | No | |
TimeOfYear | multiboard | No | |
titre | string | Yes | |
TradeShips | group | No | |
Tutorial_button | button | Yes | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
Ugroup | group | No | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
UNIT | unit | No | |
Unit_test | unit | No | |
Unit_test2 | unit | No | |
UnitInAction | boolean | Yes | |
UnitInActionEvent | real | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitMovementInterval | real | No | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes | |
UnitName | string | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
Uranium | integer | Yes | |
Uranium_Change | integer | No | |
Uranium_Value | integer | No | 500 |
vassals | force | No | |
visibilite | fogmodifier | Yes | |
WeaponItem | integer | Yes | |
Wood_Change | integer | No | |
Wood_Value | integer | No | 100 |
woodcut | string | No | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
Year | integer | Yes |
//MyResourceBar 1.2c
//By Tasyen
function MyResourceBarPlayerSize takes nothing returns integer
return 100 //each player has 100 slots allwing upto 9 additional bars (on default). MyResourceBarAutoCreateCount * MyResourceBarDataSize should not reach that number
endfunction
function MyResourceBarDataSize takes nothing returns integer
return 10 //each Bar takes that amount of slots
endfunction
function MyResourceBarAutoCreateCount takes nothing returns integer
return 1 //Create this amount of addtional Bars automatically.
endfunction
//Allow and Pos the checkbox hidding the additional Bars.
function MyResourceBarCreateCheckBox takes nothing returns boolean
return false //(true) create a checkbox to tooggle visiblity of the additional ResourceBarFrames
endfunction
function MyResourceBarCheckBoxLabelText takes nothing returns string
return "Hide Resources"
endfunction
function MyResourceBarCheckBoxX takes nothing returns real
return 0.1
endfunction
function MyResourceBarCheckBoxY takes nothing returns real
return 0.57
endfunction
//Where is the tooltip of this Bars placed.
function MyResourceBarTooltipX takes nothing returns real
return 0.8
endfunction
function MyResourceBarTooltipY takes nothing returns real
return 0.16
endfunction
function MyResourceBarTooltipPoint takes nothing returns framepointtype
return FRAMEPOINT_BOTTOMRIGHT
endfunction
function MyResourceBarAnchor takes nothing returns framepointtype
//Poses the first Bar where in the world Frame?
//I suggest to use a y-offset when using any Bottom Point.
//return FRAMEPOINT_TOPLEFT
//return FRAMEPOINT_TOP
return FRAMEPOINT_TOPRIGHT
//return FRAMEPOINT_BOTTOMLEFT
//return FRAMEPOINT_BOTTOM
//return FRAMEPOINT_BOTTOMRIGHT
//return FRAMEPOINT_LEFT
//return FRAMEPOINT_RIGHT
//return FRAMEPOINT_CENTER
endfunction
function MyResourceBarAnchor1OffsetX takes nothing returns real
return 0.0 //Offset the first bar by that amount from its FramePoint
endfunction
function MyResourceBarAnchor1OffsetY takes nothing returns real
return 0.0
endfunction
function MyResourceBarCreateTooltip takes framehandle targetFrameLeft, framehandle targetFrameRight, string title, string text, integer index returns nothing
local framehandle box = BlzGetFrameByName("MyResourceBarBoss",0)
local framehandle fhHover = BlzCreateFrameByType("FRAME", "MyResourceHover", box, "", index)
local framehandle tooltipBox = BlzCreateFrame("MyResourceBarBoxedText", box,0, index)
call BlzFrameSetPoint(fhHover, FRAMEPOINT_BOTTOMLEFT, targetFrameLeft, FRAMEPOINT_BOTTOMLEFT, 0, 0)
call BlzFrameSetPoint(fhHover, FRAMEPOINT_TOPRIGHT, targetFrameRight, FRAMEPOINT_TOPRIGHT, 0, 0)
call BlzFrameSetTooltip(fhHover, tooltipBox)
call BlzFrameSetAbsPoint(tooltipBox, MyResourceBarTooltipPoint(), MyResourceBarTooltipX(), MyResourceBarTooltipY())
call BlzFrameSetSize(tooltipBox, 0.285, 0.06)
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", index), title)
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", index), text)
set box = null
set fhHover = null
set tooltipBox = null
endfunction
function MyResourceBarSetup takes integer barIndex returns nothing //create an additonal ResourceBar between the orginal one.
local integer playerIndex = GetConvertedPlayerId(GetLocalPlayer()) * MyResourceBarPlayerSize()
local integer dataIndex = barIndex*MyResourceBarDataSize()
local integer loopIndex = 1
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar1Icon", barIndex), BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 1], udg_MyResourceBarTooltipText[dataIndex +1], dataIndex + 1)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar2Icon", barIndex), BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 2], udg_MyResourceBarTooltipText[dataIndex +2], dataIndex + 2)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar3Icon", barIndex), BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 3], udg_MyResourceBarTooltipText[dataIndex +3], dataIndex + 3)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar4Icon", barIndex), BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 4], udg_MyResourceBarTooltipText[dataIndex +4], dataIndex + 4)
loop
if udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex] == null or udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex] == "" then
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(loopIndex)+"Icon", barIndex), udg_MyResourceBarIcons[dataIndex + loopIndex], 0 ,true)
else
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(loopIndex)+"Icon", barIndex), udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex], 0 ,true)
endif
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + loopIndex] != null then //player specific Tooltip?
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + loopIndex), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + loopIndex])
endif
if udg_MyResourceBarTooltipText[playerIndex + dataIndex + loopIndex] != null then //player specific TooltipText?
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + loopIndex), udg_MyResourceBarTooltipText[playerIndex + dataIndex + loopIndex])
endif
set loopIndex = loopIndex + 1
exitwhen loopIndex == 5
endloop
endfunction
function CreateMyResourceBar takes nothing returns nothing
local framehandle bar = BlzCreateSimpleFrame("MyResourceBarFrame", BlzGetFrameByName("MyResourceBarBoss2",0), udg_MyResourceBarCount + 1)
set udg_MyResourceBarCount = udg_MyResourceBarCount + 1
if udg_MyResourceBarCount == 1 then //if this is the first create one Pos it below the default one
call BlzFrameSetPoint(bar, MyResourceBarAnchor(), BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME,0), MyResourceBarAnchor(), MyResourceBarAnchor1OffsetX(), MyResourceBarAnchor1OffsetY())
else
if MyResourceBarAnchor() == FRAMEPOINT_TOPRIGHT or MyResourceBarAnchor() == FRAMEPOINT_TOPLEFT or MyResourceBarAnchor() == FRAMEPOINT_TOP then
call BlzFrameSetPoint(bar, FRAMEPOINT_TOP, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_BOTTOM, 0, 0)
elseif MyResourceBarAnchor() == FRAMEPOINT_BOTTOMLEFT or MyResourceBarAnchor() == FRAMEPOINT_BOTTOM or MyResourceBarAnchor() == FRAMEPOINT_BOTTOMRIGHT then
call BlzFrameSetPoint(bar, FRAMEPOINT_BOTTOMLEFT, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_TOPLEFT, 0, 0)
else
call BlzFrameSetPoint(bar, FRAMEPOINT_TOP, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_BOTTOM, 0, 0)
endif
endif
call MyResourceBarSetup(udg_MyResourceBarCount)
set bar = null
endfunction
function MyResourceBarUpdateBarsReplay takes nothing returns nothing
local integer playerIndex = (R2I(BlzFrameGetValue(BlzGetFrameByName("ReplayVisionMenu",0))) + 1) * MyResourceBarPlayerSize()
local integer i
local integer barIndex = 1
local integer dataIndex
//Takes over all udg_MyResourceValue data into the MyResourceBarFrames also updates the title
//The outher Loop are the Bars, the inner Loop handles the tooltipTitle update
loop
set dataIndex = barIndex*MyResourceBarDataSize()
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 1])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 2])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 3])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 4])
set i = 1
loop
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
endif
if udg_MyResourceBarTooltipText[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + i), udg_MyResourceBarTooltipText[dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + i), udg_MyResourceBarTooltipText[playerIndex + dataIndex + i])
endif
if udg_MyResourceBarIcons[playerIndex + dataIndex + i] == null or udg_MyResourceBarIcons[playerIndex + dataIndex + i] == "" then
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(i)+"Icon", barIndex), udg_MyResourceBarIcons[dataIndex + i], 0 ,true)
else
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(i)+"Icon", barIndex), udg_MyResourceBarIcons[playerIndex + dataIndex + i], 0 ,true)
endif
set i = i + 1
exitwhen i == 5
endloop
set barIndex = barIndex + 1
exitwhen barIndex > udg_MyResourceBarCount
endloop
endfunction
function MyResourceBarUpdateBars takes nothing returns nothing
local integer playerIndex = GetConvertedPlayerId(GetLocalPlayer()) * MyResourceBarPlayerSize()
local integer i
local integer barIndex = 1
local integer dataIndex
//Takes over all udg_MyResourceValue data into the MyResourceBarFrames also updates the title
//The outher Loop are the Bars, the inner Loop handles the tooltipTitle update
loop
set dataIndex = barIndex*MyResourceBarDataSize()
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 1])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 2])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 3])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 4])
set i = 1
loop
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
endif
set i = i + 1
exitwhen i == 5
endloop
set barIndex = barIndex + 1
exitwhen barIndex > udg_MyResourceBarCount
endloop
endfunction
function MyResourceBarsFitFrames takes nothing returns nothing
local framehandle leadbor = BlzGetFrameByName("Leaderboard",0)
local framehandle multi = BlzGetFrameByName("Multiboard",0)
local framehandle time = BlzGetFrameByName("TimerDialog",0)
local framehandle prev = BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount)
local framehandle resourcebar = BlzGetFrameByName("ResourceBarFrame", 0)
local real yPlus = -0.005
if MyResourceBarAnchor() == FRAMEPOINT_TOPRIGHT then
if not BlzFrameIsVisible(BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount)) then
set prev = resourcebar
set yPlus = -0.0165
endif
if time != null then //bugs if the 1. timer window is destroyed
call BlzFrameSetPoint(time, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = time
endif
if multi != null then //bugs if the current shown multiboard is not the last created one
call BlzFrameSetPoint(multi, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = multi
endif
if leadbor != null then//bugs if the current shown leaderboard is not the last created one
call BlzFrameSetPoint(leadbor, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = leadbor
endif
endif
set leadbor = null
set multi = null
set time = null
set prev = null
set resourcebar = null
endfunction
function MyResourceBarsCheckBox takes nothing returns nothing
//In some test BlzGetFrameByName could disconnect the game hence done for all players
local framehandle fh = BlzGetFrameByName("MyResourceBarBoss",0)
local framehandle fh2 = BlzGetFrameByName("MyResourceBarBoss2",0)
if GetTriggerPlayer() == GetLocalPlayer() then //only do something for the player having pressed the checkbox
call BlzFrameSetVisible(fh, BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_UNCHECKED)
call BlzFrameSetVisible(fh2, BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_UNCHECKED)
endif
set fh = null
set fh2 = null
call MyResourceBarsFitFrames()
endfunction
function MyResourceBarCreateCheckBoxAction takes nothing returns nothing
local trigger trig = CreateTrigger()
local framehandle fh = BlzCreateFrameByType("GLUECHECKBOX", "MyResourceBarCheckBox", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"QuestCheckBox",0)
local framehandle fhText = BlzCreateFrameByType("TEXT", "MyResourceBarCheckBoxLabel", fh, "", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPLEFT, MyResourceBarCheckBoxX(), MyResourceBarCheckBoxY())
call BlzFrameSetPoint(fhText, FRAMEPOINT_TOP, fh, FRAMEPOINT_BOTTOM, 0.0, 0.0)
call BlzFrameSetEnable(fhText, false)
call BlzFrameSetText(fhText, MyResourceBarCheckBoxLabelText())
call BlzTriggerRegisterFrameEvent(trig, fh, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(trig, fh, FRAMEEVENT_CHECKBOX_UNCHECKED)
call TriggerAddAction(trig, function MyResourceBarsCheckBox)
set fh = null
set fhText = null
set trig = null
endfunction
function MyResourceBarsCreate takes nothing returns nothing
//Create Hide ResourceBar checkbox
local integer i = MyResourceBarAutoCreateCount()
if MyResourceBarCreateCheckBox() and not BlzFrameIsVisible(BlzGetFrameByName("SimpleReplayPanel",0)) then
call MyResourceBarCreateCheckBoxAction()
endif
//Create Parents of the ResourceBarFrames, one needs a SIMPLEFRAME and a FRAME. They allow to easyly hide/show the ResourceBarFrames
call BlzCreateFrameByType("FRAME", "MyResourceBarBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0) //Parent of Frames (tooltips stuff)
call BlzCreateFrameByType("SIMPLEFRAME", "MyResourceBarBoss2", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0) //Parent of SimpleFrames (bar and its content)
//Create ResourceBarFrames
loop
exitwhen i <= 0
call CreateMyResourceBar()
set i = i - 1
endloop
//CleanUP
call DestroyTimer(GetExpiredTimer())
if not BlzFrameIsVisible(BlzGetFrameByName("SimpleReplayPanel",0)) then
call TriggerAddAction( gg_trg_MyResourceBar, function MyResourceBarUpdateBars)
else
call TriggerAddAction( gg_trg_MyResourceBar, function MyResourceBarUpdateBarsReplay)
endif
endfunction
//===========================================================================
function InitTrig_MyResourceBar takes nothing returns nothing
set gg_trg_MyResourceBar = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_MyResourceBar , 0.2)
call TimerStart(CreateTimer(),0.0, false, function MyResourceBarsCreate)
call BlzLoadTOCFile("war3mapImported\\MyResourceBar.toc")
endfunction
//By Tasyen
function MyResourceBarPlayerSize takes nothing returns integer
return 100 //each player has 100 slots allwing upto 9 additional bars (on default). MyResourceBarAutoCreateCount * MyResourceBarDataSize should not reach that number
endfunction
function MyResourceBarDataSize takes nothing returns integer
return 10 //each Bar takes that amount of slots
endfunction
function MyResourceBarAutoCreateCount takes nothing returns integer
return 1 //Create this amount of addtional Bars automatically.
endfunction
//Allow and Pos the checkbox hidding the additional Bars.
function MyResourceBarCreateCheckBox takes nothing returns boolean
return false //(true) create a checkbox to tooggle visiblity of the additional ResourceBarFrames
endfunction
function MyResourceBarCheckBoxLabelText takes nothing returns string
return "Hide Resources"
endfunction
function MyResourceBarCheckBoxX takes nothing returns real
return 0.1
endfunction
function MyResourceBarCheckBoxY takes nothing returns real
return 0.57
endfunction
//Where is the tooltip of this Bars placed.
function MyResourceBarTooltipX takes nothing returns real
return 0.8
endfunction
function MyResourceBarTooltipY takes nothing returns real
return 0.16
endfunction
function MyResourceBarTooltipPoint takes nothing returns framepointtype
return FRAMEPOINT_BOTTOMRIGHT
endfunction
function MyResourceBarAnchor takes nothing returns framepointtype
//Poses the first Bar where in the world Frame?
//I suggest to use a y-offset when using any Bottom Point.
//return FRAMEPOINT_TOPLEFT
//return FRAMEPOINT_TOP
return FRAMEPOINT_TOPRIGHT
//return FRAMEPOINT_BOTTOMLEFT
//return FRAMEPOINT_BOTTOM
//return FRAMEPOINT_BOTTOMRIGHT
//return FRAMEPOINT_LEFT
//return FRAMEPOINT_RIGHT
//return FRAMEPOINT_CENTER
endfunction
function MyResourceBarAnchor1OffsetX takes nothing returns real
return 0.0 //Offset the first bar by that amount from its FramePoint
endfunction
function MyResourceBarAnchor1OffsetY takes nothing returns real
return 0.0
endfunction
function MyResourceBarCreateTooltip takes framehandle targetFrameLeft, framehandle targetFrameRight, string title, string text, integer index returns nothing
local framehandle box = BlzGetFrameByName("MyResourceBarBoss",0)
local framehandle fhHover = BlzCreateFrameByType("FRAME", "MyResourceHover", box, "", index)
local framehandle tooltipBox = BlzCreateFrame("MyResourceBarBoxedText", box,0, index)
call BlzFrameSetPoint(fhHover, FRAMEPOINT_BOTTOMLEFT, targetFrameLeft, FRAMEPOINT_BOTTOMLEFT, 0, 0)
call BlzFrameSetPoint(fhHover, FRAMEPOINT_TOPRIGHT, targetFrameRight, FRAMEPOINT_TOPRIGHT, 0, 0)
call BlzFrameSetTooltip(fhHover, tooltipBox)
call BlzFrameSetAbsPoint(tooltipBox, MyResourceBarTooltipPoint(), MyResourceBarTooltipX(), MyResourceBarTooltipY())
call BlzFrameSetSize(tooltipBox, 0.285, 0.06)
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", index), title)
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", index), text)
set box = null
set fhHover = null
set tooltipBox = null
endfunction
function MyResourceBarSetup takes integer barIndex returns nothing //create an additonal ResourceBar between the orginal one.
local integer playerIndex = GetConvertedPlayerId(GetLocalPlayer()) * MyResourceBarPlayerSize()
local integer dataIndex = barIndex*MyResourceBarDataSize()
local integer loopIndex = 1
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar1Icon", barIndex), BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 1], udg_MyResourceBarTooltipText[dataIndex +1], dataIndex + 1)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar2Icon", barIndex), BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 2], udg_MyResourceBarTooltipText[dataIndex +2], dataIndex + 2)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar3Icon", barIndex), BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 3], udg_MyResourceBarTooltipText[dataIndex +3], dataIndex + 3)
call MyResourceBarCreateTooltip(BlzGetFrameByName("MyResourceBar4Icon", barIndex), BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceBarTooltipTitle[dataIndex + 4], udg_MyResourceBarTooltipText[dataIndex +4], dataIndex + 4)
loop
if udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex] == null or udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex] == "" then
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(loopIndex)+"Icon", barIndex), udg_MyResourceBarIcons[dataIndex + loopIndex], 0 ,true)
else
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(loopIndex)+"Icon", barIndex), udg_MyResourceBarIcons[playerIndex + dataIndex + loopIndex], 0 ,true)
endif
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + loopIndex] != null then //player specific Tooltip?
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + loopIndex), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + loopIndex])
endif
if udg_MyResourceBarTooltipText[playerIndex + dataIndex + loopIndex] != null then //player specific TooltipText?
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + loopIndex), udg_MyResourceBarTooltipText[playerIndex + dataIndex + loopIndex])
endif
set loopIndex = loopIndex + 1
exitwhen loopIndex == 5
endloop
endfunction
function CreateMyResourceBar takes nothing returns nothing
local framehandle bar = BlzCreateSimpleFrame("MyResourceBarFrame", BlzGetFrameByName("MyResourceBarBoss2",0), udg_MyResourceBarCount + 1)
set udg_MyResourceBarCount = udg_MyResourceBarCount + 1
if udg_MyResourceBarCount == 1 then //if this is the first create one Pos it below the default one
call BlzFrameSetPoint(bar, MyResourceBarAnchor(), BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME,0), MyResourceBarAnchor(), MyResourceBarAnchor1OffsetX(), MyResourceBarAnchor1OffsetY())
else
if MyResourceBarAnchor() == FRAMEPOINT_TOPRIGHT or MyResourceBarAnchor() == FRAMEPOINT_TOPLEFT or MyResourceBarAnchor() == FRAMEPOINT_TOP then
call BlzFrameSetPoint(bar, FRAMEPOINT_TOP, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_BOTTOM, 0, 0)
elseif MyResourceBarAnchor() == FRAMEPOINT_BOTTOMLEFT or MyResourceBarAnchor() == FRAMEPOINT_BOTTOM or MyResourceBarAnchor() == FRAMEPOINT_BOTTOMRIGHT then
call BlzFrameSetPoint(bar, FRAMEPOINT_BOTTOMLEFT, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_TOPLEFT, 0, 0)
else
call BlzFrameSetPoint(bar, FRAMEPOINT_TOP, BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount - 1), FRAMEPOINT_BOTTOM, 0, 0)
endif
endif
call MyResourceBarSetup(udg_MyResourceBarCount)
set bar = null
endfunction
function MyResourceBarUpdateBarsReplay takes nothing returns nothing
local integer playerIndex = (R2I(BlzFrameGetValue(BlzGetFrameByName("ReplayVisionMenu",0))) + 1) * MyResourceBarPlayerSize()
local integer i
local integer barIndex = 1
local integer dataIndex
//Takes over all udg_MyResourceValue data into the MyResourceBarFrames also updates the title
//The outher Loop are the Bars, the inner Loop handles the tooltipTitle update
loop
set dataIndex = barIndex*MyResourceBarDataSize()
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 1])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 2])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 3])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 4])
set i = 1
loop
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
endif
if udg_MyResourceBarTooltipText[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + i), udg_MyResourceBarTooltipText[dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextValue", dataIndex + i), udg_MyResourceBarTooltipText[playerIndex + dataIndex + i])
endif
if udg_MyResourceBarIcons[playerIndex + dataIndex + i] == null or udg_MyResourceBarIcons[playerIndex + dataIndex + i] == "" then
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(i)+"Icon", barIndex), udg_MyResourceBarIcons[dataIndex + i], 0 ,true)
else
call BlzFrameSetTexture(BlzGetFrameByName("MyResourceBar"+I2S(i)+"Icon", barIndex), udg_MyResourceBarIcons[playerIndex + dataIndex + i], 0 ,true)
endif
set i = i + 1
exitwhen i == 5
endloop
set barIndex = barIndex + 1
exitwhen barIndex > udg_MyResourceBarCount
endloop
endfunction
function MyResourceBarUpdateBars takes nothing returns nothing
local integer playerIndex = GetConvertedPlayerId(GetLocalPlayer()) * MyResourceBarPlayerSize()
local integer i
local integer barIndex = 1
local integer dataIndex
//Takes over all udg_MyResourceValue data into the MyResourceBarFrames also updates the title
//The outher Loop are the Bars, the inner Loop handles the tooltipTitle update
loop
set dataIndex = barIndex*MyResourceBarDataSize()
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar1Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 1])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar2Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 2])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar3Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 3])
call BlzFrameSetText(BlzGetFrameByName("MyResourceBar4Text", barIndex), udg_MyResourceValue[playerIndex + dataIndex + 4])
set i = 1
loop
if udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i] == null then
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
else
call BlzFrameSetText(BlzGetFrameByName("MyResourceBarBoxedTextTitle", dataIndex + i), udg_MyResourceBarTooltipTitle[playerIndex + dataIndex + i]+": "+udg_MyResourceValue[playerIndex +dataIndex + i])
endif
set i = i + 1
exitwhen i == 5
endloop
set barIndex = barIndex + 1
exitwhen barIndex > udg_MyResourceBarCount
endloop
endfunction
function MyResourceBarsFitFrames takes nothing returns nothing
local framehandle leadbor = BlzGetFrameByName("Leaderboard",0)
local framehandle multi = BlzGetFrameByName("Multiboard",0)
local framehandle time = BlzGetFrameByName("TimerDialog",0)
local framehandle prev = BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount)
local framehandle resourcebar = BlzGetFrameByName("ResourceBarFrame", 0)
local real yPlus = -0.005
if MyResourceBarAnchor() == FRAMEPOINT_TOPRIGHT then
if not BlzFrameIsVisible(BlzGetFrameByName("MyResourceBarFrame", udg_MyResourceBarCount)) then
set prev = resourcebar
set yPlus = -0.0165
endif
if time != null then //bugs if the 1. timer window is destroyed
call BlzFrameSetPoint(time, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = time
endif
if multi != null then //bugs if the current shown multiboard is not the last created one
call BlzFrameSetPoint(multi, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = multi
endif
if leadbor != null then//bugs if the current shown leaderboard is not the last created one
call BlzFrameSetPoint(leadbor, FRAMEPOINT_TOPRIGHT, prev, FRAMEPOINT_BOTTOMRIGHT, 0, -0.005 + yPlus)
set yPlus = 0
set prev = leadbor
endif
endif
set leadbor = null
set multi = null
set time = null
set prev = null
set resourcebar = null
endfunction
function MyResourceBarsCheckBox takes nothing returns nothing
//In some test BlzGetFrameByName could disconnect the game hence done for all players
local framehandle fh = BlzGetFrameByName("MyResourceBarBoss",0)
local framehandle fh2 = BlzGetFrameByName("MyResourceBarBoss2",0)
if GetTriggerPlayer() == GetLocalPlayer() then //only do something for the player having pressed the checkbox
call BlzFrameSetVisible(fh, BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_UNCHECKED)
call BlzFrameSetVisible(fh2, BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_UNCHECKED)
endif
set fh = null
set fh2 = null
call MyResourceBarsFitFrames()
endfunction
function MyResourceBarCreateCheckBoxAction takes nothing returns nothing
local trigger trig = CreateTrigger()
local framehandle fh = BlzCreateFrameByType("GLUECHECKBOX", "MyResourceBarCheckBox", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"QuestCheckBox",0)
local framehandle fhText = BlzCreateFrameByType("TEXT", "MyResourceBarCheckBoxLabel", fh, "", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPLEFT, MyResourceBarCheckBoxX(), MyResourceBarCheckBoxY())
call BlzFrameSetPoint(fhText, FRAMEPOINT_TOP, fh, FRAMEPOINT_BOTTOM, 0.0, 0.0)
call BlzFrameSetEnable(fhText, false)
call BlzFrameSetText(fhText, MyResourceBarCheckBoxLabelText())
call BlzTriggerRegisterFrameEvent(trig, fh, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(trig, fh, FRAMEEVENT_CHECKBOX_UNCHECKED)
call TriggerAddAction(trig, function MyResourceBarsCheckBox)
set fh = null
set fhText = null
set trig = null
endfunction
function MyResourceBarsCreate takes nothing returns nothing
//Create Hide ResourceBar checkbox
local integer i = MyResourceBarAutoCreateCount()
if MyResourceBarCreateCheckBox() and not BlzFrameIsVisible(BlzGetFrameByName("SimpleReplayPanel",0)) then
call MyResourceBarCreateCheckBoxAction()
endif
//Create Parents of the ResourceBarFrames, one needs a SIMPLEFRAME and a FRAME. They allow to easyly hide/show the ResourceBarFrames
call BlzCreateFrameByType("FRAME", "MyResourceBarBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0) //Parent of Frames (tooltips stuff)
call BlzCreateFrameByType("SIMPLEFRAME", "MyResourceBarBoss2", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0) //Parent of SimpleFrames (bar and its content)
//Create ResourceBarFrames
loop
exitwhen i <= 0
call CreateMyResourceBar()
set i = i - 1
endloop
//CleanUP
call DestroyTimer(GetExpiredTimer())
if not BlzFrameIsVisible(BlzGetFrameByName("SimpleReplayPanel",0)) then
call TriggerAddAction( gg_trg_MyResourceBar, function MyResourceBarUpdateBars)
else
call TriggerAddAction( gg_trg_MyResourceBar, function MyResourceBarUpdateBarsReplay)
endif
endfunction
//===========================================================================
function InitTrig_MyResourceBar takes nothing returns nothing
set gg_trg_MyResourceBar = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_MyResourceBar , 0.2)
call TimerStart(CreateTimer(),0.0, false, function MyResourceBarsCreate)
call BlzLoadTOCFile("war3mapImported\\MyResourceBar.toc")
endfunction










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































This is the only place you should be messing around if you don't know how to code.
NOTE:
ADD = This is the value added per level, even at Lv1.
BASE = This is the base Value
So at Lv1, if you wanted an 80 damage, with 20 increase per level. BASE should be 60, and ADD should be 20.
Disregard the "C_SG_NS" just consider what is afterwards.
---------------------------------------------
Loop Interval - This is the interval of the execution of loop. 0.04s is 25 execution per second.
Channel: This is the time for the unit to channel the spell. You have to edit the one from the Object Editor; change the cast time to fit your channeling needs (+ 0.01). Also 25 = 1s, if your interval is 0.04. If you adjust your interval, then you have to recalculate the channeling time as well.
AOE: This is how big is your AOE.
DMG_Min_Flat: This here is the flat damage, the minimum damage done when the HP of your target is really low. So if your target's hp is 20, then your damage will be invariably 480, should you set it that way.
DMG_Max_Percent: This here is the percentile damage, essentially when the targets have high HP. The damage will reference a percentage of their HP, rather than flat amount to deal damage. So if your target has 20000 HP, with 60% percentile damage, the damage dealt is 12000.
DMG_Structure: This is of the same essense calculated like the flat damage. However, this is instead what is dealt to structures. Should you want to deal percentile damage to structures, you have to change it from the Nuclear Strike Loop.
Delay: This is how long for the nuke to land.
Blink Interval: This is the interval of your dot's blinking. (Loop Interval) * (Blink interval), Currently it's 3 so, the blink interval is 0.12s.
Calldown Sound: This is the sound played when casting the ability. Currently there is 2 types of alert that is loaded. Now a SC1 variant is used, but a SC2 variant is also available.
NOTE:
ADD = This is the value added per level, even at Lv1.
BASE = This is the base Value
So at Lv1, if you wanted an 80 damage, with 20 increase per level. BASE should be 60, and ADD should be 20.
Disregard the "C_SG_NS" just consider what is afterwards.
---------------------------------------------
Loop Interval - This is the interval of the execution of loop. 0.04s is 25 execution per second.
Channel: This is the time for the unit to channel the spell. You have to edit the one from the Object Editor; change the cast time to fit your channeling needs (+ 0.01). Also 25 = 1s, if your interval is 0.04. If you adjust your interval, then you have to recalculate the channeling time as well.
AOE: This is how big is your AOE.
DMG_Min_Flat: This here is the flat damage, the minimum damage done when the HP of your target is really low. So if your target's hp is 20, then your damage will be invariably 480, should you set it that way.
DMG_Max_Percent: This here is the percentile damage, essentially when the targets have high HP. The damage will reference a percentage of their HP, rather than flat amount to deal damage. So if your target has 20000 HP, with 60% percentile damage, the damage dealt is 12000.
DMG_Structure: This is of the same essense calculated like the flat damage. However, this is instead what is dealt to structures. Should you want to deal percentile damage to structures, you have to change it from the Nuclear Strike Loop.
Delay: This is how long for the nuke to land.
Blink Interval: This is the interval of your dot's blinking. (Loop Interval) * (Blink interval), Currently it's 3 so, the blink interval is 0.12s.
Calldown Sound: This is the sound played when casting the ability. Currently there is 2 types of alert that is loaded. Now a SC1 variant is used, but a SC2 variant is also available.



















































































































NOTE:
If you wanted to have a special Nuke-Launching Silo, you have to make one.
If you wanted to have a special Nuke-Launching Silo, you have to make one.









































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































//TESH.scrollpos=251
//TESH.alwaysfold=0
library AutoIndex
//===========================================================================
// Information:
//==============
//
// AutoIndex is a very simple script to utilize. Just call GetUnitId(unit)
// to get get the unique value assigned to a particular unit. The GetUnitId
// function is extremely fast because it inlines directly to a GetUnitUserData
// call. AutoIndex automatically assigns an ID to each unit as it enters the
// map, and instantly frees that ID as the unit leaves the map. Detection of
// leaving units is accomplished in constant time without a periodic scan.
//
// AutoIndex uses UnitUserData by default. If something else in your map
// would conflict with that, you can set the UseUnitUserData configuration
// constant to false, and a hashtable will be used instead. Note that hash-
// tables are about 60% slower.
//
// If you turn on debug mode, AutoIndex will be able to display several
// helpful error messages. The following issues will be detected:
// -Passing a removed or decayed unit to GetUnitId
// -Code outside of AutoIndex has overwritten a unit's UserData value.
// -GetUnitId was used on a filtered unit (a unit you don't want indexed).
//
// AutoIndex provides events upon indexing or deindexing units. This
// effectively allows you to notice when units enter or leave the game. Also
// included are the AutoData, AutoCreate, and AutoDestroy modules, which allow
// you to fully utilize AutoIndex's enter/leave detection capabilities in
// conjunction with your structs.
//
//===========================================================================
// How to install AutoIndex:
//===========================
//
// 1.) Copy and paste this script into your map.
// 2.) Save it to allow the ObjectMerger macro to generate the "Leave Detect"
// ability for you. Close and re-open the map. After that, disable the macro
// to prevent the delay while saving.
//
//===========================================================================
// How to use AutoIndex:
//=======================
//
// So you can get a unique integer for each unit, but how do you use that to
// attach data to a unit? GetUnitId will always return a number in the range of
// 1-8190. This means it can be used as an array index, as demonstrated below:
/*
globals
integer array IntegerData
real array RealData
SomeStruct array SomeStructData
englobals
function Example takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
local integer id = GetUnitId(u)
//You now have a unique index for the unit, so you can
//attach or retrieve data about the unit using arrays.
set IntegerData[id] = 5
set RealData[id] = 25.0
set SomeStructData[id] = SomeStruct.create()
//If you have access to the same unit in another function, you can
//retrieve the data by using GetUnitId() and reading the arrays.
endfunction
*/
// The UnitFilter function in the configuration section is provided so that
// you can make AutoIndex completely ignore certain unit-types. Ignored units
// won't be indexed or fire indexed/deindexed events. You may want to filter out
// dummy casters or system-private units, especially ones that use UnitUserData
// internally. xe dummy units are automatically filtered.
//
//===========================================================================
// How to use OnUnitIndexed / OnUnitDeindexed:
//=============================================
//
// AutoIndex will fire the OnUnitIndexed event when a unit enters the map,
// and the OnUnitDeindexed event when a unit leaves the map. Functions used
// as events must take a unit and return nothing. An example is given below:
/*
function UnitEntersMap takes unit u returns nothing
call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" entered the map.")
endfunction //Using GetUnitId() during Indexed events works fine...
function UnitLeavesMap takes unit u returns nothing
call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" left the map.")
endfunction //So does using GetUnitId() during Deindexed events.
function Init takes nothing returns nothing
call OnUnitIndexed(UnitEntersMap)
call OnUnitDeindexed(UnitLeavesMap)
endfunction
*/
// If you call OnUnitIndexed during map initialization, every existing
// unit will be considered as entering the map. This saves you from the need
// to manually enumerate preplaced units (or units created by initialization
// code that ran before OnUnitIndexed was called).
//
// OnUnitDeindexed runs while a unit still exists, which means you can
// still do things such as destroy special effects attached to the unit.
// The unit will cease to exist immediately after the event is over.
//
//===========================================================================
// AutoIndex API:
//================
//
// GetUnitId(unit) -> integer
// This function returns a unique ID in the range of 1-8190 for the
// specified unit. Returns 0 if a null unit was passed. This function
// inlines directly to GetUnitUserData or LoadInteger if debug mode
// is disabled. If debug mode is enabled, this function will print
// an error message when passed a decayed or filtered unit.
//
// IsUnitIndexed(unit) -> boolean
// This function returns a boolean indicating whether the specified
// unit has been indexed. The only time this will return false is
// for units you have filtered using the UnitFilter function, or
// for xe dummy units. You can use this function to easily detect
// dummy units and avoid performing certain actions on them.
//
// OnUnitIndexed(IndexFunc)
// This function accepts an IndexFunc, which must take a unit and
// return nothing. The IndexFunc will be fired instantly whenever
// a unit enters the map. You may use GetUnitId on the unit. When
// you call this function during map initialization, every existing
// unit will be considered as entering the map.
//
// OnUnitDeindexed(IndexFunc)
// Same as above, but runs whenever a unit is leaving the map. When
// this event runs, the unit still exists, but it will cease to exist
// as soon as the event ends. You may use GetUnitId on the unit.
//
//===========================================================================
// How to use AutoData:
//======================
//
// The AutoData module allows you to associate one or more instances
// of the implementing struct with units, as well as iterate through all
// of the instances associated with each unit.
//
// This association is accomplished through the "me" instance member,
// which the module will place in the implementing struct. Whichever unit
// you assign to "me" becomes the owner of that instance. You may change
// ownership by reassigning "me" to another unit at any time, or you may
// make the instance unowned by assigning "me" to null.
//
// AutoData implements the static method operator [] in your struct
// to allow you to access instances from their owning units. For example,
// you may type: local StructName s = StructName[u]. If u has been set
// to own an instance of StructName, s will be set to that instance.
//
// So, what happens if you assign the same owning unit to multiple
// instances? You may use 2D array syntax to access instances assigned to
// the same unit: local StructName s = StructName[u][n], where u is the
// owning unit, and n is the index beginning with 0 for each unit. You
// can access the size of a unit's instance list (i.e. the number of
// instances belonging to the unit) by using the .size instance member.
/*
struct Example
implement AutoData
static method create takes unit u returns Example
local Example this = allocate()
set me = u //Assigning the "me" member from AutoData.
return this
endmethod
endstruct
function Test takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
local Example e1 = Example.create(u)
local Example e2 = Example.create(u)
local Example e3 = Example.create(u)
local Example e
call BJDebugMsg(I2S(Example[u].size)) //Prints 3 because u owns e1, e2, and e3.
set e = Example[u][GetRandomInt(0, Example[u].size - 1)] //Random instance belonging to u.
set e = Example[u] //This is the fastest way to iterate the instances belonging
loop //to a specific unit, starting with the first instance.
exitwhen e == 0 //e will be assigned to 0 when no instances remain.
call BJDebugMsg(I2S(e)) //Prints the values of e1, e2, e3.
set e = e[e.index + 1] //"e.index" refers to the e's position in u's instance list.
endloop //Thus, index + 1 is next, and index - 1 is previous.
endfunction //This trick allows you to avoid a local counter.
*/
// AutoData restrictions:
// -You may not implement AutoData in any struct which has already
// declared static or non-static method operator [].
// -AutoData will conflict with anything named "me", "size", or
// "index" in the implementing struct.
// -AutoData may not be implemented in structs that extend array.
// -You may not declare your own destroy method. (This restriction
// can be dropped as soon as JassHelper supports module onDestroy).
//
// AutoData information:
// -You do not need to null the "me" member when destroying an
// instance. That is done for you automatically during destroy().
// (But if you use deallocate(), you must null "me" manually.)
// -StructName[u] and StructName[u][0] refer to the same instance,
// which is the first instance that was associated with unit u.
// -StructName[u][StructName[u].size - 1] refers to the instance that
// was most recently associated with unit u.
// -Instances keep their relative order in the list when one is removed.
//
//===========================================================================
// How to use AutoCreate:
//=======================
//
// The AutoCreate module allows you to automatically create instances
// of the implementing struct for units as they enter the game. AutoCreate
// automatically implements AutoData into your struct. Any time an instance
// is automatically created for a unit, that instance's "me" member will be
// assigned to the entering unit.
//
// AutoCreate restrictions:
// -All of the same restrictions as AutoData.
// -If your struct's allocate() method takes parameters (i.e. the parent
// type's create method takes parameters), you must declare a create
// method and pass those extra parameters to allocate yourself.
//
// AutoCreate information:
// -You may optionally declare the createFilter method, which specifies
// which units should recieve an instance as they enter the game. If
// you do not declare it, all entering units will recieve an instance.
// -You may optionally declare the onCreate method, which will run when
// AutoCreate automatically creates an instance. (This is just a stand-
// in until JassHelper supports the onCreate method.)
// -You may declare your own create method, but it must take a single
// unit parameter (the entering unit) if you do so.
/*
struct Example
private static method createFilter takes unit u returns boolean
return GetUnitTypeId(u) == 'hfoo' //Created only for Footmen.
endmethod
private method onCreate takes nothing returns nothing
call BJDebugMsg(GetUnitName(me)+" entered the game!")
endmethod
implement AutoCreate
endstruct
*/
//===========================================================================
// How to use AutoDestroy:
//=========================
//
// The AutoDestroy module allows you to automatically destroy instances
// of the implementing struct when their "me" unit leaves the game. AutoDestroy
// automatically implements AutoData into your struct. You must assign a unit
// to the "me" member of an instance for this module to have any effect.
//
// AutoDestroy restrictions:
// -All of the same restrictions as AutoData.
//
// AutoDestroy information:
// -If you also implement AutoCreate in the same struct, remember that it
// assigns the "me" unit automatically. That means you can have fully
// automatic creation and destruction.
/*
struct Example
static method create takes unit u returns Example
local Example this = allocate()
set me = u //You should assign a unit to "me",
return this //otherwise AutoDestroy does nothing.
endmethod //Not necessary if using AutoCreate.
private method onDestroy takes nothing returns nothing
call BJDebugMsg(GetUnitName(me)+" left the game!")
endmethod
implement AutoDestroy
endstruct
*/
//===========================================================================
// Configuration:
//================
//! external ObjectMerger w3a Adef lvdt anam "Leave Detect" aart "" arac 0
//Save your map with this Object Merger call enabled, then close and reopen your
//map. Disable it by removing the exclamation to remove the delay while saving.
globals
private constant integer LeaveDetectAbilityID = 'lvdt'
//This rawcode must match the parameter after "Adef" in the
//ObjectMerger macro above. You may change both if you want.
private constant boolean UseUnitUserData = true
//If this is set to true, UnitUserData will be used. You should only set
//this to false if something else in your map already uses UnitUserData.
//A hashtable will be used instead, but it is about 60% slower.
private constant boolean SafeMode = true
//This is set to true by default so that GetUnitId() will ALWAYS work.
//If if this is set to false, GetUnitId() may fail to work in a very
//rare circumstance: creating a unit that has a default-on autocast
//ability, and using GetUnitId() on that unit as it enters the game,
//within a trigger that detects any order. Set this to false for a
//performance boost only if you think you can avoid this issue.
private constant boolean AutoDataFastMode = true
//If this is set to true, AutoData will utilize one hashtable per time
//it is implemented. If this is set to false, all AutoDatas will share
//a single hashtable, but iterating through the instances belonging to
//a unit will become about 12.5% slower. Your map will break if you
//use more than 255 hashtables simultaneously. Only set this to false
//if you suspect you will run out of hashtable instances.
endglobals
private function UnitFilter takes unit u returns boolean
local integer id = GetUnitTypeId(u)
if id == 'smis' or id == 'lmis' or id == 'roct' or id == 'dumm' or id == 'dumt' then
return false
endif
return true
endfunction
//Make this function return false for any unit-types you want to ignore.
//Ignored units won't be indexed or fire OnUnitIndexed/OnUnitDeindexed
//events. The unit parameter "u" to refers to the unit being filtered.
//Do not filter out xe dummy units; they are automatically filtered.
//===========================================================================
// AutoData / AutoCreate / AutoDestroy modules:
//==============================================
function interface AutoCreator takes unit u returns nothing
function interface AutoDestroyer takes unit u returns nothing
globals
hashtable AutoData = null //If AutoDataFastMode is disabled, this hashtable will be
endglobals //initialized and shared between all AutoData implementations.
module AutoData
private static hashtable ht
private static thistype array data
private static integer array listsize
private static key typeid //Good thing keys exist to identify each implementing struct.
private unit meunit
private integer id
readonly integer index //The user can avoid using a local counter because this is accessable.
static method operator [] takes unit u returns thistype
return data[GetUnitId(u)]
endmethod //This is as fast as retrieving an instance from a unit gets.
method operator [] takes integer index returns thistype
static if AutoDataFastMode then //If fast mode is enabled...
return LoadInteger(ht, id, index)
else //Each instance has its own hashtable to associate unit and index.
return LoadInteger(AutoData, id, index*8190+typeid)
endif //Otherwise, simulate a 3D array associating unit, struct-type ID, and index.
endmethod //Somehow, this version is 12.5% slower just because of the math.
private method setIndex takes integer index, thistype data returns nothing
static if AutoDataFastMode then //Too bad you can't have a module-private operator []=.
call SaveInteger(ht, id, index, data)
else
call SaveInteger(AutoData, id, index*8190+typeid, data)
endif
endmethod
private method remove takes nothing returns nothing
if meunit == null then //If the struct doesn't have an owner...
return //Nothing needs to be done.
endif
loop
exitwhen index == listsize[id] //The last value gets overwritten by 0.
call setIndex(index, this[index + 1]) //Shift each element down by one.
set this[index].index = index //Update the shifted instance's index.
set index = index + 1
endloop
set listsize[id] = listsize[id] - 1
set data[id] = this[0] //Ensure thistype[u] returns the same value as thistype[u][0].
set meunit = null
endmethod
private method add takes unit u returns nothing
if meunit != null then //If the struct has an owner...
call remove() //remove it first.
endif
set meunit = u
set id = GetUnitId(u) //Cache GetUnitId for slight performance boost.
if data[id] == 0 then //If this is the first instance for this unit...
set data[id] = this //Update the value that thistype[u] returns.
endif
set index = listsize[id] //Remember the index for removal.
call setIndex(index, this) //Add to the array.
set listsize[id] = index + 1
endmethod
method operator me takes nothing returns unit
return meunit
endmethod
method operator me= takes unit u returns nothing
if u != null then //If assigning "me" a non-null value...
call add(u) //Add this instance to that unit's array.
else //If assigning "me" a null value...
call remove() //Remove this instance from that unit's array.
endif
endmethod
method operator size takes nothing returns integer
return listsize[id]
endmethod
method destroy takes nothing returns nothing
call deallocate()
call remove() //This makes removal automatic when an instance is destroyed.
endmethod
private static method onInit takes nothing returns nothing
static if AutoDataFastMode then //If fast mode is enabled...
set ht = InitHashtable() //Initialize one hashtable per instance.
else //If fast mode is disabled...
if AutoData == null then //If the hashtable hasn't been initialized yet...
set AutoData = InitHashtable() //Initialize the shared hashtable.
endif
endif
endmethod
endmodule
module AutoCreate
implement AutoData //AutoData is necessary for AutoCreate.
private static method creator takes unit u returns nothing
local thistype this
local boolean b = true //Assume that the instance will be created.
static if thistype.createFilter.exists then //If createFilter exists...
set b = createFilter(u) //evaluate it and update b.
endif
if b then //If the instance should be created...
static if thistype.create.exists then //If the create method exists...
set this = create(u) //Create the instance, passing the entering unit.
else //If the create method doesn't exist...
set this = allocate() //Just allocate the instance.
endif
set me = u //Assign the instance's owner as the entering unit.
static if thistype.onCreate.exists then //If onCreate exists...
call onCreate() //Call it, because JassHelper should do this anyway.
endif
endif
endmethod
private static method onInit takes nothing returns nothing
call AutoIndex.addAutoCreate(thistype.creator)
endmethod //During module initialization, pass the creator function to AutoIndex.
endmodule
module AutoDestroy
implement AutoData //AutoData is necessary for AutoDestroy.
static method destroyer takes unit u returns nothing
loop
exitwhen thistype[u] == 0
call thistype[u].destroy()
endloop
endmethod //Destroy each instance owned by the unit until none are left.
private static method onInit takes nothing returns nothing
call AutoIndex.addAutoDestroy(thistype.destroyer)
endmethod //During module initialization, pass the destroyer function to AutoIndex.
endmodule
//===========================================================================
// AutoIndex struct:
//===================
function interface IndexFunc takes unit u returns nothing
hook RemoveUnit AutoIndex.hook_RemoveUnit
hook ReplaceUnitBJ AutoIndex.hook_ReplaceUnitBJ
debug hook SetUnitUserData AutoIndex.hook_SetUnitUserData
private keyword getIndex
private keyword getIndexDebug
private keyword isUnitIndexed
private keyword onUnitIndexed
private keyword onUnitDeindexed
struct AutoIndex
private static trigger enter = CreateTrigger()
private static trigger order = CreateTrigger()
private static trigger creepdeath = CreateTrigger()
private static group preplaced = CreateGroup()
private static timer allowdecay = CreateTimer()
private static hashtable ht
private static boolean array dead
private static boolean array summoned
private static boolean array animated
private static boolean array nodecay
private static boolean array removing
private static IndexFunc array indexfuncs
private static integer indexfuncs_n = -1
private static IndexFunc array deindexfuncs
private static integer deindexfuncs_n = -1
private static IndexFunc indexfunc
private static AutoCreator array creators
private static integer creators_n = -1
private static AutoDestroyer array destroyers
private static integer destroyers_n = -1
private static unit array allowdecayunit
private static integer allowdecay_n = -1
private static boolean duringinit = true
private static boolean array altered
static unit array idunit
//===========================================================================
static method getIndex takes unit u returns integer
static if UseUnitUserData then
return GetUnitUserData(u)
else
return LoadInteger(ht, 0, GetHandleId(u))
endif
endmethod //Resolves to an inlinable one-liner after the static if.
static method operator initialized takes nothing returns boolean
return not thistype.duringinit
endmethod
static method getIndexDebug takes unit u returns integer
if u == null then
return 0
elseif GetUnitTypeId(u) == 0 then
call BJDebugMsg("AutoIndex error: Removed or decayed unit passed to GetUnitId.")
elseif idunit[getIndex(u)] != u and GetIssuedOrderId() != 852056 then
call BJDebugMsg("AutoIndex error: "+GetUnitName(u)+" is a filtered unit.")
endif
return getIndex(u)
endmethod //If debug mode is enabled, use the getIndex method that shows errors.
private static method setIndex takes unit u, integer index returns nothing
static if UseUnitUserData then
call SetUnitUserData(u, index)
else
call SaveInteger(ht, 0, GetHandleId(u), index)
endif
endmethod //Resolves to an inlinable one-liner after the static if.
static method isUnitIndexed takes unit u returns boolean
return u != null and idunit[getIndex(u)] == u
endmethod
static method isUnitAnimateDead takes unit u returns boolean
return animated[getIndex(u)]
endmethod //Don't use this; use IsUnitAnimateDead from AutoEvents instead.
//===========================================================================
private static method onUnitIndexed_sub takes nothing returns nothing
call indexfunc.evaluate(GetEnumUnit())
endmethod
static method onUnitIndexed takes IndexFunc func returns nothing
set indexfuncs_n = indexfuncs_n + 1
set indexfuncs[indexfuncs_n] = func
if duringinit then //During initialization, evaluate the indexfunc for every preplaced unit.
set indexfunc = func
call ForGroup(preplaced, function AutoIndex.onUnitIndexed_sub)
endif
endmethod
static method onUnitDeindexed takes IndexFunc func returns nothing
set deindexfuncs_n = deindexfuncs_n + 1
set deindexfuncs[deindexfuncs_n] = func
endmethod
static method addAutoCreate takes AutoCreator func returns nothing
set creators_n = creators_n + 1
set creators[creators_n] = func
endmethod
static method addAutoDestroy takes AutoDestroyer func returns nothing
set destroyers_n = destroyers_n + 1
set destroyers[destroyers_n] = func
endmethod
//===========================================================================
private static method hook_RemoveUnit takes unit whichUnit returns nothing
set removing[getIndex(whichUnit)] = true
endmethod //Intercepts whenever RemoveUnit is called and sets a flag.
private static method hook_ReplaceUnitBJ takes unit whichUnit, integer newUnitId, integer unitStateMethod returns nothing
set removing[getIndex(whichUnit)] = true
endmethod //Intercepts whenever ReplaceUnitBJ is called and sets a flag.
private static method hook_SetUnitUserData takes unit whichUnit, integer data returns nothing
static if UseUnitUserData then
if idunit[getIndex(whichUnit)] == whichUnit then
if getIndex(whichUnit) == data then
call BJDebugMsg("AutoIndex error: Code outside AutoIndex attempted to alter "+GetUnitName(whichUnit)+"'s index.")
else
call BJDebugMsg("AutoIndex error: Code outside AutoIndex altered "+GetUnitName(whichUnit)+"'s index.")
if idunit[data] != null then
call BJDebugMsg("AutoIndex error: "+GetUnitName(whichUnit)+" and "+GetUnitName(idunit[data])+" now have the same index.")
endif
set altered[data] = true
endif
endif
endif //In debug mode, intercepts whenever SetUnitUserData is used on an indexed unit.
endmethod //Displays an error message if outside code tries to alter a unit's index.
//===========================================================================
private static method allowDecay takes nothing returns nothing
local integer n = allowdecay_n
loop
exitwhen n < 0
set nodecay[getIndex(allowdecayunit[n])] = false
set allowdecayunit[n] = null
set n = n - 1
endloop
set allowdecay_n = -1
endmethod //Iterate through all the units in the stack and allow them to decay again.
private static method detectStatus takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer index = getIndex(u)
local integer n
if idunit[index] == u then //Ignore non-indexed units.
if not IsUnitType(u, UNIT_TYPE_DEAD) then
if dead[index] then //The unit was dead, but now it's alive.
set dead[index] = false //The unit has been resurrected.
//! runtextmacro optional RunAutoEvent("Resurrect")
//If AutoEvents is in the map, run the resurrection events.
if IsUnitType(u, UNIT_TYPE_SUMMONED) and not summoned[index] then
set summoned[index] = true //If the unit gained the summoned flag,
set animated[index] = true //it's been raised with Animate Dead.
//! runtextmacro optional RunAutoEvent("AnimateDead")
//If AutoEvents is in the map, run the Animate Dead events.
endif
endif
else
if not removing[index] and not dead[index] and not animated[index] then
set dead[index] = true //The unit was alive, but now it's dead.
set nodecay[index] = true //A dead unit can't decay for at least 0. seconds.
set allowdecay_n = allowdecay_n + 1 //Add the unit to a stack. After the timer
set allowdecayunit[allowdecay_n] = u //expires, allow the unit to decay again.
call TimerStart(allowdecay, 0., false, function AutoIndex.allowDecay)
//! runtextmacro optional RunAutoEvent("Death")
//If AutoEvents is in the map, run the Death events.
elseif removing[index] or (dead[index] and not nodecay[index]) or (not dead[index] and animated[index]) then
//If .nodecay was false and the unit is dead and was previously dead, the unit decayed.
//If .animated was true and the unit is dead, the unit died and exploded.
//If .removing was true, the unit is being removed or replaced.
set n = deindexfuncs_n
loop //Run the OnUnitDeindexed events.
exitwhen n < 0
call deindexfuncs[n].evaluate(u)
set n = n - 1
endloop
set n = destroyers_n
loop //Destroy AutoDestroy structs for the leaving unit.
exitwhen n < 0
call destroyers[n].evaluate(u)
set n = n - 1
endloop
call AutoIndex(index).destroy() //Free the index by destroying the AutoIndex struct.
set idunit[index] = null //Null this unit reference to prevent a leak.
endif
endif
endif
set u = null
return false
endmethod
//===========================================================================
private static method unitEntersMap takes unit u returns nothing
local integer index
local integer n = 0
if getIndex(u) != 0 then
return //Don't index a unit that already has an ID.
endif
static if LIBRARY_xebasic then
if GetUnitTypeId(u) == XE_DUMMY_UNITID then
return //Don't index xe dummy units.
endif
endif
if not UnitFilter(u) then
return //Don't index units that fail the unit filter.
endif
set index = create()
call setIndex(u, index) //Assign an index to the entering unit.
call UnitAddAbility(u, LeaveDetectAbilityID) //Add the leave detect ability to the entering unit.
call UnitMakeAbilityPermanent(u, true, LeaveDetectAbilityID) //Prevent it from disappearing on morph.
set dead[index] = IsUnitType(u, UNIT_TYPE_DEAD) //Reset all of the flags for the entering unit.
set summoned[index] = IsUnitType(u, UNIT_TYPE_SUMMONED) //Each of these flags are necessary to detect
set animated[index] = false //when a unit leaves the map.
set nodecay[index] = false
set removing[index] = false
debug set altered[index] = false //In debug mode, this flag tracks wheter a unit's index was altered.
set idunit[index] = u //Attach the unit that is supposed to have this index to the index.
if duringinit then //If a unit enters the map during initialization...
call GroupAddUnit(preplaced, u) //Add the unit to the preplaced units group. This ensures that
endif //all units are noticed by OnUnitIndexed during initialization.
loop //Create AutoCreate structs for the entering unit.
exitwhen n > creators_n
call creators[n].evaluate(u)
set n = n + 1
endloop
set n = 0
loop //Run the OnUnitIndexed events.
exitwhen n > indexfuncs_n
call indexfuncs[n].evaluate(u)
set n = n + 1
endloop
endmethod
private static method onIssuedOrder takes nothing returns boolean
static if SafeMode then //If SafeMode is enabled, perform this extra check.
if getIndex(GetTriggerUnit()) == 0 then //If the unit doesn't already have
call unitEntersMap(GetTriggerUnit()) //an index, then assign it one.
endif
endif
return GetIssuedOrderId() == 852056 //If the order is Undefend, allow detectStatus to run.
endmethod
private static method initEnteringUnit takes nothing returns boolean
call unitEntersMap(GetFilterUnit())
return false
endmethod
//===========================================================================
private static method afterInit takes nothing returns nothing
set duringinit = false //Initialization is over; set a flag.
call DestroyTimer(GetExpiredTimer()) //Destroy the timer.
call GroupClear(preplaced) //The preplaced units group is
call DestroyGroup(preplaced) //no longer needed, so clean it.
set preplaced = null
endmethod
private static method onInit takes nothing returns nothing
local region maparea = CreateRegion()
local rect bounds = GetWorldBounds()
local group g = CreateGroup()
local integer i = 15
static if not UseUnitUserData then
set ht = InitHashtable() //Only create a hashtable if it will be used.
endif
loop
exitwhen i < 0
call SetPlayerAbilityAvailable(Player(i), LeaveDetectAbilityID, false)
//Make the LeaveDetect ability unavailable so that it doesn't show up on the command card of every unit.
call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
//Register the "EVENT_PLAYER_UNIT_ISSUED_ORDER" event for each player.
call GroupEnumUnitsOfPlayer(g, Player(i), function AutoIndex.initEnteringUnit)
//Enum every non-filtered unit on the map during initialization and assign it a unique
//index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
set i = i - 1
endloop
call TriggerAddCondition(order, And(function AutoIndex.onIssuedOrder, function AutoIndex.detectStatus))
//The detectStatus method will fire every time a non-filtered unit recieves an undefend order.
//And() is used here to avoid using a trigger action, which starts a new thread and is slower.
call TriggerRegisterPlayerUnitEvent(creepdeath, Player(12), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(creepdeath, function AutoIndex.detectStatus)
//The detectStatus method must also fire when a neutral hostile creep dies, in case it was
//sleeping. Sleeping creeps don't fire undefend orders on non-damaging deaths.
call RegionAddRect(maparea, bounds) //GetWorldBounds() includes the shaded boundry areas.
call TriggerRegisterEnterRegion(enter, maparea, function AutoIndex.initEnteringUnit)
//The filter function of an EnterRegion trigger runs instantly when a unit is created.
call TimerStart(CreateTimer(), 0., false, function AutoIndex.afterInit)
//After any time elapses, perform after-initialization actions.
call GroupClear(g)
call DestroyGroup(g)
call RemoveRect(bounds)
set g = null
set bounds = null
endmethod
endstruct
//===========================================================================
// User functions:
//=================
function GetUnitId takes unit u returns integer
static if DEBUG_MODE then //If debug mode is enabled...
return AutoIndex.getIndexDebug(u) //call the debug version of GetUnitId.
else //If debug mode is disabled...
return AutoIndex.getIndex(u) //call the normal, inlinable version.
endif
endfunction
function GetUnitById takes integer id returns unit
return AutoIndex.idunit[id]
endfunction
function IsUnitIndexed takes unit u returns boolean
return AutoIndex.isUnitIndexed(u)
endfunction
function OnUnitIndexed takes IndexFunc func returns nothing
call AutoIndex.onUnitIndexed(func)
endfunction
function OnUnitDeindexed takes IndexFunc func returns nothing
call AutoIndex.onUnitDeindexed(func)
endfunction
endlibrary
//TESH.alwaysfold=0
library AutoIndex
//===========================================================================
// Information:
//==============
//
// AutoIndex is a very simple script to utilize. Just call GetUnitId(unit)
// to get get the unique value assigned to a particular unit. The GetUnitId
// function is extremely fast because it inlines directly to a GetUnitUserData
// call. AutoIndex automatically assigns an ID to each unit as it enters the
// map, and instantly frees that ID as the unit leaves the map. Detection of
// leaving units is accomplished in constant time without a periodic scan.
//
// AutoIndex uses UnitUserData by default. If something else in your map
// would conflict with that, you can set the UseUnitUserData configuration
// constant to false, and a hashtable will be used instead. Note that hash-
// tables are about 60% slower.
//
// If you turn on debug mode, AutoIndex will be able to display several
// helpful error messages. The following issues will be detected:
// -Passing a removed or decayed unit to GetUnitId
// -Code outside of AutoIndex has overwritten a unit's UserData value.
// -GetUnitId was used on a filtered unit (a unit you don't want indexed).
//
// AutoIndex provides events upon indexing or deindexing units. This
// effectively allows you to notice when units enter or leave the game. Also
// included are the AutoData, AutoCreate, and AutoDestroy modules, which allow
// you to fully utilize AutoIndex's enter/leave detection capabilities in
// conjunction with your structs.
//
//===========================================================================
// How to install AutoIndex:
//===========================
//
// 1.) Copy and paste this script into your map.
// 2.) Save it to allow the ObjectMerger macro to generate the "Leave Detect"
// ability for you. Close and re-open the map. After that, disable the macro
// to prevent the delay while saving.
//
//===========================================================================
// How to use AutoIndex:
//=======================
//
// So you can get a unique integer for each unit, but how do you use that to
// attach data to a unit? GetUnitId will always return a number in the range of
// 1-8190. This means it can be used as an array index, as demonstrated below:
/*
globals
integer array IntegerData
real array RealData
SomeStruct array SomeStructData
englobals
function Example takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
local integer id = GetUnitId(u)
//You now have a unique index for the unit, so you can
//attach or retrieve data about the unit using arrays.
set IntegerData[id] = 5
set RealData[id] = 25.0
set SomeStructData[id] = SomeStruct.create()
//If you have access to the same unit in another function, you can
//retrieve the data by using GetUnitId() and reading the arrays.
endfunction
*/
// The UnitFilter function in the configuration section is provided so that
// you can make AutoIndex completely ignore certain unit-types. Ignored units
// won't be indexed or fire indexed/deindexed events. You may want to filter out
// dummy casters or system-private units, especially ones that use UnitUserData
// internally. xe dummy units are automatically filtered.
//
//===========================================================================
// How to use OnUnitIndexed / OnUnitDeindexed:
//=============================================
//
// AutoIndex will fire the OnUnitIndexed event when a unit enters the map,
// and the OnUnitDeindexed event when a unit leaves the map. Functions used
// as events must take a unit and return nothing. An example is given below:
/*
function UnitEntersMap takes unit u returns nothing
call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" entered the map.")
endfunction //Using GetUnitId() during Indexed events works fine...
function UnitLeavesMap takes unit u returns nothing
call BJDebugMsg(GetUnitName(u)+" with ID "+I2S(GetUnitId(u))+" left the map.")
endfunction //So does using GetUnitId() during Deindexed events.
function Init takes nothing returns nothing
call OnUnitIndexed(UnitEntersMap)
call OnUnitDeindexed(UnitLeavesMap)
endfunction
*/
// If you call OnUnitIndexed during map initialization, every existing
// unit will be considered as entering the map. This saves you from the need
// to manually enumerate preplaced units (or units created by initialization
// code that ran before OnUnitIndexed was called).
//
// OnUnitDeindexed runs while a unit still exists, which means you can
// still do things such as destroy special effects attached to the unit.
// The unit will cease to exist immediately after the event is over.
//
//===========================================================================
// AutoIndex API:
//================
//
// GetUnitId(unit) -> integer
// This function returns a unique ID in the range of 1-8190 for the
// specified unit. Returns 0 if a null unit was passed. This function
// inlines directly to GetUnitUserData or LoadInteger if debug mode
// is disabled. If debug mode is enabled, this function will print
// an error message when passed a decayed or filtered unit.
//
// IsUnitIndexed(unit) -> boolean
// This function returns a boolean indicating whether the specified
// unit has been indexed. The only time this will return false is
// for units you have filtered using the UnitFilter function, or
// for xe dummy units. You can use this function to easily detect
// dummy units and avoid performing certain actions on them.
//
// OnUnitIndexed(IndexFunc)
// This function accepts an IndexFunc, which must take a unit and
// return nothing. The IndexFunc will be fired instantly whenever
// a unit enters the map. You may use GetUnitId on the unit. When
// you call this function during map initialization, every existing
// unit will be considered as entering the map.
//
// OnUnitDeindexed(IndexFunc)
// Same as above, but runs whenever a unit is leaving the map. When
// this event runs, the unit still exists, but it will cease to exist
// as soon as the event ends. You may use GetUnitId on the unit.
//
//===========================================================================
// How to use AutoData:
//======================
//
// The AutoData module allows you to associate one or more instances
// of the implementing struct with units, as well as iterate through all
// of the instances associated with each unit.
//
// This association is accomplished through the "me" instance member,
// which the module will place in the implementing struct. Whichever unit
// you assign to "me" becomes the owner of that instance. You may change
// ownership by reassigning "me" to another unit at any time, or you may
// make the instance unowned by assigning "me" to null.
//
// AutoData implements the static method operator [] in your struct
// to allow you to access instances from their owning units. For example,
// you may type: local StructName s = StructName[u]. If u has been set
// to own an instance of StructName, s will be set to that instance.
//
// So, what happens if you assign the same owning unit to multiple
// instances? You may use 2D array syntax to access instances assigned to
// the same unit: local StructName s = StructName[u][n], where u is the
// owning unit, and n is the index beginning with 0 for each unit. You
// can access the size of a unit's instance list (i.e. the number of
// instances belonging to the unit) by using the .size instance member.
/*
struct Example
implement AutoData
static method create takes unit u returns Example
local Example this = allocate()
set me = u //Assigning the "me" member from AutoData.
return this
endmethod
endstruct
function Test takes nothing returns nothing
local unit u = CreateUnit(Player(0), 'hpea', 0., 0., 0.)
local Example e1 = Example.create(u)
local Example e2 = Example.create(u)
local Example e3 = Example.create(u)
local Example e
call BJDebugMsg(I2S(Example[u].size)) //Prints 3 because u owns e1, e2, and e3.
set e = Example[u][GetRandomInt(0, Example[u].size - 1)] //Random instance belonging to u.
set e = Example[u] //This is the fastest way to iterate the instances belonging
loop //to a specific unit, starting with the first instance.
exitwhen e == 0 //e will be assigned to 0 when no instances remain.
call BJDebugMsg(I2S(e)) //Prints the values of e1, e2, e3.
set e = e[e.index + 1] //"e.index" refers to the e's position in u's instance list.
endloop //Thus, index + 1 is next, and index - 1 is previous.
endfunction //This trick allows you to avoid a local counter.
*/
// AutoData restrictions:
// -You may not implement AutoData in any struct which has already
// declared static or non-static method operator [].
// -AutoData will conflict with anything named "me", "size", or
// "index" in the implementing struct.
// -AutoData may not be implemented in structs that extend array.
// -You may not declare your own destroy method. (This restriction
// can be dropped as soon as JassHelper supports module onDestroy).
//
// AutoData information:
// -You do not need to null the "me" member when destroying an
// instance. That is done for you automatically during destroy().
// (But if you use deallocate(), you must null "me" manually.)
// -StructName[u] and StructName[u][0] refer to the same instance,
// which is the first instance that was associated with unit u.
// -StructName[u][StructName[u].size - 1] refers to the instance that
// was most recently associated with unit u.
// -Instances keep their relative order in the list when one is removed.
//
//===========================================================================
// How to use AutoCreate:
//=======================
//
// The AutoCreate module allows you to automatically create instances
// of the implementing struct for units as they enter the game. AutoCreate
// automatically implements AutoData into your struct. Any time an instance
// is automatically created for a unit, that instance's "me" member will be
// assigned to the entering unit.
//
// AutoCreate restrictions:
// -All of the same restrictions as AutoData.
// -If your struct's allocate() method takes parameters (i.e. the parent
// type's create method takes parameters), you must declare a create
// method and pass those extra parameters to allocate yourself.
//
// AutoCreate information:
// -You may optionally declare the createFilter method, which specifies
// which units should recieve an instance as they enter the game. If
// you do not declare it, all entering units will recieve an instance.
// -You may optionally declare the onCreate method, which will run when
// AutoCreate automatically creates an instance. (This is just a stand-
// in until JassHelper supports the onCreate method.)
// -You may declare your own create method, but it must take a single
// unit parameter (the entering unit) if you do so.
/*
struct Example
private static method createFilter takes unit u returns boolean
return GetUnitTypeId(u) == 'hfoo' //Created only for Footmen.
endmethod
private method onCreate takes nothing returns nothing
call BJDebugMsg(GetUnitName(me)+" entered the game!")
endmethod
implement AutoCreate
endstruct
*/
//===========================================================================
// How to use AutoDestroy:
//=========================
//
// The AutoDestroy module allows you to automatically destroy instances
// of the implementing struct when their "me" unit leaves the game. AutoDestroy
// automatically implements AutoData into your struct. You must assign a unit
// to the "me" member of an instance for this module to have any effect.
//
// AutoDestroy restrictions:
// -All of the same restrictions as AutoData.
//
// AutoDestroy information:
// -If you also implement AutoCreate in the same struct, remember that it
// assigns the "me" unit automatically. That means you can have fully
// automatic creation and destruction.
/*
struct Example
static method create takes unit u returns Example
local Example this = allocate()
set me = u //You should assign a unit to "me",
return this //otherwise AutoDestroy does nothing.
endmethod //Not necessary if using AutoCreate.
private method onDestroy takes nothing returns nothing
call BJDebugMsg(GetUnitName(me)+" left the game!")
endmethod
implement AutoDestroy
endstruct
*/
//===========================================================================
// Configuration:
//================
//! external ObjectMerger w3a Adef lvdt anam "Leave Detect" aart "" arac 0
//Save your map with this Object Merger call enabled, then close and reopen your
//map. Disable it by removing the exclamation to remove the delay while saving.
globals
private constant integer LeaveDetectAbilityID = 'lvdt'
//This rawcode must match the parameter after "Adef" in the
//ObjectMerger macro above. You may change both if you want.
private constant boolean UseUnitUserData = true
//If this is set to true, UnitUserData will be used. You should only set
//this to false if something else in your map already uses UnitUserData.
//A hashtable will be used instead, but it is about 60% slower.
private constant boolean SafeMode = true
//This is set to true by default so that GetUnitId() will ALWAYS work.
//If if this is set to false, GetUnitId() may fail to work in a very
//rare circumstance: creating a unit that has a default-on autocast
//ability, and using GetUnitId() on that unit as it enters the game,
//within a trigger that detects any order. Set this to false for a
//performance boost only if you think you can avoid this issue.
private constant boolean AutoDataFastMode = true
//If this is set to true, AutoData will utilize one hashtable per time
//it is implemented. If this is set to false, all AutoDatas will share
//a single hashtable, but iterating through the instances belonging to
//a unit will become about 12.5% slower. Your map will break if you
//use more than 255 hashtables simultaneously. Only set this to false
//if you suspect you will run out of hashtable instances.
endglobals
private function UnitFilter takes unit u returns boolean
local integer id = GetUnitTypeId(u)
if id == 'smis' or id == 'lmis' or id == 'roct' or id == 'dumm' or id == 'dumt' then
return false
endif
return true
endfunction
//Make this function return false for any unit-types you want to ignore.
//Ignored units won't be indexed or fire OnUnitIndexed/OnUnitDeindexed
//events. The unit parameter "u" to refers to the unit being filtered.
//Do not filter out xe dummy units; they are automatically filtered.
//===========================================================================
// AutoData / AutoCreate / AutoDestroy modules:
//==============================================
function interface AutoCreator takes unit u returns nothing
function interface AutoDestroyer takes unit u returns nothing
globals
hashtable AutoData = null //If AutoDataFastMode is disabled, this hashtable will be
endglobals //initialized and shared between all AutoData implementations.
module AutoData
private static hashtable ht
private static thistype array data
private static integer array listsize
private static key typeid //Good thing keys exist to identify each implementing struct.
private unit meunit
private integer id
readonly integer index //The user can avoid using a local counter because this is accessable.
static method operator [] takes unit u returns thistype
return data[GetUnitId(u)]
endmethod //This is as fast as retrieving an instance from a unit gets.
method operator [] takes integer index returns thistype
static if AutoDataFastMode then //If fast mode is enabled...
return LoadInteger(ht, id, index)
else //Each instance has its own hashtable to associate unit and index.
return LoadInteger(AutoData, id, index*8190+typeid)
endif //Otherwise, simulate a 3D array associating unit, struct-type ID, and index.
endmethod //Somehow, this version is 12.5% slower just because of the math.
private method setIndex takes integer index, thistype data returns nothing
static if AutoDataFastMode then //Too bad you can't have a module-private operator []=.
call SaveInteger(ht, id, index, data)
else
call SaveInteger(AutoData, id, index*8190+typeid, data)
endif
endmethod
private method remove takes nothing returns nothing
if meunit == null then //If the struct doesn't have an owner...
return //Nothing needs to be done.
endif
loop
exitwhen index == listsize[id] //The last value gets overwritten by 0.
call setIndex(index, this[index + 1]) //Shift each element down by one.
set this[index].index = index //Update the shifted instance's index.
set index = index + 1
endloop
set listsize[id] = listsize[id] - 1
set data[id] = this[0] //Ensure thistype[u] returns the same value as thistype[u][0].
set meunit = null
endmethod
private method add takes unit u returns nothing
if meunit != null then //If the struct has an owner...
call remove() //remove it first.
endif
set meunit = u
set id = GetUnitId(u) //Cache GetUnitId for slight performance boost.
if data[id] == 0 then //If this is the first instance for this unit...
set data[id] = this //Update the value that thistype[u] returns.
endif
set index = listsize[id] //Remember the index for removal.
call setIndex(index, this) //Add to the array.
set listsize[id] = index + 1
endmethod
method operator me takes nothing returns unit
return meunit
endmethod
method operator me= takes unit u returns nothing
if u != null then //If assigning "me" a non-null value...
call add(u) //Add this instance to that unit's array.
else //If assigning "me" a null value...
call remove() //Remove this instance from that unit's array.
endif
endmethod
method operator size takes nothing returns integer
return listsize[id]
endmethod
method destroy takes nothing returns nothing
call deallocate()
call remove() //This makes removal automatic when an instance is destroyed.
endmethod
private static method onInit takes nothing returns nothing
static if AutoDataFastMode then //If fast mode is enabled...
set ht = InitHashtable() //Initialize one hashtable per instance.
else //If fast mode is disabled...
if AutoData == null then //If the hashtable hasn't been initialized yet...
set AutoData = InitHashtable() //Initialize the shared hashtable.
endif
endif
endmethod
endmodule
module AutoCreate
implement AutoData //AutoData is necessary for AutoCreate.
private static method creator takes unit u returns nothing
local thistype this
local boolean b = true //Assume that the instance will be created.
static if thistype.createFilter.exists then //If createFilter exists...
set b = createFilter(u) //evaluate it and update b.
endif
if b then //If the instance should be created...
static if thistype.create.exists then //If the create method exists...
set this = create(u) //Create the instance, passing the entering unit.
else //If the create method doesn't exist...
set this = allocate() //Just allocate the instance.
endif
set me = u //Assign the instance's owner as the entering unit.
static if thistype.onCreate.exists then //If onCreate exists...
call onCreate() //Call it, because JassHelper should do this anyway.
endif
endif
endmethod
private static method onInit takes nothing returns nothing
call AutoIndex.addAutoCreate(thistype.creator)
endmethod //During module initialization, pass the creator function to AutoIndex.
endmodule
module AutoDestroy
implement AutoData //AutoData is necessary for AutoDestroy.
static method destroyer takes unit u returns nothing
loop
exitwhen thistype[u] == 0
call thistype[u].destroy()
endloop
endmethod //Destroy each instance owned by the unit until none are left.
private static method onInit takes nothing returns nothing
call AutoIndex.addAutoDestroy(thistype.destroyer)
endmethod //During module initialization, pass the destroyer function to AutoIndex.
endmodule
//===========================================================================
// AutoIndex struct:
//===================
function interface IndexFunc takes unit u returns nothing
hook RemoveUnit AutoIndex.hook_RemoveUnit
hook ReplaceUnitBJ AutoIndex.hook_ReplaceUnitBJ
debug hook SetUnitUserData AutoIndex.hook_SetUnitUserData
private keyword getIndex
private keyword getIndexDebug
private keyword isUnitIndexed
private keyword onUnitIndexed
private keyword onUnitDeindexed
struct AutoIndex
private static trigger enter = CreateTrigger()
private static trigger order = CreateTrigger()
private static trigger creepdeath = CreateTrigger()
private static group preplaced = CreateGroup()
private static timer allowdecay = CreateTimer()
private static hashtable ht
private static boolean array dead
private static boolean array summoned
private static boolean array animated
private static boolean array nodecay
private static boolean array removing
private static IndexFunc array indexfuncs
private static integer indexfuncs_n = -1
private static IndexFunc array deindexfuncs
private static integer deindexfuncs_n = -1
private static IndexFunc indexfunc
private static AutoCreator array creators
private static integer creators_n = -1
private static AutoDestroyer array destroyers
private static integer destroyers_n = -1
private static unit array allowdecayunit
private static integer allowdecay_n = -1
private static boolean duringinit = true
private static boolean array altered
static unit array idunit
//===========================================================================
static method getIndex takes unit u returns integer
static if UseUnitUserData then
return GetUnitUserData(u)
else
return LoadInteger(ht, 0, GetHandleId(u))
endif
endmethod //Resolves to an inlinable one-liner after the static if.
static method operator initialized takes nothing returns boolean
return not thistype.duringinit
endmethod
static method getIndexDebug takes unit u returns integer
if u == null then
return 0
elseif GetUnitTypeId(u) == 0 then
call BJDebugMsg("AutoIndex error: Removed or decayed unit passed to GetUnitId.")
elseif idunit[getIndex(u)] != u and GetIssuedOrderId() != 852056 then
call BJDebugMsg("AutoIndex error: "+GetUnitName(u)+" is a filtered unit.")
endif
return getIndex(u)
endmethod //If debug mode is enabled, use the getIndex method that shows errors.
private static method setIndex takes unit u, integer index returns nothing
static if UseUnitUserData then
call SetUnitUserData(u, index)
else
call SaveInteger(ht, 0, GetHandleId(u), index)
endif
endmethod //Resolves to an inlinable one-liner after the static if.
static method isUnitIndexed takes unit u returns boolean
return u != null and idunit[getIndex(u)] == u
endmethod
static method isUnitAnimateDead takes unit u returns boolean
return animated[getIndex(u)]
endmethod //Don't use this; use IsUnitAnimateDead from AutoEvents instead.
//===========================================================================
private static method onUnitIndexed_sub takes nothing returns nothing
call indexfunc.evaluate(GetEnumUnit())
endmethod
static method onUnitIndexed takes IndexFunc func returns nothing
set indexfuncs_n = indexfuncs_n + 1
set indexfuncs[indexfuncs_n] = func
if duringinit then //During initialization, evaluate the indexfunc for every preplaced unit.
set indexfunc = func
call ForGroup(preplaced, function AutoIndex.onUnitIndexed_sub)
endif
endmethod
static method onUnitDeindexed takes IndexFunc func returns nothing
set deindexfuncs_n = deindexfuncs_n + 1
set deindexfuncs[deindexfuncs_n] = func
endmethod
static method addAutoCreate takes AutoCreator func returns nothing
set creators_n = creators_n + 1
set creators[creators_n] = func
endmethod
static method addAutoDestroy takes AutoDestroyer func returns nothing
set destroyers_n = destroyers_n + 1
set destroyers[destroyers_n] = func
endmethod
//===========================================================================
private static method hook_RemoveUnit takes unit whichUnit returns nothing
set removing[getIndex(whichUnit)] = true
endmethod //Intercepts whenever RemoveUnit is called and sets a flag.
private static method hook_ReplaceUnitBJ takes unit whichUnit, integer newUnitId, integer unitStateMethod returns nothing
set removing[getIndex(whichUnit)] = true
endmethod //Intercepts whenever ReplaceUnitBJ is called and sets a flag.
private static method hook_SetUnitUserData takes unit whichUnit, integer data returns nothing
static if UseUnitUserData then
if idunit[getIndex(whichUnit)] == whichUnit then
if getIndex(whichUnit) == data then
call BJDebugMsg("AutoIndex error: Code outside AutoIndex attempted to alter "+GetUnitName(whichUnit)+"'s index.")
else
call BJDebugMsg("AutoIndex error: Code outside AutoIndex altered "+GetUnitName(whichUnit)+"'s index.")
if idunit[data] != null then
call BJDebugMsg("AutoIndex error: "+GetUnitName(whichUnit)+" and "+GetUnitName(idunit[data])+" now have the same index.")
endif
set altered[data] = true
endif
endif
endif //In debug mode, intercepts whenever SetUnitUserData is used on an indexed unit.
endmethod //Displays an error message if outside code tries to alter a unit's index.
//===========================================================================
private static method allowDecay takes nothing returns nothing
local integer n = allowdecay_n
loop
exitwhen n < 0
set nodecay[getIndex(allowdecayunit[n])] = false
set allowdecayunit[n] = null
set n = n - 1
endloop
set allowdecay_n = -1
endmethod //Iterate through all the units in the stack and allow them to decay again.
private static method detectStatus takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer index = getIndex(u)
local integer n
if idunit[index] == u then //Ignore non-indexed units.
if not IsUnitType(u, UNIT_TYPE_DEAD) then
if dead[index] then //The unit was dead, but now it's alive.
set dead[index] = false //The unit has been resurrected.
//! runtextmacro optional RunAutoEvent("Resurrect")
//If AutoEvents is in the map, run the resurrection events.
if IsUnitType(u, UNIT_TYPE_SUMMONED) and not summoned[index] then
set summoned[index] = true //If the unit gained the summoned flag,
set animated[index] = true //it's been raised with Animate Dead.
//! runtextmacro optional RunAutoEvent("AnimateDead")
//If AutoEvents is in the map, run the Animate Dead events.
endif
endif
else
if not removing[index] and not dead[index] and not animated[index] then
set dead[index] = true //The unit was alive, but now it's dead.
set nodecay[index] = true //A dead unit can't decay for at least 0. seconds.
set allowdecay_n = allowdecay_n + 1 //Add the unit to a stack. After the timer
set allowdecayunit[allowdecay_n] = u //expires, allow the unit to decay again.
call TimerStart(allowdecay, 0., false, function AutoIndex.allowDecay)
//! runtextmacro optional RunAutoEvent("Death")
//If AutoEvents is in the map, run the Death events.
elseif removing[index] or (dead[index] and not nodecay[index]) or (not dead[index] and animated[index]) then
//If .nodecay was false and the unit is dead and was previously dead, the unit decayed.
//If .animated was true and the unit is dead, the unit died and exploded.
//If .removing was true, the unit is being removed or replaced.
set n = deindexfuncs_n
loop //Run the OnUnitDeindexed events.
exitwhen n < 0
call deindexfuncs[n].evaluate(u)
set n = n - 1
endloop
set n = destroyers_n
loop //Destroy AutoDestroy structs for the leaving unit.
exitwhen n < 0
call destroyers[n].evaluate(u)
set n = n - 1
endloop
call AutoIndex(index).destroy() //Free the index by destroying the AutoIndex struct.
set idunit[index] = null //Null this unit reference to prevent a leak.
endif
endif
endif
set u = null
return false
endmethod
//===========================================================================
private static method unitEntersMap takes unit u returns nothing
local integer index
local integer n = 0
if getIndex(u) != 0 then
return //Don't index a unit that already has an ID.
endif
static if LIBRARY_xebasic then
if GetUnitTypeId(u) == XE_DUMMY_UNITID then
return //Don't index xe dummy units.
endif
endif
if not UnitFilter(u) then
return //Don't index units that fail the unit filter.
endif
set index = create()
call setIndex(u, index) //Assign an index to the entering unit.
call UnitAddAbility(u, LeaveDetectAbilityID) //Add the leave detect ability to the entering unit.
call UnitMakeAbilityPermanent(u, true, LeaveDetectAbilityID) //Prevent it from disappearing on morph.
set dead[index] = IsUnitType(u, UNIT_TYPE_DEAD) //Reset all of the flags for the entering unit.
set summoned[index] = IsUnitType(u, UNIT_TYPE_SUMMONED) //Each of these flags are necessary to detect
set animated[index] = false //when a unit leaves the map.
set nodecay[index] = false
set removing[index] = false
debug set altered[index] = false //In debug mode, this flag tracks wheter a unit's index was altered.
set idunit[index] = u //Attach the unit that is supposed to have this index to the index.
if duringinit then //If a unit enters the map during initialization...
call GroupAddUnit(preplaced, u) //Add the unit to the preplaced units group. This ensures that
endif //all units are noticed by OnUnitIndexed during initialization.
loop //Create AutoCreate structs for the entering unit.
exitwhen n > creators_n
call creators[n].evaluate(u)
set n = n + 1
endloop
set n = 0
loop //Run the OnUnitIndexed events.
exitwhen n > indexfuncs_n
call indexfuncs[n].evaluate(u)
set n = n + 1
endloop
endmethod
private static method onIssuedOrder takes nothing returns boolean
static if SafeMode then //If SafeMode is enabled, perform this extra check.
if getIndex(GetTriggerUnit()) == 0 then //If the unit doesn't already have
call unitEntersMap(GetTriggerUnit()) //an index, then assign it one.
endif
endif
return GetIssuedOrderId() == 852056 //If the order is Undefend, allow detectStatus to run.
endmethod
private static method initEnteringUnit takes nothing returns boolean
call unitEntersMap(GetFilterUnit())
return false
endmethod
//===========================================================================
private static method afterInit takes nothing returns nothing
set duringinit = false //Initialization is over; set a flag.
call DestroyTimer(GetExpiredTimer()) //Destroy the timer.
call GroupClear(preplaced) //The preplaced units group is
call DestroyGroup(preplaced) //no longer needed, so clean it.
set preplaced = null
endmethod
private static method onInit takes nothing returns nothing
local region maparea = CreateRegion()
local rect bounds = GetWorldBounds()
local group g = CreateGroup()
local integer i = 15
static if not UseUnitUserData then
set ht = InitHashtable() //Only create a hashtable if it will be used.
endif
loop
exitwhen i < 0
call SetPlayerAbilityAvailable(Player(i), LeaveDetectAbilityID, false)
//Make the LeaveDetect ability unavailable so that it doesn't show up on the command card of every unit.
call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
//Register the "EVENT_PLAYER_UNIT_ISSUED_ORDER" event for each player.
call GroupEnumUnitsOfPlayer(g, Player(i), function AutoIndex.initEnteringUnit)
//Enum every non-filtered unit on the map during initialization and assign it a unique
//index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
set i = i - 1
endloop
call TriggerAddCondition(order, And(function AutoIndex.onIssuedOrder, function AutoIndex.detectStatus))
//The detectStatus method will fire every time a non-filtered unit recieves an undefend order.
//And() is used here to avoid using a trigger action, which starts a new thread and is slower.
call TriggerRegisterPlayerUnitEvent(creepdeath, Player(12), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(creepdeath, function AutoIndex.detectStatus)
//The detectStatus method must also fire when a neutral hostile creep dies, in case it was
//sleeping. Sleeping creeps don't fire undefend orders on non-damaging deaths.
call RegionAddRect(maparea, bounds) //GetWorldBounds() includes the shaded boundry areas.
call TriggerRegisterEnterRegion(enter, maparea, function AutoIndex.initEnteringUnit)
//The filter function of an EnterRegion trigger runs instantly when a unit is created.
call TimerStart(CreateTimer(), 0., false, function AutoIndex.afterInit)
//After any time elapses, perform after-initialization actions.
call GroupClear(g)
call DestroyGroup(g)
call RemoveRect(bounds)
set g = null
set bounds = null
endmethod
endstruct
//===========================================================================
// User functions:
//=================
function GetUnitId takes unit u returns integer
static if DEBUG_MODE then //If debug mode is enabled...
return AutoIndex.getIndexDebug(u) //call the debug version of GetUnitId.
else //If debug mode is disabled...
return AutoIndex.getIndex(u) //call the normal, inlinable version.
endif
endfunction
function GetUnitById takes integer id returns unit
return AutoIndex.idunit[id]
endfunction
function IsUnitIndexed takes unit u returns boolean
return AutoIndex.isUnitIndexed(u)
endfunction
function OnUnitIndexed takes IndexFunc func returns nothing
call AutoIndex.onUnitIndexed(func)
endfunction
function OnUnitDeindexed takes IndexFunc func returns nothing
call AutoIndex.onUnitDeindexed(func)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ListModule
//===========================================================================
// Information:
//==============
//
// This library provides the List module, which allows you to easily create
// a linked list of all of the allocated instances of a struct-type. Iterating
// through a linked list is about 12% faster than iteratating through an array
// in JASS. There is no faster method to iterate through a list of structs than
// the method used by this module. Aside from the marginal speed gain, the best
// use of this library is to hide some ugly low-level code from your structs.
// Rather than manually building and maintaining a list of struct instances,
// just implement the List module, and your code will become much prettier.
//
//===========================================================================
// How to use the List module:
//=============================
//
// Using the List module is pretty simple. First, implement it in your
// struct (preferably at the top to avoid unnecessary TriggerEvaluate calls).
// In the struct's create method, you must call listAdd(). In the onDestroy
// method, you must also call listRemove(). An example is shown below:
/*
struct Example
implement List
static method create takes nothing returns Example
local Example this = allocate()
call listAdd() //This method adds the instance to the list.
return this
endmethod
method onDestroy takes nothing returns nothing
call listRemove() //This method removes the instance from the list.
endmethod
endstruct
*/
// The requirement to call listAdd() and listRemove() will be done away
// with once JassHelper supports module onDestroy and module onCreate, but
// for now, it is not too much of a burden.
//
// Once this is done, your struct will gain all of the methods detailed
// in the API section. Below is an example of how to iterate through the list
// of allocated structs of the implementing struct-type:
/*
function IterationExample takes nothing returns nothing
local Example e = Example.first
loop
exitwhen e == 0
//Do something with e here.
set e = e.next
endloop
//Use .last and .prev instead to iterate backwards.
endmethod
*/
//
//===========================================================================
// List module API:
//==================
//
// (readonly)(static) first -> thistype
// This member contains the first instance of thistype in the list.
//
// (readonly)(static) last -> thistype
// This member contains the last instance of thistype in the list.
//
// (readonly)(static) count -> integer
// This member contains the number of allocated structs of thistype.
//
// (readonly) next -> thistype
// This member contains the next instance of thistype in the list.
//
// (readonly) prev -> thistype
// This member contains the previous instance of thistype in the list.
//
// listAdd()
// This method adds this instance to the list of structs of thistype.
// This should be called on each instance after it is allocated (within
// the create method).
//
// listRemove()
// This method removes this instance from the list of structs of thistype.
// This should be called on each instance before it is destroyed (within
// the onDestroy method).
//
// (static) listDestroy()
// This method destroys all the structs of thistype within the list.
//
//===========================================================================
module List
private static boolean destroying = false
private boolean inlist = false
readonly static integer count = 0
readonly thistype next = 0
readonly thistype prev = 0
static method operator first takes nothing returns thistype
return thistype(0).next
endmethod
static method operator last takes nothing returns thistype
return thistype(0).prev
endmethod
method listRemove takes nothing returns nothing
if not inlist then
return
endif
set inlist = false
set prev.next = next
set next.prev = prev
set count = count - 1
endmethod
method listAdd takes nothing returns nothing
if inlist or destroying then
return
endif
set inlist = true
set last.next = this
set prev = last
set thistype(0).prev = this
set count = count + 1
endmethod
static method listDestroy takes nothing returns nothing
local thistype this = last
set destroying = true
loop
exitwhen this == 0
call destroy()
set this = prev
endloop
set destroying = false
endmethod
endmodule
endlibrary
//TESH.alwaysfold=0
library ListModule
//===========================================================================
// Information:
//==============
//
// This library provides the List module, which allows you to easily create
// a linked list of all of the allocated instances of a struct-type. Iterating
// through a linked list is about 12% faster than iteratating through an array
// in JASS. There is no faster method to iterate through a list of structs than
// the method used by this module. Aside from the marginal speed gain, the best
// use of this library is to hide some ugly low-level code from your structs.
// Rather than manually building and maintaining a list of struct instances,
// just implement the List module, and your code will become much prettier.
//
//===========================================================================
// How to use the List module:
//=============================
//
// Using the List module is pretty simple. First, implement it in your
// struct (preferably at the top to avoid unnecessary TriggerEvaluate calls).
// In the struct's create method, you must call listAdd(). In the onDestroy
// method, you must also call listRemove(). An example is shown below:
/*
struct Example
implement List
static method create takes nothing returns Example
local Example this = allocate()
call listAdd() //This method adds the instance to the list.
return this
endmethod
method onDestroy takes nothing returns nothing
call listRemove() //This method removes the instance from the list.
endmethod
endstruct
*/
// The requirement to call listAdd() and listRemove() will be done away
// with once JassHelper supports module onDestroy and module onCreate, but
// for now, it is not too much of a burden.
//
// Once this is done, your struct will gain all of the methods detailed
// in the API section. Below is an example of how to iterate through the list
// of allocated structs of the implementing struct-type:
/*
function IterationExample takes nothing returns nothing
local Example e = Example.first
loop
exitwhen e == 0
//Do something with e here.
set e = e.next
endloop
//Use .last and .prev instead to iterate backwards.
endmethod
*/
//
//===========================================================================
// List module API:
//==================
//
// (readonly)(static) first -> thistype
// This member contains the first instance of thistype in the list.
//
// (readonly)(static) last -> thistype
// This member contains the last instance of thistype in the list.
//
// (readonly)(static) count -> integer
// This member contains the number of allocated structs of thistype.
//
// (readonly) next -> thistype
// This member contains the next instance of thistype in the list.
//
// (readonly) prev -> thistype
// This member contains the previous instance of thistype in the list.
//
// listAdd()
// This method adds this instance to the list of structs of thistype.
// This should be called on each instance after it is allocated (within
// the create method).
//
// listRemove()
// This method removes this instance from the list of structs of thistype.
// This should be called on each instance before it is destroyed (within
// the onDestroy method).
//
// (static) listDestroy()
// This method destroys all the structs of thistype within the list.
//
//===========================================================================
module List
private static boolean destroying = false
private boolean inlist = false
readonly static integer count = 0
readonly thistype next = 0
readonly thistype prev = 0
static method operator first takes nothing returns thistype
return thistype(0).next
endmethod
static method operator last takes nothing returns thistype
return thistype(0).prev
endmethod
method listRemove takes nothing returns nothing
if not inlist then
return
endif
set inlist = false
set prev.next = next
set next.prev = prev
set count = count - 1
endmethod
method listAdd takes nothing returns nothing
if inlist or destroying then
return
endif
set inlist = true
set last.next = this
set prev = last
set thistype(0).prev = this
set count = count + 1
endmethod
static method listDestroy takes nothing returns nothing
local thistype this = last
set destroying = true
loop
exitwhen this == 0
call destroy()
set this = prev
endloop
set destroying = false
endmethod
endmodule
endlibrary
//TESH.scrollpos=39
//TESH.alwaysfold=0
library mAirplanes requires ListModule, AutoIndex
/*
.~@ FINGOLFINS AIRPLANE MOVEMENT SYSTEM @~.
INSTRUCTIONS:
- Implement AutoIndex as specified in its description
- Create your airplane units as you would with any normal unit
- Set the turn speed of your airplanes to something below 0.1 (use shift-click)
- Register plane types by adding this line to the initPlaneTypes function:
call registerPlaneType('xxxx')
where 'xxxx' is the id of your airplane.
*/
//=======================//
//======= GLOBALS =======//
//=======================//
globals
private constant real INTERVAL = 0.03125 //I SUBMIT TO THIS FOLLY
private constant real DEFAULT_FACING = 270
//LOWER NUMBERS = LESS INERTIA. SET TO ZERO TO REMOVE INERTIA COMPLETELY. THIS VALUE MUST BE LOWER THAN 1!
private constant real AIR_FRICTION = 0.93
//A CONSTANT MULTIPILER TO THE UNIT SPEED, TO CIRCUMVENT THE HARDCODED SPEED LIMIT OF WC3.
private constant real SPEED_FACTOR = 1.6
//MAP BOUNDS
private real MAP_MAX_X
private real MAP_MAX_Y
private real MAP_MIN_X
private real MAP_MIN_Y
//HAVING A UNIQUE ID MIGHT BE USEFUL IF YOU WANT TO USE YOUR OWN, EXISTING HASHTABLE.
private constant integer SYSTEM_ID = StringHash("Airplanes")
private hashtable Hash = InitHashtable()
endglobals
native UnitAlive takes unit id returns boolean
//=======================//
//===== SYSTEM CODE =====//
//=======================//
private function RegisterPlaneType takes integer unitid returns nothing
call SaveInteger(Hash, SYSTEM_ID, unitid, 1)
endfunction
private function IsUnitPlane takes unit whichunit returns boolean
return HaveSavedInteger(Hash, SYSTEM_ID, GetUnitTypeId(whichunit))
endfunction
private function InitPlaneTypes takes nothing returns nothing
//REGISTER YOUR PLANE TYPES LIKE THIS
call RegisterPlaneType('h01F')
call RegisterPlaneType('h01J')
call RegisterPlaneType('h01H')
call RegisterPlaneType('h02B')
call RegisterPlaneType('h01N')
call RegisterPlaneType('h01E')
call RegisterPlaneType('h02F')
call RegisterPlaneType('h02D')
call RegisterPlaneType('h02C')
endfunction
struct Plane
implement List
unit plane = null
unit target = null
real vx = 0
real vy = 0
real tx = 0
real ty = 0
real speed = 0
integer order = 0
integer index = 0
private static timer t1
private static timer t2
private static thistype array planes
static method get takes unit whichunit returns thistype
return .planes[GetUnitId(whichunit)]
endmethod
method onDestroy takes nothing returns nothing
//DON'T GIVE ME CRAP ABOUT USING onDestroy(), IT POSES NO PERFORMANCE ISSUE IN THIS CASE.
call .listRemove()
//SAVING THE INDEX IS UGLY, BUT THE UNIT HAS ALREADY BEEN DEINDEXED AT THIS POINT.
set .planes[.index] = 0
if .count == 0 then
call PauseTimer(.t1)
call PauseTimer(.t2)
endif
endmethod
private static method updateOrder takes nothing returns nothing
local thistype this = .first
local thistype temp
local real x
local real y
if .count == 0 then
call PauseTimer(.t1)
call PauseTimer(.t2)
endif
loop
exitwhen this == 0
set temp = .next
if GetUnitTypeId(.plane) == 0 then
//DESTROY THE STRUCT WHEN THE PLANE NO LONGER EXISTS
call .destroy()
else
if .target != null then
if UnitAlive(.target) == false or GetUnitTypeId(.target) == 0 then
set .target = null
set .tx = GetUnitX(.plane)
set .ty = GetUnitY(.plane)
set .order = OrderId("attack")
else
call IssueTargetOrderById(.plane, .order, .target)
endif
else
if .order == OrderId("move") or .order == OrderId("smart") then
set x = GetUnitX(.plane)
set y = GetUnitY(.plane)
if (x - .tx)*(x - .tx) + (y - .ty)*(y - .ty) < 10000 then
//ALLOW THE UNIT TO ATTACK ONCE IT HAS REACHED ITS DESTINATION
set .order = OrderId("attack")
endif
endif
call IssuePointOrderById(.plane, .order, .tx, .ty)
endif
endif
set this = temp
endloop
endmethod
private static method updatePosition takes nothing returns nothing
local thistype this = .first
local real x = 0
local real y = 0
local real f = 0
loop
exitwhen this == 0
set f = GetUnitFacing(.plane)*bj_DEGTORAD
//ADD FRICTION FIRST INCASE IT IS ZEROED
set .vx = (.vx * AIR_FRICTION) + .speed * Cos(f)
set .vy = (.vy * AIR_FRICTION) + .speed * Sin(f)
set x = GetUnitX(.plane)+.vx
set y = GetUnitY(.plane)+.vy
//ENFORCE BOUNDS
if x > MAP_MAX_X then
set x = MAP_MAX_X
elseif x < MAP_MIN_X then
set x = MAP_MIN_X
endif
if y > MAP_MAX_Y then
set y = MAP_MAX_Y
elseif y < MAP_MIN_Y then
set y = MAP_MIN_Y
endif
call SetUnitX(.plane, x)
call SetUnitY(.plane, y)
set this = .next
endloop
endmethod
private static method onOrderTarget takes nothing returns boolean
local thistype this = thistype.get(GetTriggerUnit())
if this == 0 then
return false
endif
set .target = GetOrderTargetUnit()
set .tx = GetUnitX(.target)
set .ty = GetUnitY(.target)
set .order = GetIssuedOrderId()
return false
endmethod
private static method onOrderPoint takes nothing returns boolean
local real x = GetOrderPointX()
local real y = GetOrderPointY()
local thistype this = thistype.get(GetTriggerUnit())
if this == 0 then
return false
endif
set .tx = x
set .ty = y
set .target = null
set .order = GetIssuedOrderId()
return false
endmethod
static method create takes unit whichunit returns thistype
local thistype this = thistype.allocate()
call .listAdd()
set .planes[GetUnitId(whichunit)] = this
//=========SOME MATH TRIVIA!=========//
//The acceleration is given by the following differential equation:
// v(t)' = a = v(t) - v(t)*(1-R), where R = AIR_FRICTION
//And it's solution:
//v(t) = (a/(1-R)*(1 + e^-(1-R)t)
//Calculating the limit when (t -> infinity) gives:
//vmax = a/(1-R)
//vmax*(1-R) = a (in this case 'vmax' is known and 'a' is unknown)
//===========END OF TRIVIA===========//
set .plane = whichunit
set .speed = GetUnitDefaultMoveSpeed(.plane)*(1-AIR_FRICTION)*INTERVAL*SPEED_FACTOR
set .tx = GetUnitX(.plane) + 500 * Cos(DEFAULT_FACING*bj_DEGTORAD)
set .ty = GetUnitY(.plane) + 500 * Sin(DEFAULT_FACING*bj_DEGTORAD)
set .order = OrderId("move")
set .index = GetUnitId(whichunit)
call SetUnitMoveSpeed(.plane, 0.01)
call SetUnitFacing(.plane, DEFAULT_FACING)
call SetUnitFlyHeight(.plane, 0, 0)
call SetUnitFlyHeight(.plane, GetUnitDefaultFlyHeight(.plane), GetUnitDefaultFlyHeight(.plane)/3)
if .count == 1 then
call TimerStart(.t1, INTERVAL, true, function thistype.updatePosition)
call TimerStart(.t2, 1, true, function thistype.updateOrder)
endif
return this
endmethod
private static method onIndex takes unit u returns nothing
if IsUnitPlane(u) then
call .create(u)
endif
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local rect r = GetWorldBounds()
set MAP_MAX_X = GetRectMaxX(r)-200
set MAP_MAX_Y = GetRectMaxY(r)-200
set MAP_MIN_X = GetRectMinX(r)+200
set MAP_MIN_Y = GetRectMinY(r)+200
set Plane.t1 = CreateTimer()
set Plane.t2 = CreateTimer()
call InitPlaneTypes()
loop
exitwhen i > 11
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
set i = i+1
endloop
call TriggerAddCondition(t, Condition(function Plane.onOrderTarget))
set t = CreateTrigger()
set i = 0
loop
exitwhen i > 11
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
set i = i+1
endloop
call TriggerAddCondition(t, Condition(function Plane.onOrderPoint))
call OnUnitIndexed(thistype.onIndex)
call RemoveRect(r)
set r = null
set t = null
endmethod
endstruct
endlibrary
//TESH.alwaysfold=0
library mAirplanes requires ListModule, AutoIndex
/*
.~@ FINGOLFINS AIRPLANE MOVEMENT SYSTEM @~.
INSTRUCTIONS:
- Implement AutoIndex as specified in its description
- Create your airplane units as you would with any normal unit
- Set the turn speed of your airplanes to something below 0.1 (use shift-click)
- Register plane types by adding this line to the initPlaneTypes function:
call registerPlaneType('xxxx')
where 'xxxx' is the id of your airplane.
*/
//=======================//
//======= GLOBALS =======//
//=======================//
globals
private constant real INTERVAL = 0.03125 //I SUBMIT TO THIS FOLLY
private constant real DEFAULT_FACING = 270
//LOWER NUMBERS = LESS INERTIA. SET TO ZERO TO REMOVE INERTIA COMPLETELY. THIS VALUE MUST BE LOWER THAN 1!
private constant real AIR_FRICTION = 0.93
//A CONSTANT MULTIPILER TO THE UNIT SPEED, TO CIRCUMVENT THE HARDCODED SPEED LIMIT OF WC3.
private constant real SPEED_FACTOR = 1.6
//MAP BOUNDS
private real MAP_MAX_X
private real MAP_MAX_Y
private real MAP_MIN_X
private real MAP_MIN_Y
//HAVING A UNIQUE ID MIGHT BE USEFUL IF YOU WANT TO USE YOUR OWN, EXISTING HASHTABLE.
private constant integer SYSTEM_ID = StringHash("Airplanes")
private hashtable Hash = InitHashtable()
endglobals
native UnitAlive takes unit id returns boolean
//=======================//
//===== SYSTEM CODE =====//
//=======================//
private function RegisterPlaneType takes integer unitid returns nothing
call SaveInteger(Hash, SYSTEM_ID, unitid, 1)
endfunction
private function IsUnitPlane takes unit whichunit returns boolean
return HaveSavedInteger(Hash, SYSTEM_ID, GetUnitTypeId(whichunit))
endfunction
private function InitPlaneTypes takes nothing returns nothing
//REGISTER YOUR PLANE TYPES LIKE THIS
call RegisterPlaneType('h01F')
call RegisterPlaneType('h01J')
call RegisterPlaneType('h01H')
call RegisterPlaneType('h02B')
call RegisterPlaneType('h01N')
call RegisterPlaneType('h01E')
call RegisterPlaneType('h02F')
call RegisterPlaneType('h02D')
call RegisterPlaneType('h02C')
endfunction
struct Plane
implement List
unit plane = null
unit target = null
real vx = 0
real vy = 0
real tx = 0
real ty = 0
real speed = 0
integer order = 0
integer index = 0
private static timer t1
private static timer t2
private static thistype array planes
static method get takes unit whichunit returns thistype
return .planes[GetUnitId(whichunit)]
endmethod
method onDestroy takes nothing returns nothing
//DON'T GIVE ME CRAP ABOUT USING onDestroy(), IT POSES NO PERFORMANCE ISSUE IN THIS CASE.
call .listRemove()
//SAVING THE INDEX IS UGLY, BUT THE UNIT HAS ALREADY BEEN DEINDEXED AT THIS POINT.
set .planes[.index] = 0
if .count == 0 then
call PauseTimer(.t1)
call PauseTimer(.t2)
endif
endmethod
private static method updateOrder takes nothing returns nothing
local thistype this = .first
local thistype temp
local real x
local real y
if .count == 0 then
call PauseTimer(.t1)
call PauseTimer(.t2)
endif
loop
exitwhen this == 0
set temp = .next
if GetUnitTypeId(.plane) == 0 then
//DESTROY THE STRUCT WHEN THE PLANE NO LONGER EXISTS
call .destroy()
else
if .target != null then
if UnitAlive(.target) == false or GetUnitTypeId(.target) == 0 then
set .target = null
set .tx = GetUnitX(.plane)
set .ty = GetUnitY(.plane)
set .order = OrderId("attack")
else
call IssueTargetOrderById(.plane, .order, .target)
endif
else
if .order == OrderId("move") or .order == OrderId("smart") then
set x = GetUnitX(.plane)
set y = GetUnitY(.plane)
if (x - .tx)*(x - .tx) + (y - .ty)*(y - .ty) < 10000 then
//ALLOW THE UNIT TO ATTACK ONCE IT HAS REACHED ITS DESTINATION
set .order = OrderId("attack")
endif
endif
call IssuePointOrderById(.plane, .order, .tx, .ty)
endif
endif
set this = temp
endloop
endmethod
private static method updatePosition takes nothing returns nothing
local thistype this = .first
local real x = 0
local real y = 0
local real f = 0
loop
exitwhen this == 0
set f = GetUnitFacing(.plane)*bj_DEGTORAD
//ADD FRICTION FIRST INCASE IT IS ZEROED
set .vx = (.vx * AIR_FRICTION) + .speed * Cos(f)
set .vy = (.vy * AIR_FRICTION) + .speed * Sin(f)
set x = GetUnitX(.plane)+.vx
set y = GetUnitY(.plane)+.vy
//ENFORCE BOUNDS
if x > MAP_MAX_X then
set x = MAP_MAX_X
elseif x < MAP_MIN_X then
set x = MAP_MIN_X
endif
if y > MAP_MAX_Y then
set y = MAP_MAX_Y
elseif y < MAP_MIN_Y then
set y = MAP_MIN_Y
endif
call SetUnitX(.plane, x)
call SetUnitY(.plane, y)
set this = .next
endloop
endmethod
private static method onOrderTarget takes nothing returns boolean
local thistype this = thistype.get(GetTriggerUnit())
if this == 0 then
return false
endif
set .target = GetOrderTargetUnit()
set .tx = GetUnitX(.target)
set .ty = GetUnitY(.target)
set .order = GetIssuedOrderId()
return false
endmethod
private static method onOrderPoint takes nothing returns boolean
local real x = GetOrderPointX()
local real y = GetOrderPointY()
local thistype this = thistype.get(GetTriggerUnit())
if this == 0 then
return false
endif
set .tx = x
set .ty = y
set .target = null
set .order = GetIssuedOrderId()
return false
endmethod
static method create takes unit whichunit returns thistype
local thistype this = thistype.allocate()
call .listAdd()
set .planes[GetUnitId(whichunit)] = this
//=========SOME MATH TRIVIA!=========//
//The acceleration is given by the following differential equation:
// v(t)' = a = v(t) - v(t)*(1-R), where R = AIR_FRICTION
//And it's solution:
//v(t) = (a/(1-R)*(1 + e^-(1-R)t)
//Calculating the limit when (t -> infinity) gives:
//vmax = a/(1-R)
//vmax*(1-R) = a (in this case 'vmax' is known and 'a' is unknown)
//===========END OF TRIVIA===========//
set .plane = whichunit
set .speed = GetUnitDefaultMoveSpeed(.plane)*(1-AIR_FRICTION)*INTERVAL*SPEED_FACTOR
set .tx = GetUnitX(.plane) + 500 * Cos(DEFAULT_FACING*bj_DEGTORAD)
set .ty = GetUnitY(.plane) + 500 * Sin(DEFAULT_FACING*bj_DEGTORAD)
set .order = OrderId("move")
set .index = GetUnitId(whichunit)
call SetUnitMoveSpeed(.plane, 0.01)
call SetUnitFacing(.plane, DEFAULT_FACING)
call SetUnitFlyHeight(.plane, 0, 0)
call SetUnitFlyHeight(.plane, GetUnitDefaultFlyHeight(.plane), GetUnitDefaultFlyHeight(.plane)/3)
if .count == 1 then
call TimerStart(.t1, INTERVAL, true, function thistype.updatePosition)
call TimerStart(.t2, 1, true, function thistype.updateOrder)
endif
return this
endmethod
private static method onIndex takes unit u returns nothing
if IsUnitPlane(u) then
call .create(u)
endif
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local rect r = GetWorldBounds()
set MAP_MAX_X = GetRectMaxX(r)-200
set MAP_MAX_Y = GetRectMaxY(r)-200
set MAP_MIN_X = GetRectMinX(r)+200
set MAP_MIN_Y = GetRectMinY(r)+200
set Plane.t1 = CreateTimer()
set Plane.t2 = CreateTimer()
call InitPlaneTypes()
loop
exitwhen i > 11
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
set i = i+1
endloop
call TriggerAddCondition(t, Condition(function Plane.onOrderTarget))
set t = CreateTrigger()
set i = 0
loop
exitwhen i > 11
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
set i = i+1
endloop
call TriggerAddCondition(t, Condition(function Plane.onOrderPoint))
call OnUnitIndexed(thistype.onIndex)
call RemoveRect(r)
set r = null
set t = null
endmethod
endstruct
endlibrary















































































































































































































































































































































































































































































































































































































































































































































































































































