• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] PlayerAbility

Level 6
Joined
Jan 9, 2019
Messages
102
JASS:
library PlayerAbility requires Table, PlayerUtils //wc3_v1.29+
//== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
//  __________________
//   #  PlayerAbility
//			v1.2c, by Overfrost
//	----------------------------
//
//	  - packs abilityId, abilityLevel, and abilityOwner into one package,
//		allowing better manipulation of abilityUI
//
//	  - handles both global abilityUI and each player's abilityUI,
//		prioritizing player's abilityUI over the global
//
//  ______________
//   #  Requires:
//
//	  v Warcraft3 v1.29+
//    - Table
//          hiveworkshop.com/threads/snippet-new-table.188084
//	  - PlayerUtils
//			hiveworkshop.com/threads/playerutils.278559
//
//== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
//! novjass

    //
    struct PlayerAbility extends array

        //------------
        // Instancer
        //
        static method get takes integer abilId, integer level, player owner returns thistype
		// - if owner = null, then returns the global ability, otherwise returns a player's ability
        // - no destructors
        //

        //---------------
        // Basic Fields
        //
        integer id     // abilId
		integer level
		player owner
		// - if any of these changes, the instance itself also changes
		// - any field other than these are not copied to the new instance
		//

		//-------------------
		// All Level Fields
		//
		integer posX
		integer posY
		// - can take any positive integers or 0
		//
		string icon
		// - all of those apply to all levels of the ability, at once
		//

		//-------------------
		// Per Level Fields
		//
		string name  // Tooltip
		string desc  // ExtendedTooltip
		//
		string learnName  // ResearchTooltip
		string learnDesc  // ResearchExtendedTooltip
		//
		string actedName  // ActivatedTooltip
		string actedDesc  // ActivatedExtendedTooltip
		//

        //----------
        // Methods
        //
		method clearPos takes nothing returns thistype(this)   // posX/posY
		method clearIcon takes nothing returns thistype(this)
		//
		method clearTip takes nothing returns thistype(this)       // name/desc
		method clearLearnTip takes nothing returns thistype(this)  // learnName/learnDesc
		method clearActedTip takes nothing returns thistype(this)  // actedName/actedDesc
		//
		method clear takes nothing returns thistype(this)  // all
		// - for all above:
		//   - if this ability is global, clears the modifications of each player's ability
		//   - otherwise clears the modifications of this player's ability only
		//   - can't clear the modifications of a global ability itself
        //

//! endnovjass
//== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====

