[Infrastructure/System(?)] The Utilities Library (JASS)
An infrastructure Library used in many of my Systems.
REQUIREMENTS:
JassPack NewGen
FEATURES:
Can convert integers into hexstrings ( for string coloring ) with Hex2S( integer, ndigits ) ( only ndigits digits of the hex integer will be put into the string )
Can color a string according to a percentage ( EG: 100% -> Green, 50% -> brown, 0% -> Red ) with State2Color( real state ) // state is between 0 and 1
Comes with four strings to color messages in a coordinated way: RED, GREEN, GREY and GOLD ( just use string = RED + "You have been killed!" )
Can create bounty tags ( and the bounty effect ) that just look like the Wc3 ones with CreateBountyText( integer amount, unit target, player getter ): This will display the bounty text above unit target. Bounty text is only visible for getter. Btw, if the amount is negative, color will be changed to red and it will bear a minus sign insted of the + sign.
You can also use a color you want with the bounty texts. Just use CreateColoredBountyText( string color, integer amount, unit target, player getter )
Comes with StartLocX[ playerId ] / StartLocY[ playerId ] for the start location x and y of Player(playerId)
Comes with variables for players, although I don't know if that is really faster than Player( x ): Players[ x ]
Comes with the unformatted names for name checking ( is faster than the GetPlayerName() function ): PlayerStartName[ playerId ]
Comes with autocolored playernames PlayerName[ playerid ] ( is colored for text output ). Uncolored ones are PlayerNameUncolored[ playerId ]
Needs another namechange command, that is: SetPlayerNameSJ( player, name ). This changes PlayerName/PlayerNameUncolored accordingly. PlayerStartName will not be altered!
Alternatively to the normal player text colors, you can set a players text colors with SetPlayerColors( integer playerid, integer red, integer green, integer blue ). It won't affect the player's name in the interface, as the normal coloring does not work here. I'm still trying to find a way for fixing this.
Has a Leaver handler that fires whenever a player leaves. Displays a message, and changes the players name to GREY+Name+ (LEFT).
The message shown on player leave can be altered in the parameters. It will use the message of the parameters ( LEAVER_MESSAGE ), but enter the players name at the position of the "%p" string. If there is no %p, no name will be displayed.
The trigger to attach leaver actions to is LEAVER_HANDLER. You can, but needn't create your own one.
Has a function to calculate the distance between units. DistanceBetweenUnits( unit a, unit b ), as fast as I could get it. You most probably have your own function here ; )
Has a function to register the chat event of any player. Saves me the pain in the neck Chat events normally are. TriggerRegisterAnyPlayerChatEvent( trigger register, string chat, boolean exactmatchonly )
Has two functions to create n units, one of them issues a point order - good for spawning. CreateNUnitsAngle( player owner, integer unittype, real x, real y, real angle, integer number ) and CreateNUnitsOrder( player owner, integer unittype, real x, real y, integer number, string order, real targetx, real targety ) . The last one sets the angle towards the direction of the order x/y. Note also that it returns a unit group that you can use, but it is MUI only to some extent. Using
localgroup g = CreateNUnitsAngle( Players[0], 'hfoo', 0, 0, 270, 7 ) call CreateNUnitsAngle( Players[1], 'hfoo', 512, 0, 270, 7 ) // g will now be the units at 512|0, not the ones at 0|0 !!!
In order to still use g, you'ld need to do the following:
localgroup g = CreateGroup() call GroupAddGroup( CreateNUnitsAngle( Players[0], 'hfoo', 0, 0, 270, 7 ), g ) call CreateNUnitsAngle( Players[1], 'hfoo', 512, 0, 270, 7 ) // g will now be the units at 0|0, not the ones at 512|0 !!!
The SetPlayerAllianceStateSJ( player one, player two, integer alliancestate ) function does the same like the BJ, just that it allies in both ways, saves all if clauses and lots of function calls.
Has a function to retrieve either the closest or the farest unit in a certain range. GetClosestUnitInRange( real x, real y, real radius, boolean closest, boolexpr filter ).
Comes with a function to have a player win/loose with a certain message. WinGame( player whichPlayer, boolean win, string message ). Creates the dialogs etc.
Comes with the PlayerActive[ playerId ] array that is set to true when the slot is used by either a computer player or an user. Will be automatically set to false when a player leaves, looses or if the slot was not filled at map start.
Has MAX_INV_SLOT ( 5, maximum item slot ), MAX_PLAYER_SLOT ( 15, maximum player slot ) and MAX_USER_SLOT ( 11, maximum user slot ) constants for looping through all players, the user players, and an inventory
a ReturnHandle variable in order to fix the returnbug handle-leaks ( return location etc ). In the utilities, there is only one function that returns a handle, but that function uses it ; D
Has a textmacro for randomized string output. Tiny, yet useful, you can add strings to a stack and use a function to retrieve a random one of them.
//! runtextmacro RandomString( "Name" )
for Stack Creation;
call AddNameString("Jones") call AddNameString("Sarah") call AddNameString("Tim") call GetNameString()// Gets a random 'Name' string; In this case either Jones, Sarah or Tim. call AddNameString("Jones") call AddNameString("Carol") call GetNameString()// Gets a random 'Name' string; In this case either Jones, Sarah, Carol or Tim. Note that the chance to get 'Jones' is twice as high.
Has 2 functions that convert an alphanumerical string into a number and back. NOT TO BE CONFUSED WITH ASCII! However, 'A' will score lower than 'B' and 'AB'. Can be used for alphabetical sorting or for saveload codes or whatever. Non-Alphanumerical characters will not be retrieved when you revert the number to a string; They will simply be left out ( 'Cpt.Davey' will become 'CptDavey' ). The case is ignored. The Char2I function only processes on a substring of the argument, which is chosen by the two min and max parameters.
If the span is to big, it might get an overflow error! You should always use 6 letters at max.
Has a DisplayText( player, text ) function that actually does nothing but call DisplayTimedTextToPlayer( player, 0, 0, 15, text ). JASSHelper 0.9.9.E.0 inlines this so it is as fast as the normal function, but it saves 50% of the time and is easier to read.
Has a GetHandleId function, that does but H2I(). I didn't want to use H2I as name becouse it is overused and might get a syntax with a non-scoped H2I.
. This sets the (row|col) item's stats. If value is "" ( empty string ), it won't show the text; If iconfilename is "", it won't show the icon, if width is 0 or smaller, it will not alter the item's width at all. If whichplayer is null, it will apply the changes for everyone - elsewise just for whichplayer. If row is -1, it will affect all rows; If col is -1, it will affect all cols. If multiboard is null, it will crash ; D
Comes with a handy textmacro for state 2 text conversion. That means, a Text ( like empty, or full ) can be mapped to State A ( like 0%, or 100% ) and then be retrieved with a function. With Empty: 0% and Full 100%, everything that is less than 100% will return Empty, and everything above will return Full. This is nice when you want to output certain states of anything without having to do an enourmous if-cluster whenever you want to use it. The syntax is:
will print to the screen:
Wounded
Dead
Ok
( with the right coloring )
NEW
There is a global variable for the GetLocalPlayer() function: LOCAL_PLAYER
Perhaps you have remarked Blizzards Multiboard flaw: Only one can be displayed at the same time. When you display another one, the first one will no longer be displayed - and without a huge amount of coding, it is impossible to regain the old multiboard once the new one is destroyed.
The Utilities library comes with a function that handles this problem:
When invoked with true, the function will store the last displayed multiboard of player, and when invoked with false, return it. Works with up to 680 Multiboards per player ( at average. You can also concentrate 8191 on one single player ), but might get a bit slower by that time ; )
I hope it is helpful for someone, I use it mainly for coordination purposes of style ( not using 5 different reds for negative warnings, lol ) and for not having to code the "pain in the neck" functions everytime I use them.
If you should find a bug ( which is really unprobable, I have been using most of these functions for almost half a year now and haven't found anything ), or have a suggestion for a function / constant that should make it into this Library, just post here.
Greetings to all, Davey Jones
Code
//----------------------------\\ // VER B2 \\ //----------------------------\\
// Special thanks: Tom_Kazansky for his incredible wisdom concerning the creation of texttags ; ) // PurplePoot for his countless tips on what to improve!
library UtilityParameters globals // parameters // for parameter coloring // GOLD will be used as the display color for positive bounty created with CreateBountyText() // RED will be used as the display color for negative bounty created with CreateBountyText()
function Text2$STATE$ takesstring text, real state returnsnothing localreal curKey = state localstring parKey = text localinteger index = $STATE$s localinteger curdex = index - 1 set $STATE$s = $STATE$s + 1 loop exitwhen index < 1 exitwhen curKey >= $STATE$State[ curdex ] set $STATE$State[ index ] = $STATE$State[ curdex ] set $STATE$Name[ index ] = $STATE$Name[ curdex ] set index = curdex set curdex = index - 1 endloop
set $STATE$State[ index ] = curKey set $STATE$Name[ index ] = parKey endfunction
function $STATE$2Text takesreal state returnsstring localinteger index = 0 loop if $STATE$State[ index ] >= state then set index = index - 1 if index < 0 then set index = 0 endif exitwhentrue endif exitwhen index >= $STATE$s - 1 set index = index + 1 endloop return $STATE$Name[ index ] endfunction //! endtextmacro
globals // Do not change these! playerarray Players constantinteger NUMPLAYERS = 15 constantinteger MAX_PLAYER_SLOT = 15
loop exitwhen digits <= 0 set curDigit = ModuloInteger( hex, HexBase ) set hex = hex / HexBase set hexstring = Hex[ curDigit ] + hexstring set digits = digits - 1 endloop return hexstring endfunction
function DistanceBetweenUnits takesunit a, unit b returnsreal localreal deltaX = GetUnitX( a ) - GetUnitX( b ) localreal deltaY = GetUnitY( a ) - GetUnitY( b ) set a = null set b = null return SquareRoot( deltaX * deltaX + deltaY * deltaY ) endfunction
function GetHandleId takeshandle h returnsinteger return h return 0 endfunction
function State2Color takesreal state returnsstring localinteger hex = R2I( state * 204 ) if hex > 204 then set hex = 204 elseif hex < 0 then set hex = 0 endif return"|cff" + Hex2S( 255 - hex, 2 ) + Hex2S( 51 + hex, 2 ) + "20" endfunction
function SetPlayerNameSJ takesplayer whichplayer, string name returnsnothing localinteger playerId = GetPlayerId( whichplayer ) set PlayerName[ playerId ] = PlayerColor[ playerId ] + name set PlayerNameUncolored[ playerId ] = name call SetPlayerName( whichplayer, name ) endfunction
function SetAllianceState takesinteger alliancestate, boolean passive, boolean helprequest, boolean helpresponse, boolean sharedxp, boolean sharedspells, boolean sharedvision, boolean sharedcontrol, boolean sharedadvancedcontrol returnsnothing if alliancestate >= 0 and alliancestate <= 8 then set PLAYER_ALLIANCE_STATE_PASSIVE[ alliancestate ] = passive set PLAYER_ALLIANCE_STATE_HELP_REQUEST[ alliancestate ] = helprequest set PLAYER_ALLIANCE_STATE_HELP_RESPONSE[ alliancestate ] = helpresponse set PLAYER_ALLIANCE_STATE_SHARED_XP[ alliancestate ] = sharedxp set PLAYER_ALLIANCE_STATE_SHARED_SPELLS[ alliancestate ] = sharedspells set PLAYER_ALLIANCE_STATE_ALLIANCE_SHARED_VISION[ alliancestate ] = sharedvision set PLAYER_ALLIANCE_STATE_ALLIANCE_SHARED_CONTROL[ alliancestate ] = sharedcontrol set PLAYER_ALLIANCE_STATE_ALLIANCE_SHARED_ADVANCED_CONTROL[ alliancestate ] = sharedadvancedcontrol endif endfunction
privatefunction AddLetter takesstring char returnsnothing set LETTER[ LETTERS ] = char set LETTERS = LETTERS + 1 endfunction
struct multiboardchain player owner multiboardchain_member first multiboardchain_member last staticmethod create takesplayer owner returns multiboardchain local multiboardchain this = .allocate() set .owner = owner set .first = 0 set .last = 0 return this endmethod endstruct
struct multiboardchain_member multiboard mb multiboardchain parent multiboardchain_member next multiboardchain_member last staticmethod create takesmultiboard mb, multiboardchain parent returns multiboardchain_member local multiboardchain_member this local multiboardchain_member curChild = parent.first
if parent.first == 0 then set this = .allocate() set parent.first = this else loop exitwhen curChild == 0 if curChild.mb == mb then call curChild.reAppend() return curChild endif set curChild = curChild.next endloop set this = .allocate() endif
set .mb = mb set .parent = parent set .last = .parent.last set .parent.last = this set .last.next = this set .next = 0 if LOCAL_PLAYER == .parent.owner then if .last != 0 then call MultiboardDisplay( .last.mb, false) endif call MultiboardDisplay( mb, true) endif return this endmethod
// drops the chain member from the chain and fixes the chain method drop takesnothingreturnsnothing localboolean isLast = .next == 0 localboolean isFirst = .last == 0 if isLast and isFirst then set .parent.last = 0 set .parent.first = 0 elseif isLast then set .parent.last = .last set .last.next = 0 elseif isFirst then set .parent.first = .next set .next.last = 0 else set .next.last = .last set .last.next = .next endif endmethod
method reAppend takesnothingreturnsnothing // fix chain call .drop() // append self set .last = .parent.last set .parent.last = this set .last.next = this if LOCAL_PLAYER == .parent.owner then if .last != 0 then call MultiboardDisplay( .last.mb, false) endif call MultiboardDisplay( .mb, true) endif endmethod
method onDestroy takesnothingreturnsnothing localboolean view = LOCAL_PLAYER == .parent.owner localboolean showLast = ( .next == 0 )and( .last != 0 ) if view then call MultiboardDisplay( .mb, false) if showLast then call MultiboardDisplay( .last.mb, true) endif endif call .drop()
set .mb = null endmethod endstruct
function MultiboardDisplaySJ takesmultiboard mb, boolean display, player viewer returnsnothing local multiboardchain parent local multiboardchain_member curChild localboolean view
if viewer == nullthen set viewer = LOCAL_PLAYER endif
set view = viewer == LOCAL_PLAYER set parent = MBChain[ GetPlayerId( viewer )] if display then call multiboardchain_member.create( mb, parent ) else set curChild = parent.last loop exitwhen curChild == 0 if curChild.mb == mb then call curChild.destroy() set view = false exitwhentrue endif set curChild = curChild.last endloop if view then call MultiboardDisplay( mb, false) endif endif endfunction
if DISPLAY_LEAVER_NAME then call TriggerAddAction( LEAVER_HANDLER, function LeaverHandlerName_Actions ) else call TriggerAddAction( LEAVER_HANDLER, function LeaverHandlerNoName_Actions ) endif
function CreateNUnits takesplayer owner, integer unittypeid, real x, real y, integer n returnsgroup call GroupClear( GLOBAL_GROUP ) loop exitwhen n <= 0 call GroupAddUnit( GLOBAL_GROUP, CreateUnit( owner, unittypeid, x, y, GetRandomReal( 0, 360 ))) set n = n - 1 endloop return GLOBAL_GROUP endfunction
function CreateNUnitsAngle takesplayer owner, integer unittypeid, real x, real y, real angle, integer n returnsgroup call GroupClear( GLOBAL_GROUP ) loop exitwhen n <= 0 call GroupAddUnit( GLOBAL_GROUP, CreateUnit( owner, unittypeid, x, y, angle )) set n = n - 1 endloop return GLOBAL_GROUP endfunction
function CreateNUnitsOrder takesplayer owner, integer unittypeid, real x, real y, integer n, string order, real targetx, real targety returnsgroup localreal angle = Atan2( y-targety, x-targetx ) localunit loopUnit call GroupClear( GLOBAL_GROUP ) loop exitwhen n <= 0 set loopUnit = CreateUnit( owner, unittypeid, x, y, angle ) call GroupAddUnit( GLOBAL_GROUP, loopUnit ) call IssuePointOrder( loopUnit, order, targetx, targety ) set n = n - 1 endloop set loopUnit = null return GLOBAL_GROUP endfunction
function GetClosestUnitInRange takesreal x, real y, real radius, boolean closest, boolexpr filter returnsunit localgroup g = GLOBAL_GROUP localunit curUnit = null localunit loopUnit localreal curDist localreal dX localreal dY localreal loopDist call GroupClear( g ) call GroupEnumUnitsInRange( g, x, y, radius, filter ) if closest then set curDist = radius + 1 else set curDist = 0 endif loop set loopUnit = FirstOfGroup( g ) exitwhen loopUnit == null set dX = x - GetUnitX( loopUnit ) set dY = y - GetUnitY( loopUnit ) set loopDist = SquareRoot( dX * dX + dY * dY ) if loopDist < curDist == closest then set curDist = loopDist set curUnit = loopUnit endif call GroupRemoveUnit( g, loopUnit ) endloop set ReturnHandle = curUnit set filter = null set loopUnit = null set curUnit = null return ReturnHandle endfunction
function EndMap takesnothingreturnsnothing call EndGame(true) endfunction
function WinGame takesplayer whichPlayer, boolean win, string message returnsnothing localtrigger t = CreateTrigger() localdialog d = DialogCreate () localplayer localPlayer = LOCAL_PLAYER
if win then call RemovePlayer ( whichPlayer, PLAYER_GAME_RESULT_VICTORY ) else call RemovePlayer ( whichPlayer, PLAYER_GAME_RESULT_DEFEAT ) endif
function SetMultiboardItemValue takesmultiboard mb, integer row, integer col, string value, string iconfilename, real width, player whichplayer returnsnothing localmultiboarditem curItem localboolean showIcon = iconfilename != "" localboolean showValue = value != "" localboolean changeWidth = width > 0 localinteger minCol localinteger maxCol localinteger minRow localinteger maxRow localinteger i localinteger j if col == - 1 then set minCol = 0 set maxCol = MultiboardGetColumnCount( mb ) else set minCol = col set maxCol = col + 1 endif if row == -1 then set minRow = 0 set maxRow = MultiboardGetRowCount( mb ) else set minRow = row set maxRow = row + 1 endif
set col = minCol
loop exitwhen col >= maxCol
set row = minRow loop exitwhen row >= maxRow set curItem = MultiboardGetItem( mb, row, col ) if whichplayer == nullor whichplayer == LOCAL_PLAYER then call MultiboardSetItemStyle( curItem, showValue, showIcon ) if showIcon then call MultiboardSetItemIcon( curItem, iconfilename ) endif if showValue then call MultiboardSetItemValue( curItem, value ) endif if changeWidth then call MultiboardSetItemWidth( curItem, width ) endif endif