//
private keyword pm
struct PlayerAbility extends array
	//
	private static integer pgCount = 0
	private static integer pgH0
	private static integer pgH1

	//---------
	// fields
	private static Table pgId
	private static Table pgAbiId
	//
	private static Table pgPos
	private static Table pgIcon
	//
	private static Table pgTip
	private static Table pgLearnTip
	private static Table pgActedTip

	//-------
	// hash
	private static method pgHash takes integer aId, integer aLevel, integer aUser returns integer
		return aId*pgH1 + aLevel*pgH0 + aUser
	endmethod //inlines
	private static method pgHash2 takes integer aId, integer aUser returns integer
		return aId*pgH1 + aUser
	endmethod //inlines
	// indeed 0 to (pgH1-1) are skipped, this is intended

	//
	static method get takes integer aAbiId, integer aLevel, player aOwner returns thistype
	//! textmacro P_PLAYER_ABILITY_GET takes ABI_ID
			//
			local integer lId = pgId[$ABI_ID$]
			local integer lHash
			//
			if (lId == 0) then
				set pgCount = pgCount + 1
				set lId = pgCount
				//
				set pgId[$ABI_ID$] = lId
				set pgAbiId[lId] = $ABI_ID$
			endif
			//
			set lHash = pgHash2(lId, bj_MAX_PLAYER_SLOTS)
			//
	//! endtextmacro
	//! runtextmacro P_PLAYER_ABILITY_GET("aAbiId")
		//
	//! textmacro P_PLAYER_ABILITY_SET_GLOBAL takes B, ABI_ID, LEVEL
			//
			static if ($B$) then
				if (not pgPos.has(lHash)) then
					set pgPos[ lHash] = BlzGetAbilityPosX($ABI_ID$)
					set pgPos[-lHash] = BlzGetAbilityPosY($ABI_ID$)
					//
					set pgIcon.string[lHash] = BlzGetAbilityIcon($ABI_ID$)
				endif
				//
				set lHash = lHash + $LEVEL$*pgH0
			endif
			//
			if (not pgTip.string.has(lHash)) then
				set pgTip.string[ lHash] = BlzGetAbilityTooltip($ABI_ID$, $LEVEL$)
				set pgTip.string[-lHash] = BlzGetAbilityExtendedTooltip($ABI_ID$, $LEVEL$)
				//
				set pgLearnTip.string[ lHash] = BlzGetAbilityResearchTooltip($ABI_ID$, $LEVEL$)
				set pgLearnTip.string[-lHash] = BlzGetAbilityResearchExtendedTooltip($ABI_ID$, $LEVEL$)
				//
				set pgActedTip.string[ lHash] = BlzGetAbilityActivatedTooltip($ABI_ID$, $LEVEL$)
				set pgActedTip.string[-lHash] = BlzGetAbilityActivatedExtendedTooltip($ABI_ID$, $LEVEL$)
			endif
			//
	//! endtextmacro
	//! runtextmacro P_PLAYER_ABILITY_SET_GLOBAL("true", "aAbiId", "aLevel")
		//
		if (aOwner == null) then
			return lHash
		endif
		//
		return lHash - bj_MAX_PLAYER_SLOTS + User[aOwner]
	endmethod

	//----------
	// helpers
	private method pId takes thistype aThis returns integer
		return (this - (aThis/pgH0)*pgH0)/pgH1
	endmethod //inlines
	private method pUser takes thistype aThis returns User
		return this - (aThis/pgH1)*pgH1
	endmethod //inlines

	//---------------
	// basic fields
	method operator id takes nothing returns integer
		return pgAbiId[pId(this)]
	endmethod
	method operator level takes nothing returns integer
		return this/pgH0
	endmethod //inlines
	method operator owner takes nothing returns player
		return pUser(this).toPlayer()
	endmethod
	//
	method operator id= takes integer aAbiId returns thistype
		local integer lLevel = level
		//
	//! runtextmacro P_PLAYER_ABILITY_GET("aAbiId")
		//
	//! runtextmacro P_PLAYER_ABILITY_SET_GLOBAL("true", "aAbiId", "lLevel")
		//
		return lHash - bj_MAX_PLAYER_SLOTS + pUser(this)
	endmethod
	method operator level= takes integer aLevel returns thistype
		local integer lId = pId(this)
		local integer lAbiId = pgAbiId[lId]
		//
		local integer lHash = pgHash(lId, aLevel, bj_MAX_PLAYER_SLOTS)
		//
	//! runtextmacro P_PLAYER_ABILITY_SET_GLOBAL("false", "lAbiId", "aLevel")
		//
		return lHash - bj_MAX_PLAYER_SLOTS + pUser(this)
	endmethod
	method operator owner= takes player aOwner returns thistype
		return (this/pgH1)*pgH1 + User[aOwner]
	endmethod //inlines

	//------------------
	// unilevel fields
//! textmacro P_PLAYER_ABILITY_ULEVEL_FIELD takes ID, TAB, SIGN, TYPE, SUFFIX, C, SIZE
		//
		method operator $ID$ takes nothing returns $TYPE$
			set this = this - (this/pgH0)*pgH0
			if ($TAB$.$TYPE$.has($SIGN$this)) then
				return $TAB$.$TYPE$[$SIGN$this]
			endif
			//
			return $TAB$.$TYPE$[$SIGN$pgHash2(pId(this), bj_MAX_PLAYER_SLOTS)]
		endmethod
		method operator $ID$= takes $TYPE$ aVal returns nothing
			local integer lId = pId(this)
			local integer lAbiId = pgAbiId[lId]
			//
			local User lUser = pUser(this)
			//
		$C$ set aVal = aVal - (aVal/$SIZE$)*$SIZE$
			//
			if (lUser == bj_MAX_PLAYER_SLOTS) then
				set $TAB$.$TYPE$[$SIGN$pgHash2(lId, bj_MAX_PLAYER_SLOTS)] = aVal
				//
				set lUser = User.first
				loop
					//
					if ((not $TAB$.$TYPE$.has($SIGN$pgHash2(lId, lUser))) and User.LocalId == lUser) then
						call BlzSetAbility$SUFFIX$(lAbiId, aVal)
					endif
					//
					exitwhen lUser == User.last
					set lUser = lUser.next
				endloop
				//
				return
			endif
			//
			if (User.LocalId == lUser) then
				call BlzSetAbility$SUFFIX$(lAbiId, aVal)
			endif
			//
			set $TAB$.$TYPE$[$SIGN$pgHash2(lId, lUser)] = aVal
		endmethod
//! endtextmacro
	//
//! runtextmacro P_PLAYER_ABILITY_ULEVEL_FIELD("posX", "pgPos",  "", "integer", "PosX", "", "4")
//! runtextmacro P_PLAYER_ABILITY_ULEVEL_FIELD("posY", "pgPos", "-", "integer", "PosY", "", "3")
	//
//! runtextmacro P_PLAYER_ABILITY_ULEVEL_FIELD("icon", "pgIcon", "", "string", "Icon", "//", "")

	//--------------------
	// multilevel fields
//! textmacro P_PLAYER_ABILITY_TOOLTIP_FIELD takes ID, TAB, SIGN, INFIX
		//
		method operator $ID$ takes nothing returns string
			if ($TAB$.string.has($SIGN$this)) then
				return $TAB$.string[$SIGN$this]
			endif
			return $TAB$.string[$SIGN$pgHash(pId(this), level, bj_MAX_PLAYER_SLOTS)]
		endmethod
		method operator $ID$= takes string aTip returns nothing
			local integer lId = pId(this)
			local integer lAbiId = pgAbiId[lId]
			local integer lLevel = level
			//
			local User lUser = pUser(this)
			//
			if (lUser == bj_MAX_PLAYER_SLOTS) then
				set lUser = User.first
				loop
					//
					if ((not $TAB$.string.has($SIGN$pgHash(lId, lLevel, lUser))) and User.LocalId == lUser) then
						call BlzSetAbility$INFIX$Tooltip(lAbiId, aTip, lLevel)
					endif
					//
					exitwhen lUser == User.last
					set lUser = lUser.next
				endloop
				//
			elseif (User.LocalId == lUser) then
				call BlzSetAbility$INFIX$Tooltip(lAbiId, aTip, lLevel)
			endif
			//
			set $TAB$.string[$SIGN$this] = aTip
		endmethod
//! endtextmacro
	//
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("name", "pgTip",  "", "")
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("desc", "pgTip", "-", "Extended")
	//
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("learnName", "pgLearnTip",  "", "Research")
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("learnDesc", "pgLearnTip", "-", "ResearchExtended")
	//
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("actedName", "pgActedTip",  "", "Activated")
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_FIELD("actedDesc", "pgActedTip", "-", "ActivatedExtended")

	//--------------------
	// unilevel clearers
//! textmacro P_PLAYER_ABILITY_ULEVEL_CLEAR takes ID, TAB, C, TYPE, OP0, OP1, SUFFIX0, SUFFIX1
		//
		method clear$ID$ takes nothing returns thistype
			local integer lId = pId(this)
			local integer lAbiId = pgAbiId[lId]
			//
			local User lUser = pUser(this)
			//
			local thistype lHash = pgHash2(lId, bj_MAX_PLAYER_SLOTS)
			local $TYPE$ lVal0 = lHash.$OP0$
		$C$ local $TYPE$ lVal1 = lHash.$OP1$
			//
			if (lUser == bj_MAX_PLAYER_SLOTS) then
				set lUser = User.first
				loop
					set lHash = pgHash2(lId, lUser)
					//
					call $TAB$.$TYPE$.remove( lHash)
				$C$ call $TAB$.$TYPE$.remove(-lHash)
					//
					if (User.LocalId == lUser) then
						call BlzSetAbility$SUFFIX0$(lAbiId, lVal0)
					$C$ call BlzSetAbility$SUFFIX1$(lAbiId, lVal1)
					endif
					//
					exitwhen lUser == User.last
					set lUser = lUser.next
				endloop
			else
				set lHash = pgHash2(lId, lUser)
				//
				call $TAB$.$TYPE$.remove( lHash)
			$C$ call $TAB$.$TYPE$.remove(-lHash)
				//
				if (User.LocalId == lUser) then
					call BlzSetAbility$SUFFIX0$(lAbiId, lVal0)
				$C$ call BlzSetAbility$SUFFIX1$(lAbiId, lVal1)
				endif
			endif
			//
			return this
		endmethod
//! endtextmacro
	//
//! runtextmacro P_PLAYER_ABILITY_ULEVEL_CLEAR("Pos",  "pgPos",   "", "integer", "posX", "posY", "PosX", "PosY")
//! runtextmacro P_PLAYER_ABILITY_ULEVEL_CLEAR("Icon", "pgIcon", "//", "string", "icon", ""    , "Icon", "")

	//-------------------
	// tooltip clearers
//! textmacro P_PLAYER_ABILITY_TOOLTIP_CLEAR takes PREFIX, B, OP_PREFIX, INFIX
		//
		method clear$PREFIX$Tip takes nothing returns thistype
			local integer lId = pId(this)
			local integer lAbiId = pgAbiId[lId]
			local integer lLevel = level
			//
			local User lUser = pUser(this)
			//
			local thistype lHash = pgHash(lId, lLevel, bj_MAX_PLAYER_SLOTS)
			static if ($B$) then
				local string lName = lHash.$OP_PREFIX$Name
				local string lDesc = lHash.$OP_PREFIX$Desc
			else
				local string lName = lHash.name
				local string lDesc = lHash.desc
			endif
			//
			if (lUser == bj_MAX_PLAYER_SLOTS) then
				set lUser = User.first
				loop
					set lHash = pgHash(lId, lLevel, lUser)
					//
					call pg$PREFIX$Tip.string.remove( lHash)
					call pg$PREFIX$Tip.string.remove(-lHash)
					//
					if (User.LocalId == lUser) then
						call BlzSetAbility$INFIX$Tooltip(lAbiId, lName, lLevel)
						call BlzSetAbility$INFIX$ExtendedTooltip(lAbiId, lDesc, lLevel)
					endif
					//
					exitwhen lUser == User.last
					set lUser = lUser.next
				endloop
				//
			else
				call pg$PREFIX$Tip.string.remove( this)
				call pg$PREFIX$Tip.string.remove(-this)
				//
				if (User.LocalId == lUser) then
					call BlzSetAbility$INFIX$Tooltip(lAbiId, lName, lLevel)
					call BlzSetAbility$INFIX$ExtendedTooltip(lAbiId, lDesc, lLevel)
				endif
			endif
			//
			return this
		endmethod
//! endtextmacro
	//
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_CLEAR("", "false", "", "")
	//
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_CLEAR("Learn", "true", "learn", "Research")
//! runtextmacro P_PLAYER_ABILITY_TOOLTIP_CLEAR("Acted", "true", "acted", "Activated")

	//--------------
	// all clearer
//! textmacro P_PLAYER_ABILITY_CLEAR takes C
		//
		call pgTip.string.remove( lHash)
		call pgTip.string.remove(-lHash)
		//
		call pgLearnTip.string.remove( lHash)
		call pgLearnTip.string.remove(-lHash)
		//
		call pgActedTip.string.remove( lHash)
		call pgActedTip.string.remove(-lHash)
		//
		set lHash = pgHash2(lId, lUser)
		call pgPos.remove( lHash)
		call pgPos.remove(-lHash)
		//
		call pgIcon.string.remove(lHash)
		//
	$C$ set lHash = lHash + lLevel*pgH0
		//
		if (User.LocalId == lUser) then
			call BlzSetAbilityPosX(lAbiId, lPosX)
			call BlzSetAbilityPosY(lAbiId, lPosY)
			//
			call BlzSetAbilityIcon(lAbiId, lIcon)
			//
			call BlzSetAbilityTooltip(lAbiId, lName, lLevel)
			call BlzSetAbilityExtendedTooltip(lAbiId, lDesc, lLevel)
			//
			call BlzSetAbilityResearchTooltip(lAbiId, lLearnName, lLevel)
			call BlzSetAbilityResearchExtendedTooltip(lAbiId, lLearnDesc, lLevel)
			//
			call BlzSetAbilityActivatedTooltip(lAbiId, lActedName, lLevel)
			call BlzSetAbilityActivatedExtendedTooltip(lAbiId, lActedDesc, lLevel)
		endif
		//
//! endtextmacro
	method clear takes nothing returns thistype
		local integer lId = pId(this)
		local integer lAbiId = pgAbiId[lId]
		local integer lLevel = level
		//
		local User lUser = pUser(this)
		//
		local string lName
		local string lDesc
		//
		local string lLearnName
		local string lLearnDesc
		//
		local string lActedName
		local string lActedDesc
		//
		local thistype lHash = pgHash2(lId, bj_MAX_PLAYER_SLOTS)
		local integer lPosX = lHash.posX
		local integer lPosY = lHash.posY
		//
		local string lIcon = lHash.icon
		//
		set lHash = lHash + lLevel*pgH0
		set lName = lHash.name
		set lDesc = lHash.desc
		//
		set lLearnName = lHash.learnName
		set lLearnDesc = lHash.learnDesc
		//
		set lActedName = lHash.actedName
		set lActedDesc = lHash.actedDesc
		//
		if (lUser == bj_MAX_PLAYER_SLOTS) then
			set lUser = User.first
			loop
				//
			//! runtextmacro P_PLAYER_ABILITY_CLEAR("")
				//
				exitwhen lUser == User.last
				set lUser = lUser.next
			endloop
		else
			//
		//! runtextmacro P_PLAYER_ABILITY_CLEAR("//")
			//
		endif
		//
		return this
	endmethod

	implement pm
endstruct
private module pm
	//--------------
	// initializer
	private static method onInit takes nothing returns nothing
		set pgH1 = bj_MAX_PLAYER_SLOTS + 1
		set pgH0 = pgH1*0x2000
		//
		set pgId    = Table.create()
		set pgAbiId = Table.create()
		//
		set pgPos  = Table.create()
		set pgIcon = Table.create()
		//
		set pgTip      = Table.create()
		set pgLearnTip = Table.create()
		set pgActedTip = Table.create()
	endmethod
endmodule

endlibrary
JASS:
//
function SetGlobalAbilityTip takes integer aId, integer aLevel, string aName, string aDesc returns PlayerAbility
	local PlayerAbility lAbility = PlayerAbility.get(aId, aLevel, null)
	//
	set lAbility.name = aName
	set lAbility.desc = aDesc
	//
	return lAbility
endfunction

//
function GetLocalAbilityIcon takes integer aId, integer aLevel, player aOwner returns string
	return PlayerAbility.get(aId, aLevel, aOwner).icon
    // this returns the same string for all players (in accordance to GetLocalPlayer)
    // because this doesn't use GetLocalPlayer to retrieve the data
endfunction

//
function GetResetGlobalAbility takes integer aId, integer aLevel returns PlayerAbility
	return PlayerAbility.get(aId, aLevel, null).clearPos().clearTip().clearIcon()
	// note that the global ability itself is unchanged
	// all of those only clear each player's instance of the ability
endfunction
Notes:
  • GetLocalPlayer + BlzSetAbilitySomething combination has been tested in multiplayer games.
  • The test also included testing GetLocalPlayer + BlzGetAbilitySomething combination, which worked without causing any crashes or unwanted results. Other interactions caused by potentially unsynchronized returned values were not tested. (It only interacted with GetLocalPlayer + BlzSetAbilitySomething, and the test itself was rather specific.)
  • This lib doesn't use the aforementioned local BlzGetAbilitySomething combination. Therefore values it returns are always the same to all players.
  • Test map used is attached below.
  • Credits to [color=gold]Pinzu[/color] for performing the test.
Changelog:
  • v1.2c:
    - Fixed missing inlining behavior.
    - Optimized the script a little.
  • v1.2b:
    - Optimized the assignments of id, level, and owner.
    - Replaced pgMod with manual mod operation.
  • v1.2a:
    - Fixed a bug in handling global abilities.
    - Rewritten and optimized the code.
    - Now id, level, and owner are assignable. But doing so also changes the instance.
    - Added the missing tooltip modifiers, prefixed with learn for research and acted for activated.
    - Added clear that clears all kinds of modifiers at once.
  • v1.1b: Fixed fatal hash-algorithm error.
  • v1.1a:
    - Optimized the code, now retrieves ability-index, level, and owner directly from struct-id instead.
    - Renamed private/local variables to longer names.
  • v1.0b: Renamed textmacros to help prevent name-clashing.
 

Attachments

  • LocalAbilityTest.w3x
    19.1 KB · Views: 50
Last edited:
Level 6
Joined
Jan 9, 2019
Messages
102
You should definitely do some multiplayer testing.
Unfortunately I can't. The only 1-pc 2-warcraft method that I know only available up to wc3 v1.26 or so. If you know any way to open 2 instances of wc3 v1.29 in the same pc, please let me know.

you don't need to store anything inside the table you just need GetLocalPlayer() wrappers or?
Do you mean something like this eh?
JASS:
function GetPlayerAbilityIcon takes integer aId, player aOwner returns string
	local string lS = BlzGetAbilityIcon(aId)  // this one is for every player
	if (GetLocalPlayer() == aOwner) then
		set lS = BlzGetAbilityIcon(aId)  // this one is for the specific player
	endif
	return lS  // this one is a mix however
endfunction
I'm quite sure this can lead to desyncs, unless my assumption is incorrect. By using Tables, getting the abilities' UI values won't involve BlzGetAbilitySomething, so it's safer at least.
 
Level 6
Joined
Jan 9, 2019
Messages
102
Im actually writing a little test suite as we speak... :D
Can I depend on you sir? Please? :D

But no matter the outcome, my lib will remain the same. I'm more interested in declaring this lib 99% multiplayer-safe, and just seeing GetLocalPlayer + BlzSetAbilitySomething combination works. My lib depends on Tables in handling global vs local values so I can't remove any, that's why.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202

[vJASS] - Command Utilities
[Snippet] Ascii
JASS:
library LocalAbility initializer Test uses CommandUtils, Ascii
    function GetLocalAbilityTooltip takes player p, integer abilCode, integer level returns string
        if GetLocalPlayer() == p then
            return BlzGetAbilityTooltip(abilCode, level)
        endif
        return null    // I think null here is fine.
    endfunction
    function SetLocalAbilityTooltip takes player p, integer abilCode, integer level, string text returns nothing
        if GetLocalPlayer() == p then
            call BlzSetAbilityTooltip(abilCode, text, level)
        endif
    endfunction
 
    /*
        ~ Test Environment
    */
 
    globals
        private unit array u
    endglobals
 
    private function AbilityExists takes integer abilCode returns boolean
        local string s = GetAbilityName(abilCode)
        return s != null
    endfunction
 
    private function Refresh takes player p returns nothing
        if GetLocalPlayer() == p then
            call ClearSelection()
            call SelectUnitForPlayerSingle(u[GetPlayerId(p)], p)
        endif
    endfunction
 
    private function Set takes nothing returns nothing
        local PChat chat = GetLastUpdatedChat()
        local integer abilCode = S2A(chat.word[1])
        local integer lvl
        local string s
        if not AbilityExists(abilCode) then
            call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Invalid argument: No such ability")
            return
        endif
        if chat.word[2] == "tooltip" then
            if chat.wordCount  < 4 then
                call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Invalid argument, expected: abilCode, type, level, text")
                return
            endif
            set lvl = S2I(chat.word[3])
            set s = SubString(chat.str, chat.wordEnd[3] + 1, chat.length)
            call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Setting " + GetAbilityName(abilCode) + " tooltip " + I2S(lvl) + " =  " + s)
            call SetLocalAbilityTooltip(chat.user, abilCode, lvl, s)
            call Refresh(chat.user)
        endif
    endfunction
 
    private function Get takes nothing returns nothing
        local PChat chat = GetLastUpdatedChat()
        local integer abilCode = S2A(chat.word[1])
        local string s
        local integer lvl
        if not AbilityExists(abilCode) then
            call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Invalid argument: No such ability")
            return
        endif
        if chat.word[2] == "tooltip" then
            if chat.wordCount  < 4 then
                call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Invalid argument, expected: abilCode, type, text, level")
                return
            endif
            set lvl = S2I(chat.word[3])
            set s = GetLocalAbilityTooltip(chat.user, abilCode, lvl)
            call DisplayTimedTextToPlayer(chat.user, 0,0,10, "Getting " + GetAbilityName(abilCode) + " tooltip " + I2S(lvl) + " =  " + s)
        endif
    endfunction
 
    private function AddAbility takes nothing returns nothing
        local PChat chat = GetLastUpdatedChat()
        local integer abilCode
        if chat.wordCount  <= 1 then
            return
        endif
        set abilCode = S2A(chat.word[1])
        call UnitAddAbility(u[chat.userId], abilCode)
        call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Added: " + GetAbilityName(abilCode))
    endfunction
 
    private function RemoveAbility takes nothing returns nothing
        local PChat chat = GetLastUpdatedChat()
        local integer abilCode
        if chat.wordCount  <= 1 then
            return
        endif
        set abilCode = S2A(chat.word[1])
        call UnitRemoveAbility(u[chat.userId], abilCode)
        call DisplayTimedTextToPlayer(chat.user ,0,0,10, "Removed: " + GetAbilityName(abilCode))
    endfunction
 
    private function Commands takes nothing returns nothing
        local PChat chat = GetLastUpdatedChat()
        local Command cmd = Command.head
        local string s = ""
        loop
            exitwhen cmd == 0
            if Command.isEnabledForPlayer(cmd.argument, chat.user) then
                set s = s + cmd.tooltip + "\n"
            endif
            set cmd = cmd.next
        endloop
        call DisplayTimedTextToPlayer(chat.user ,0,0,20, "Commands:\n" + s)
    endfunction
 
    private function Test takes nothing returns nothing
        local integer i = 0
        local player p
        loop
            exitwhen i == bj_MAX_PLAYER_SLOTS
            set p = Player(i)
            if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
            */ GetPlayerController(p) == MAP_CONTROL_USER then
                set u[i] = CreateUnit(p, 'hfoo', 0, 0, 0)
                call UnitAddAbility(u[i], 'Avul')
            endif
            set i = i + 1
        endloop
        call DisplayTimedTextToPlayer(GetLocalPlayer() ,0,0,20, "Type \"-commands\" to list all avaiable commands\n")
        call Command.register("-commands", function Commands)
        call Command.register("-add", function AddAbility)
        call Command.register("-remove", function RemoveAbility)
        call Command.register("-set", function Set)
        call Command.register("-get", function Get)
    endfunction
 
endlibrary

I think one would need to add a test to print the local message to all just to see what would happen. Right now the message displayed is within it's "local scope" as it's only shown to that particular player?

I would like to leave the map with you though, as I don't want to write these tests... :d
 
Last edited:
Top