Name | Type | is_array | initial_value |
CustomRace_AISetupTrig | trigger | No | |
CustomRace_BuildingID | unitcode | Yes | |
CustomRace_DefName | string | No | |
CustomRace_DefRace | race | No | |
CustomRace_Description | string | No | |
CustomRace_Display | string | No | |
CustomRace_FactionHall | unitcode | No | |
CustomRace_FactionWorker | unitcode | No | |
CustomRace_HallID | unitcode | Yes | |
CustomRace_HeroID | unitcode | Yes | |
CustomRace_Player | player | No | |
CustomRace_PlayerMine | unit | No | |
CustomRace_Playlist | string | No | |
CustomRace_PreloadPLDTrig | trigger | No | |
CustomRace_SetupTrig | trigger | No | |
CustomRace_StartLocation | location | No | |
CustomRace_StartPeonCenterLoc | location | No | |
CustomRace_StartPeonLoc | location | Yes | |
CustomRace_UnitID | unitcode | Yes |
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library FrameLoader initializer init_function
// in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
// This library runs all functions added to it with a 0s delay after the game was loaded.
// function FrameLoaderAdd takes code func returns nothing
// func runs when the game is loaded.
globals
private trigger eventTrigger = CreateTrigger()
private trigger actionTrigger = CreateTrigger()
private timer t = CreateTimer()
endglobals
function FrameLoaderAdd takes code func returns nothing
call TriggerAddAction(actionTrigger, func)
endfunction
private function timerAction takes nothing returns nothing
call TriggerExecute(actionTrigger)
endfunction
private function eventAction takes nothing returns nothing
call TimerStart(t, 0, false, function timerAction)
endfunction
private function init_function takes nothing returns nothing
call TriggerRegisterGameEvent(eventTrigger, EVENT_GAME_LOADED)
call TriggerAddAction(eventTrigger, function eventAction)
endfunction
endlibrary
library Init
module Init
static if thistype.onStartup.exists then
private static method startup takes nothing returns nothing
call thistype.onStartup()
endmethod
endif
private static method onInit takes nothing returns nothing
static if thistype.init.exists then
call thistype.init()
endif
static if thistype.onStartup.exists then
call TimerStart(CreateTimer(), 0.00, false, function thistype.startup)
endif
endmethod
endmodule
endlibrary
library GameStatus uses optional PlayerUtils
/***************************************************************
*
* v1.0.0 by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Simple API for detecting if the game is online, offline, or a replay.
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it (requires JassHelper *or* JNGP)
* _________________________________________________________________________
* 2. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* This library provides one function
*
* function GetGameStatus takes nothing returns integer
*
* It returns one of the following constants
*
* - GAME_STATUS_OFFLINE
* - GAME_STATUS_ONLINE
* - GAME_STATUS_REPLAY
*
***************************************************************/
// Configuration:
globals
// The dummy unit is only created once, and removed directly after.
private constant integer DUMMY_UNIT_ID = 'hfoo'
endglobals
// (end)
globals
constant integer GAME_STATUS_OFFLINE = 0
constant integer GAME_STATUS_ONLINE = 1
constant integer GAME_STATUS_REPLAY = 2
private integer status = 0
endglobals
function GetGameStatus takes nothing returns integer
return status
endfunction
private module GameStatusInit
private static method onInit takes nothing returns nothing
local player firstPlayer
local unit u
local boolean selected
// find an actual player
static if not (LIBRARY_PlayerUtils) then
set firstPlayer = Player(0)
loop
exitwhen (GetPlayerController(firstPlayer) == MAP_CONTROL_USER and GetPlayerSlotState(firstPlayer) == PLAYER_SLOT_STATE_PLAYING)
set firstPlayer = Player(GetPlayerId(firstPlayer)+1)
endloop
else
set firstPlayer = User.fromPlaying(0).toPlayer()
endif
// force the player to select a dummy unit
set u = CreateUnit(firstPlayer, DUMMY_UNIT_ID, 0, 0, 0)
call SelectUnit(u, true)
set selected = IsUnitSelected(u, firstPlayer)
call RemoveUnit(u)
set u = null
if (selected) then
// detect if replay or offline game
if (ReloadGameCachesFromDisk()) then
set status = GAME_STATUS_OFFLINE
else
set status = GAME_STATUS_REPLAY
endif
else
// if the unit wasn't selected instantly, the game is online
set status = GAME_STATUS_ONLINE
endif
endmethod
endmodule
private struct GameStatus
implement GameStatusInit
endstruct
endlibrary
library CustomRaceCore requires /*
----------------------
*/ Init, /*
----------------------
----------------------
*/ optional Table /*
----------------------
- Bribe
- link: https://www.hiveworkshop.com/threads/snippet-new-table.188084/
---------------------------------------------------------------------------------------
|
| CustomRaceCore
| v.1.3
|
|---------------------------------------------------------------------------------------
|
| The preliminary resource you'll ever want in modern techtree making (1.31+).
| Pros:
| - Custom UI for faction making.
| - Flexible faction creation.
| - Techtree display (with icon, name, and description).
| - Tournament-format compatibility.
| - (Observer) Real-time monitoring of player faction choice.
| - Up to 32767 factions in any game (realistically, 5 is really pushing it.)
|
| Cons:
| - Available in versions 1.31 and above.
| - Requires CustomRaceFrame.fdf
|
|---------------------------------------------------------------------------------------
|
| Since there are a lot of public methods in the CustomRace, it is
| to be assumed that every method found therein is considered to be
| a system only method, unless documented below:
| - static method create(race whichRace, name factionName) -> faction
| - Creates a new faction instance.
|
| method defAISetup(code setupfunc)
| - Defines an AI setup function (just in case you would like
| to do more than just assign AI scripts).
| method defSetup(code setupfunc)
| - Defines a setup function. (This is usually when the hall
| and the workers are created).
| method defRacePic(string path)
| - Defines the race picture display. (Note: Empty String ""
| will show no race picture, while buggy paths will
| display a green box.)
| method defDescription(string desc)
| - Defines what the faction is all about. You can expand
| the lore of your faction here.
| method defName(string name)
| - Didn't like the original name? You can redefine it here.
| method defPlaylist(string playlist)
| - Defines a playlist that will play once the game
| officially starts (after faction choices have
| been made, setup has been performed, and the countdown finishes.)
|
---------------------------------------------------------------------------------------
*/
struct CustomRace
static if not LIBRARY_Table then
private static hashtable ht = InitHashtable()
private static integer gHeroKey = 0
private static integer gHallKey = 0
else
private static Table gHeroMap = 0
private static Table gHallMap = 0
endif
readonly static integer array globalHeroID
readonly static integer array globalHallID
readonly static integer array raceFactionCount
readonly static thistype array humanFactionObject
readonly static thistype array orcFactionObject
readonly static thistype array undeadFactionObject
readonly static thistype array nightelfFactionObject
readonly string name
readonly string racePic
readonly string desc
readonly string playlist
readonly race baseRace
private trigger setupTrig
private trigger setupTrigAI
static if LIBRARY_Table then
private Table hallTable
private Table hallMap
private Table heroTable
private Table heroMap
private Table unitTable
private Table unitMap
private Table strcTable
private Table strcMap
else
private integer hallKey
private integer hallMapKey
private integer heroKey
private integer heroMapKey
private integer unitKey
private integer unitMapKey
private integer strcKey
private integer strcMapKey
endif
static if not LIBRARY_Table then
private static method generateKey takes nothing returns integer
call SaveInteger(ht, 0, 0, LoadInteger(ht, 0, 0) + 1)
return LoadInteger(ht, 0, 0)
endmethod
endif
// Only 4 races are actually available to the player.
private static method isValidRace takes race whichRace returns boolean
return GetHandleId(whichRace) < 5
endmethod
private static method updateFactionCount takes integer index, thistype this returns nothing
set raceFactionCount[index] = raceFactionCount[index] + 1
if index == 1 then
set humanFactionObject[raceFactionCount[index]] = this
elseif index == 2 then
set orcFactionObject[raceFactionCount[index]] = this
elseif index == 3 then
set undeadFactionObject[raceFactionCount[index]] = this
elseif index == 4 then
set nightelfFactionObject[raceFactionCount[index]] = this
endif
endmethod
static method getRaceFactionCount takes race whichRace returns integer
return raceFactionCount[GetHandleId(whichRace)]
endmethod
static method getRaceFaction takes race whichRace, integer index returns thistype
local integer id = GetHandleId(whichRace)
if (not thistype.isValidRace(whichRace)) then
return thistype(-1)
endif
if id == 1 then
return humanFactionObject[index]
elseif id == 2 then
return orcFactionObject[index]
elseif id == 3 then
return undeadFactionObject[index]
endif
return nightelfFactionObject[index]
endmethod
// destroy method is reserved to prevent bugs from occurring related
// to the creation of factions at runtime.
private method destroy takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60.00, /*
*/ "CustomRace.destroy >> Faction objects cannot be destroyed.")
endmethod
static method create takes race whichRace, string factionName returns thistype
local thistype this = 0
local integer index = GetHandleId(whichRace)
if not thistype.isValidRace(whichRace) then
return this
endif
set this = thistype.allocate()
set this.name = factionName
set this.baseRace = whichRace
// Setting this to empty string ensures that the faction display frame
// will not show by default.
set this.racePic = ""
// Basic info about the race done, now create a Table instance
static if LIBRARY_Table then
set this.hallTable = Table.create()
set this.hallMap = Table.create()
set this.heroTable = Table.create()
set this.heroMap = Table.create()
set this.unitTable = Table.create()
set this.unitMap = Table.create()
set this.strcTable = Table.create()
set this.strcMap = Table.create()
else
set this.hallKey = generateKey()
set this.hallMapKey = generateKey()
set this.heroKey = generateKey()
set this.heroMapKey = generateKey()
set this.unitKey = generateKey()
set this.unitMapKey = generateKey()
set this.strcKey = generateKey()
set this.strcMapKey = generateKey()
endif
// Update raceFactionCount and factionObject
call thistype.updateFactionCount(index, this)
return this
endmethod
//! textmacro CRCore_InstantiateStrings takes NAME
call GetObjectName($NAME$)
call BlzGetAbilityExtendedTooltip($NAME$, 0)
call BlzGetAbilityIcon($NAME$)
//! endtextmacro
method addUnit takes integer unitID returns nothing
//! runtextmacro CRCore_InstantiateStrings("unitID")
static if LIBRARY_Table then
if this.unitMap.has(unitID) then
return
endif
set this.unitTable.integer[0] = this.unitTable.integer[0] + 1
set this.unitTable[this.unitTable[0]] = unitID
set this.unitMap[unitID] = this.unitTable[0]
else
if HaveSavedInteger(ht, this.unitMapKey, unitID) then
return
endif
call SaveInteger(ht, this.unitKey, 0, LoadInteger(ht, this.unitKey, 0) + 1)
call SaveInteger(ht, this.unitKey, LoadInteger(ht, this.unitKey, 0), unitID)
call SaveInteger(ht, this.unitMapKey, unitID, LoadInteger(ht, this.unitKey, 0))
endif
endmethod
method addStructure takes integer strcID returns nothing
//! runtextmacro CRCore_InstantiateStrings("strcID")
static if LIBRARY_Table then
if this.strcMap.has(strcID) then
return
endif
set this.strcTable.integer[0] = this.strcTable.integer[0] + 1
set this.strcTable[this.strcTable[0]] = strcID
set this.strcMap[strcID] = this.strcTable[0]
else
if HaveSavedInteger(ht, this.strcMapKey, strcID) then
return
endif
call SaveInteger(ht, this.strcKey, 0, LoadInteger(ht, this.strcKey, 0) + 1)
call SaveInteger(ht, this.strcKey, LoadInteger(ht, this.strcKey, 0), strcID)
call SaveInteger(ht, this.strcMapKey, strcID, LoadInteger(ht, this.strcKey, 0))
endif
endmethod
// It is the responsibility of the user to provide the
// correct parameter for the heroIDs
method addHero takes integer heroID returns nothing
//! runtextmacro CRCore_InstantiateStrings("heroID")
static if LIBRARY_Table then
if this.heroMap.has(heroID) then
return
endif
set this.heroTable.integer[0] = this.heroTable.integer[0] + 1
set this.heroTable[this.heroTable[0]] = heroID
set this.heroMap[heroID] = this.heroTable[0]
if gHeroMap.has(heroID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = heroID
set gHeroMap[heroID] = globalHeroID[0]
else
if HaveSavedInteger(ht, this.heroMapKey, heroID) then
return
endif
call SaveInteger(ht, this.heroKey, 0, LoadInteger(ht, this.heroKey, 0) + 1)
call SaveInteger(ht, this.heroKey, LoadInteger(ht, this.heroKey, 0), heroID)
call SaveInteger(ht, this.heroMapKey, heroID, LoadInteger(ht, this.heroKey, 0))
if HaveSavedInteger(ht, gHeroKey, heroID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = heroID
call SaveInteger(ht, gHeroKey, heroID, globalHeroID[0])
endif
endmethod
method addHall takes integer hallID returns nothing
//! runtextmacro CRCore_InstantiateStrings("hallID")
static if LIBRARY_Table then
if this.hallMap.has(hallID) then
return
endif
set this.hallTable.integer[0] = this.hallTable.integer[0] + 1
set this.hallTable[this.hallTable[0]] = hallID
set this.hallMap[hallID] = this.hallTable[0]
if gHallMap.has(hallID) then
return
endif
set globalHallID[0] = globalHallID[0] + 1
set globalHallID[globalHallID[0]] = hallID
set gHallMap[hallID] = globalHallID[0]
else
if HaveSavedInteger(ht, this.hallMapKey, hallID) then
return
endif
call SaveInteger(ht, this.hallKey, 0, LoadInteger(ht, this.hallKey, 0) + 1)
call SaveInteger(ht, this.hallKey, LoadInteger(ht, this.hallKey, 0), hallID)
call SaveInteger(ht, this.hallMapKey, hallID, LoadInteger(ht, this.hallKey, 0))
if HaveSavedInteger(ht, gHallKey, hallID) then
return
endif
set globalHallID[0] = globalHallID[0] + 1
set globalHallID[globalHallID[0]] = hallID
call SaveInteger(ht, gHallKey, hallID, globalHallID[0])
endif
endmethod
//! textmacro CRCore_DEF_GETTER takes NAME, SUBNAME
method get$NAME$ takes integer index returns integer
static if LIBRARY_Table then
return this.$SUBNAME$Table[index]
else
return LoadInteger(ht, this.$SUBNAME$Key, index)
endif
endmethod
method get$NAME$MaxIndex takes nothing returns integer
static if LIBRARY_Table then
return this.$SUBNAME$Table.integer[0]
else
return LoadInteger(ht, this.$SUBNAME$Key, 0)
endif
endmethod
//! endtextmacro
//! runtextmacro CRCore_DEF_GETTER("Hero", "hero")
//! runtextmacro CRCore_DEF_GETTER("Hall", "hall")
//! runtextmacro CRCore_DEF_GETTER("Unit", "unit")
//! runtextmacro CRCore_DEF_GETTER("Structure", "strc")
method getRandomHero takes nothing returns integer
return this.getHero(GetRandomInt(1, this.getHeroMaxIndex()))
endmethod
static method getGlobalHeroMaxIndex takes nothing returns integer
return globalHeroID[0]
endmethod
static method getGlobalHallMaxIndex takes nothing returns integer
return globalHallID[0]
endmethod
static method getGlobalHero takes integer index returns integer
return globalHeroID[index]
endmethod
static method getGlobalHall takes integer index returns integer
return globalHallID[index]
endmethod
static method isGlobalHero takes integer heroID returns boolean
static if LIBRARY_Table then
return gHeroMap.has(heroID)
else
return HaveSavedInteger(ht, gHeroKey, heroID)
endif
endmethod
static method addGlobalHero takes integer heroID returns nothing
//! runtextmacro CRCore_InstantiateStrings("heroID")
static if LIBRARY_Table then
if gHeroMap.has(heroID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = heroID
set gHeroMap[heroID] = globalHeroID[0]
else
if HaveSavedInteger(ht, gHeroKey, heroID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = heroID
call SaveInteger(ht, gHeroKey, heroID, globalHeroID[0])
endif
endmethod
static method addGlobalHall takes integer hallID returns nothing
//! runtextmacro CRCore_InstantiateStrings("hallID")
static if LIBRARY_Table then
if gHeroMap.has(hallID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = hallID
set gHeroMap[hallID] = globalHeroID[0]
else
if HaveSavedInteger(ht, gHeroKey, hallID) then
return
endif
set globalHeroID[0] = globalHeroID[0] + 1
set globalHeroID[globalHeroID[0]] = hallID
call SaveInteger(ht, gHeroKey, hallID, globalHeroID[0])
endif
endmethod
static method isKeyStructure takes integer hallID returns boolean
static if LIBRARY_Table then
return gHallMap.has(hallID)
else
return HaveSavedInteger(ht, gHallKey, hallID)
endif
endmethod
method defSetup takes code setupfunc returns nothing
if this.setupTrig != null then
call DestroyTrigger(this.setupTrig)
endif
set this.setupTrig = CreateTrigger()
call TriggerAddCondition(this.setupTrig, Condition(setupfunc))
endmethod
method defAISetup takes code setupfunc returns nothing
if this.setupTrigAI != null then
call DestroyTrigger(this.setupTrigAI)
endif
set this.setupTrigAI = CreateTrigger()
call TriggerAddCondition(this.setupTrigAI, Condition(setupfunc))
endmethod
method defRacePic takes string racePic returns nothing
set this.racePic = racePic
endmethod
method defDescription takes string desc returns nothing
set this.desc = desc
endmethod
method defName takes string name returns nothing
set this.name = name
endmethod
method defPlaylist takes string plist returns nothing
set this.playlist = plist
endmethod
method execSetup takes nothing returns nothing
call TriggerEvaluate(this.setupTrig)
endmethod
method execSetupAI takes nothing returns nothing
call TriggerEvaluate(this.setupTrigAI)
endmethod
private static method init takes nothing returns nothing
set raceFactionCount[GetHandleId(RACE_HUMAN)] = 0
set raceFactionCount[GetHandleId(RACE_ORC)] = 0
set raceFactionCount[GetHandleId(RACE_UNDEAD)] = 0
set raceFactionCount[GetHandleId(RACE_NIGHTELF)] = 0
static if LIBRARY_Table then
set gHeroMap = Table.create()
set gHallMap = Table.create()
else
set gHeroKey = generateKey()
set gHallKey = generateKey()
endif
endmethod
implement Init
endstruct
endlibrary
library CustomRaceUI requires /*
----------------------
*/ CustomRaceCore, /*
----------------------
----------------------
*/ Init, /*
----------------------
------------------------------
*/ optional FrameLoader /*
------------------------------
---------------------------------------------------------------------------
|
| CustomRaceUI
|
|---------------------------------------------------------------------------
|
| - function MainFrameInitiallyVisible() -> boolean
| - determines whether the main frame is visible at the start
| of the game. Must not be touched!
|
|---------------------------------------------------------------------------
|
| Configuration Section:
|
|---------------------------------------------------------------------------
|
| GetMainFrameCenterX() -> real
| GetMainFrameCenterY() -> real
| - Determines the position of the center of the main frame.
|
| GetTechtreeTooltipOffsetX() -> real
| GetTechtreeTooltipOffsetY() -> real
| - Determines the position of the leftmost lower edge of the
| tooltip frame.
|
| GetTechtreeChunkCount() -> integer
| - Determines the number of techtree chunks to generate.
| - An example of a techtree chunk may consist of units
| existing as part of the techtree of a certain faction.
|
| GetTechtreeIconRowMax() -> integer
| - Returns the maximum amount of icons per column
| within a given chunk.
| - o
| o --> 2
| GetTechtreeIconColumnMax() -> integer
| - Returns the maximum amount of icons per row
| within a given chunk.
|
| - o o o o --> 4
|
| InitChunkNames()
| - While not considered a traditionally configurable
| function, this function provides one with the
| means to edit the labels of each techtree chunk,
| albeit indirectly.
|
| GetMaxDisplayChoices() -> integer
| - The amount of choices for factions that are displayed at any given time.
| - NOTE: The actual maximum number of factions is practically unlimited
| and should not be confused with the value here.
| GetChoiceSizeOffset() -> real
| - The difference between the total height of the choices and the height
| of their container frame.
|
| GetBarModel() -> string
| - The model art for the "bar" frame (which is actually a backdrop frame)
| (behind the scenes.)
| GetBarTransparency() -> real
| - The transparency of the "bar" frame. Accepts values from 0.0 to 1.0.
| - A transparency of 1 will render the frame invisible. A transparency
| of 0 will render the frame completely opaque.
|
|---------------------------------------------------------------------------
|
| CustomRaceInterface method guide:
|
|---------------------------------------------------------------------------
|
| Although not really meant for public usage, the public methods
| "available" to the user are written to make certain interactions
| with some of the elements in the main frame as direct and easy
| as possible. In that regard, expect performance to be sacrificed
| a bit.
|
| If opting for speed, one can directly access most of the elements
| and make changes from there. Performance may improve, but the
| maintainability of the code might be negatively affected.
|
| All of the following methods are static:
|
|---------------------------------------------------------------------------
|
| Getters:
| method getTechtreeIcon(int techChunk, int row, int col) -> framehandle
| - returns the techtree icon at the specified location
| and chunk.
|
| method getTechtreeIconRaw(int index) -> framehandle
| - returns the techtree icon at the specified index.
| Be wary, as this is not protected from out of bounds
| results.
|
| method getChoiceButton(int index) -> framehandle
| - returns one of the choice buttons (found within the
| choice container frame at the lower left portion.)
|
| method getTechtreeArrow(int techChunk, bool isUp) -> framehandle
| - returns one of the two techtree arrows associated
| with the requested chunk.
|
| method getTechtreeArrowID(framehandle arrow) -> int
| - returns the index of the arrow handle.
|
| method getChoiceArrow(bool isUp) -> framehandle
| - returns one of the two choice arrows bound to the
| slider frame.
|
| method getChoiceArrowID(framehandle arrow) -> int
| - returns the index of the arrow handle.
|
| method getSliderValue() -> int
| - self-explanatory
|
| method getChunkFromIndex(int id) -> int
| - Retrieves the chunk containing the techtree
| icon id.
|
| Setters:
| method setTooltipName(string name)
| - sets the text entry for the name portion of the
| tooltip frame to the specified parameter. Empty
| string defaults into "Unit Name Missing!"
|
| method setTooltipDesc(string name)
| - similar to setTooltipName, this sets the entry
| of the description portion of the tooltip frame
| to the specified parameter. Defaults into "Tooltip
| Missing!"
|
| method setDescription(string desc)
| - Assigns the contents to the textarea frame. Used
| for giving a faction some background info or
| description, etc.
|
| method setChoiceName(int index, string name)
| - Sets the name of the selected choice button to
| the specified name. Defaults to "Factionless"
|
| method setTechtreeIconDisplay(int techChunk, int row, int col, string display)
| - Sets the background of the specified techtree
| icon to the model pointed by the display path.
|
| method setTechtreeIconDisplayEx(framehandle icon, string display)
| - A more direct version of the above function.
| Useful when the user is already using the
| appropriate icon directly.
|
| method setTechtreeIconDisplayByID(int contextID, string display)
| - An index-based version of the above function.
|
| method setBarProgress(real value)
| - Sets the width of the visual bar to a specified
| ratio relative to its parent frame that is equal
| to the specified value.
|
| method setMainAlpha(real ratio)
| - Modifies the alpha coloring of the main frame.
|
| method setFactionDisplay(string iconPath)
| - Updates the screen texture at the top left section
| of the main frame. Automatically handles visibility.
| - Setting the display to an empty string hides it
| while setting the display to any other value shows
| it.
|
| method setFactionName(string name)
| - Sets the contents of the text frame above the screen
| texture to the specified name. Defaults to "Faction
| Name".
| - It is to be used in conjunction with the selection
| of the current frame.
|
| method setMainPos(x, y)
| - Moves the center of the main frame to that specified
| position.
|
| method setSliderValue(real value)
| - Changes the position value of the slider button.
|
| method setSliderMaxValue(int max)
| - Sets the slider's maximum value to the specified
| amount. Cannot go lower than 1.
| - Has the added effect of automatically updating
| the slider value.
|
| Visibility:
| method isMainVisible() -> bool
| method isTooltipVisible() -> bool
| method isSliderVisible() -> bool
| method isChoiceButtonVisible(int index) -> bool
| method isTechtreeChunkVisible(int techChunk) -> bool
| method isChoiceArrowVisible(int isUp) -> bool
| method isTechtreeArrowVisible(int techChunk, bool isUp) -> bool
| method isFactionNameVisible() -> bool
| method isTechtreeIconVisible(int contextId) -> bool
| - Returns the visibility state of the following frames in order:
| - Main frame
| - Tooltip
| - Slider adjacent to container frame
| - Choice button
| - Techtree chunk contained inside techtree container frame
| - Arrow buttons adjacent to the techtree chunk frames.
| - Techtree arrows adjacent to the slider.
| - Faction Name
| - Techtree icon
|
| method setMainVisible(bool flag)
| method setTooltipVisible(bool flag)
| method setSliderVisible(bool flag)
| method setChoiceButtonVisible(int index, bool flag)
| method setTechtreeChunkVisible(int techChunk, bool flag)
| method setChoiceArrowVisible(int isUp, bool flag)
| method setTechtreeArrowVisible(int techChunk, bool isUp, bool flag)
| method setFactionNameVisible(bool flag)
| method setTechtreeIconVisible(int contextId, bool flag)
| - Modifies the visibility state of the following frames in order:
| - Main frame
| - Tooltip
| - Slider adjacent to container frame
| - Choice button
| - Techtree chunk contained inside techtree container frame
| - Arrow buttons adjacent to the techtree chunk frames.
| - Techtree arrows adjacent to the slider.
| - Faction Name
| - Techtree icon
|
|---------------------------------------------------------------------------
|
| Aside from the methods publicly available, the following members are
| readonly for the user's convenience (should they choose to update it):
|
| struct CustomRaceInterface
| framehandle main
| framehandle iconFrame
| framehandle descArea
| framehandle factFrame
| framehandle confirmFrame
| framehandle choiceFrame
| framehandle techFrame
| framehandle slider
| framehandle bar
| framehandle barParent
| framehandle techTooltip
| framehandle techTooltipName
| framehandle techTooltipDesc
| framehandle array techtreeIcons
| framehandle array techtreeChunk
| framehandle array techtreeArrow
| framehandle array choiceArrow
| framehandle array choiceButton
|
---------------------------------------------------------------------------
*/
globals
private constant boolean IN_DEBUG_MODE = true
endglobals
private constant function DebugFrameModel takes nothing returns string
return "ReplaceableTextures\\CommandButtons\\BTNGhoul.tga"
endfunction
private constant function GetTOCPath takes nothing returns string
return "war3mapImported\\CustomRaceTOC.toc"
endfunction
private constant function GetUpArrowButtonModel takes nothing returns string
return "UI\\Widgets\\Glues\\SinglePlayerSkirmish-ScrollBarUpButton.blp"
endfunction
private constant function GetDownArrowButtonModel takes nothing returns string
return "UI\\Widgets\\Glues\\SinglePlayerSkirmish-ScrollBarDownButton.blp"
endfunction
private constant function MainFrameInitiallyVisible takes nothing returns boolean
return false
endfunction
private constant function GetTechtreeChunkTextFrameWidth takes nothing returns real
return 0.024
endfunction
private constant function GetTechtreeChunkTextFrameHeight takes nothing returns real
return 0.018
endfunction
private constant function GetTechtreeChunkHolderWidthOffset takes nothing returns real
return 0.004
endfunction
private constant function GetTechtreeChunkHolderHeightOffset takes nothing returns real
return 0.004
endfunction
private constant function GetTechtreeArrowMaxWidth takes nothing returns real
return 0.032
endfunction
// ==================================================== //
// CONFIGURATION SECTION //
// ==================================================== //
globals
public string array techName
constant integer TECHTREE_CHUNK_UNIT = 1
constant integer TECHTREE_CHUNK_BUILDING = 2
constant integer TECHTREE_CHUNK_HEROES = 3
constant integer TECHTREE_CHUNK_UPGRADES = 4
endglobals
public constant function GetMainFrameCenterX takes nothing returns real
return 0.342
endfunction
public constant function GetMainFrameCenterY takes nothing returns real
return 0.338
endfunction
private constant function GetTechtreeTooltipOffsetX takes nothing returns real
return 0.016
endfunction
private constant function GetTechtreeTooltipOffsetY takes nothing returns real
return -0.06
endfunction
public constant function GetMaxDisplayChoices takes nothing returns integer
return 3
endfunction
private constant function GetChoiceSizeOffset takes nothing returns real
return 0.003
endfunction
public constant function GetTechtreeChunkCount takes nothing returns integer
return 2
endfunction
public constant function GetTechtreeIconColumnMax takes nothing returns integer
return 4
endfunction
public constant function GetTechtreeIconRowMax takes nothing returns integer
return 2
endfunction
private constant function GetBarModel takes nothing returns string
return "ReplaceableTextures\\Teamcolor\\Teamcolor01.tga"
endfunction
private constant function GetBarTransparency takes nothing returns real
return 0.55
endfunction
private function InitChunkNames takes nothing returns nothing
set techName[TECHTREE_CHUNK_UNIT] = "Units:"
set techName[TECHTREE_CHUNK_BUILDING] = "Buildings:"
set techName[TECHTREE_CHUNK_HEROES] = "Heroes:"
set techName[TECHTREE_CHUNK_UPGRADES] = "Upgrades:"
endfunction
// ==================================================== //
// END CONFIGURATION SECTION //
// ==================================================== //
// Too lazy to use a hashtable here, so this hashing function will do.
// Since there are only about 3-4 (8+ is pushing it) buttons in total,
// the chance of a collision in index entry might as well be 0. (there
// is a chance, but it is statistically improbable.)
private function GetFrameIndex takes framehandle whichButton returns integer
return ModuloInteger(GetHandleId(whichButton) - 0x100000, 0x8000)
endfunction
static if IN_DEBUG_MODE then
private struct Debugger extends array
private static integer warningRaised = 0
private static string array warning
static method prepWarning takes string source, string msg returns nothing
set warningRaised = warningRaised + 1
set warning[warningRaised] = "\n (" + I2S(warningRaised) + /*
*/ ") In " + source + ": (" + msg + ")."
endmethod
static method raiseWarning takes string source returns nothing
local string msg = source + ": Warning Raised!"
local integer i = 1
if warningRaised < 1 then
return
endif
loop
exitwhen i > warningRaised
set msg = msg + warning[i]
set i = i + 1
endloop
set warningRaised = 0
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 60.0, msg)
endmethod
static method warningReady takes nothing returns boolean
return warningRaised > 0
endmethod
endstruct
endif
struct CustomRaceInterface extends array
readonly static framehandle main = null
readonly static framehandle iconFrame = null
readonly static framehandle descArea = null
readonly static framehandle factFrame = null
readonly static framehandle confirmFrame = null
readonly static framehandle choiceFrame = null
readonly static framehandle techFrame = null
readonly static framehandle slider = null
readonly static framehandle bar = null
readonly static framehandle barParent = null
readonly static framehandle techTooltip = null
readonly static framehandle techTooltipName = null
readonly static framehandle techTooltipDesc = null
readonly static framehandle array techtreeIcons
readonly static framehandle array techtreeChunk
readonly static framehandle array techtreeArrow
readonly static framehandle array choiceArrow
readonly static framehandle array choiceButton
readonly static integer array choiceButtonId
readonly static integer array techtreeIconContextId
readonly static integer iconsPerChunk = 0
readonly static integer sliderMinValue = 0
readonly static integer sliderMaxValue = 1
readonly static string iconTexture = ""
private static method getBoundedRealValue takes real a, real max, real min returns real
local real temp = 0.0
if max < min then
set temp = max
set max = min
set min = temp
endif
if a > max then
static if IN_DEBUG_MODE then
call Debugger.prepWarning("getBoundedRealValue", R2S(a) + " is greater than the maximum value " + R2S(max))
endif
set a = max
endif
if a < min then
static if IN_DEBUG_MODE then
call Debugger.prepWarning("getBoundedRealValue", R2S(a) + " is less than the minimum value " + R2S(min))
endif
set a = min
endif
return a
endmethod
private static method getBoundedIntValue takes integer a, integer max, integer min returns integer
local integer temp = 0
if max < min then
set temp = max
set max = min
set min = temp
endif
if a > max then
static if IN_DEBUG_MODE then
call Debugger.prepWarning("getBoundedIntValue", I2S(a) + " is greater than the maximum value " + I2S(max))
endif
set a = max
endif
if a < min then
static if IN_DEBUG_MODE then
call Debugger.prepWarning("getBoundedIntValue", I2S(a) + " is less than the minimum value " + I2S(min))
endif
set a = min
endif
return a
endmethod
private static method chunkInfo2Index takes integer techChunk, integer row, integer col returns integer
set techChunk = getBoundedIntValue(techChunk, 1, GetTechtreeChunkCount())
static if IN_DEBUG_MODE then
call Debugger.raiseWarning("chunkInfo2Index (techChunk)")
endif
set row = getBoundedIntValue(row, 1, GetTechtreeIconRowMax())
static if IN_DEBUG_MODE then
call Debugger.raiseWarning("chunkInfo2Index (row)")
endif
set col = getBoundedIntValue(col, 1, GetTechtreeIconColumnMax())
static if IN_DEBUG_MODE then
call Debugger.raiseWarning("chunkInfo2Index (col)")
endif
return (techChunk-1)*GetTechtreeIconRowMax()*GetTechtreeIconColumnMax() + /*
*/ (row-1)*GetTechtreeIconColumnMax() + col
endmethod
// ============================================================= //
// External Struct API //
// ============================================================= //
// ================== //
// Getter API //
// ================== //
static method getTechtreeIcon takes integer techChunk, integer row, integer col returns framehandle
return techtreeIcons[chunkInfo2Index(techChunk, row, col)]
endmethod
static method getTechtreeIconRaw takes integer index returns framehandle
return techtreeIcons[index]
endmethod
static method getChoiceButton takes integer index returns framehandle
return choiceButton[index]
endmethod
static method getTechtreeArrow takes integer techChunk, boolean isUp returns framehandle
set techChunk = getBoundedIntValue(techChunk, 1, GetMaxDisplayChoices())
if isUp then
return techtreeArrow[2*(techChunk-1) + 1]
endif
return techtreeArrow[2*(techChunk)]
endmethod
static method getTechtreeArrowID takes framehandle arrow returns integer
local integer i = 1
local integer j = GetTechtreeChunkCount()*2
loop
exitwhen i > j
if techtreeArrow[i] == arrow then
return i
endif
set i = i + 1
endloop
return 0
endmethod
static method getChoiceArrow takes boolean isUp returns framehandle
if isUp then
return choiceArrow[1]
endif
return choiceArrow[2]
endmethod
static method getChoiceArrowID takes framehandle arrow returns integer
if arrow == choiceArrow[1] then
return 1
elseif arrow == choiceArrow[2] then
return 2
endif
return 0
endmethod
static method getChoiceButtonID takes framehandle choice returns integer
return choiceButtonId[GetFrameIndex(choice)]
endmethod
static method getTechtreeIconID takes framehandle icon returns integer
return techtreeIconContextId[GetFrameIndex(icon)]
endmethod
static method getSliderValue takes nothing returns integer
return R2I(BlzFrameGetValue(slider) + 0.01)
endmethod
static method getChunkFromIndex takes integer id returns integer
return ((id - 1) / iconsPerChunk) + 1
endmethod
// ================== //
// Setter API //
// ================== //
static method setTooltipName takes string name returns nothing
if name == "" then
set name = "Unit Name Missing!"
endif
call BlzFrameSetText(techTooltipName, name)
endmethod
static method setTooltipDesc takes string desc returns nothing
if desc == "" then
set desc = "Tooltip Missing!"
endif
call BlzFrameSetText(techTooltipDesc, desc)
endmethod
static method setDescription takes string content returns nothing
call BlzFrameSetText(descArea, content)
endmethod
static method setChoiceName takes integer index, string name returns nothing
set index = getBoundedIntValue(index, 1, GetMaxDisplayChoices())
if name == "" then
set name = "Factionless"
endif
call BlzFrameSetText(choiceButton[index], name)
endmethod
static method setTechtreeIconDisplay takes integer techChunk, integer row, integer col, string display returns nothing
local integer index = chunkInfo2Index(techChunk, row, col)
local framehandle icon = BlzGetFrameByName("CustomRaceFactionTechtreeIconActiveBackdrop", index)
local framehandle pIcon = BlzGetFrameByName("CustomRaceFactionTechtreeIconBackdrop", index)
call BlzFrameSetTexture(icon, display, 0, true)
call BlzFrameSetTexture(pIcon, display, 0, true)
set pIcon = null
set icon = null
endmethod
static method setTechtreeIconDisplayEx takes framehandle techIcon, string display returns nothing
local integer index = techtreeIconContextId[GetFrameIndex(techIcon)]
local framehandle icon
local framehandle pIcon
if index == 0 then
return
endif
set icon = BlzGetFrameByName("CustomRaceFactionTechtreeIconActiveBackdrop", index)
set pIcon = BlzGetFrameByName("CustomRaceFactionTechtreeIconBackdrop", index)
call BlzFrameSetTexture(icon, display, 0, true)
call BlzFrameSetTexture(pIcon, display, 0, true)
set pIcon = null
set icon = null
endmethod
static method setTechtreeIconDisplayByID takes integer contextID, string display returns nothing
local framehandle icon = BlzGetFrameByName("CustomRaceFactionTechtreeIconActiveBackdrop", contextID)
local framehandle pIcon = BlzGetFrameByName("CustomRaceFactionTechtreeIconBackdrop", contextID)
call BlzFrameSetTexture(icon, display, 0, true)
call BlzFrameSetTexture(pIcon, display, 0, true)
set pIcon = null
set icon = null
endmethod
// Values range from 0.0 - 1.0 with 1.0 filling up the entire bar
// and 0.0 being completely empty.
static method setBarProgress takes real amount returns nothing
set amount = getBoundedRealValue(amount, 1.0, 0.0)
call BlzFrameSetSize(bar, BlzFrameGetWidth(barParent)*(amount), BlzFrameGetHeight(barParent))
endmethod
// Values range from 0.0 - 1.0 with 1.0 being completely visible
// and 0.0 being completely invisible
static method setMainAlpha takes real ratio returns nothing
set ratio = getBoundedRealValue(ratio, 1.0, 0.0)
call BlzFrameSetAlpha(main, R2I(255.0*ratio))
if iconTexture == "" and BlzFrameIsVisible(iconFrame) then
call BlzFrameSetVisible(iconFrame, false)
endif
call BlzFrameSetAlpha(bar, R2I(255.0*ratio*(1.0 - GetBarTransparency())))
endmethod
// Displays the representative faction image to the top-left
// of the main frame. Adding an empty string automatically
// hides the frame.
static method setFactionDisplay takes string imagePath returns nothing
set iconTexture = imagePath
if imagePath == "" and BlzFrameIsVisible(iconFrame) then
call BlzFrameSetVisible(iconFrame, false)
elseif (imagePath != "") and (not BlzFrameIsVisible(iconFrame)) then
call BlzFrameSetVisible(iconFrame, true)
endif
call BlzFrameSetTexture(iconFrame, imagePath, 0, true)
endmethod
static method setFactionName takes string name returns nothing
if name == "" then
set name = "Faction Name"
endif
call BlzFrameSetText(factFrame, name)
endmethod
static method setMainPos takes real x, real y returns nothing
call BlzFrameSetAbsPoint(main, FRAMEPOINT_CENTER, x, y)
endmethod
static method setSliderValue takes integer value returns nothing
call BlzFrameSetValue(slider, value)
endmethod
static method setSliderMaxValue takes integer value returns nothing
local real preValue = BlzFrameGetValue(slider)
local real preMax = sliderMaxValue
set value = IMaxBJ(value, 1)
set sliderMaxValue = value
call BlzFrameSetMinMaxValue(slider, 0.0, value)
call BlzFrameSetValue(slider, preValue + value - preMax)
endmethod
// ============================== //
// Boolean State Check API //
// ============================== //
static method isMainVisible takes nothing returns boolean
return BlzFrameIsVisible(main)
endmethod
static method isTooltipVisible takes nothing returns boolean
return BlzFrameIsVisible(techTooltip)
endmethod
static method isSliderVisible takes nothing returns boolean
return BlzFrameIsVisible(slider)
endmethod
static method isChoiceButtonVisible takes integer index returns boolean
set index = getBoundedIntValue(index, 1, GetMaxDisplayChoices())
return BlzFrameIsVisible(choiceButton[index])
endmethod
static method isTechtreeChunkVisible takes integer techChunk returns boolean
set techChunk = getBoundedIntValue(techChunk, 1, GetTechtreeChunkCount())
return BlzFrameIsVisible(techtreeChunk[techChunk])
endmethod
static method isChoiceArrowVisible takes boolean isUp returns boolean
if isUp then
return BlzFrameIsVisible(choiceArrow[1])
endif
return BlzFrameIsVisible(choiceArrow[2])
endmethod
static method isTechtreeArrowVisible takes integer techChunk, boolean isUp returns boolean
local integer index = 0
set techChunk = getBoundedIntValue(techChunk, 1, GetTechtreeChunkCount())
set index = (techChunk)*2
if isUp then
set index = index - 1
endif
return BlzFrameIsVisible(techtreeArrow[index])
endmethod
static method isFactionNameVisible takes nothing returns boolean
return BlzFrameIsVisible(factFrame)
endmethod
static method isTechtreeIconVisible takes integer contextID returns boolean
return BlzFrameIsVisible(techtreeIcons[contextID])
endmethod
// ============================== //
// Regular API //
// ============================== //
static method setMainVisible takes boolean flag returns nothing
call BlzFrameSetVisible(main, flag)
endmethod
static method setTooltipVisible takes boolean flag returns nothing
call BlzFrameSetVisible(techTooltip, flag)
endmethod
static method setSliderVisible takes boolean flag returns nothing
call BlzFrameSetVisible(slider, flag)
endmethod
static method setChoiceButtonVisible takes integer index, boolean flag returns nothing
set index = getBoundedIntValue(index, 1, GetMaxDisplayChoices())
call BlzFrameSetVisible(choiceButton[index], flag)
endmethod
static method setTechtreeChunkVisible takes integer techChunk, boolean flag returns nothing
set techChunk = getBoundedIntValue(techChunk, 1, GetTechtreeChunkCount())
call BlzFrameSetVisible(techtreeChunk[techChunk], flag)
endmethod
static method setChoiceArrowVisible takes boolean isUp, boolean flag returns nothing
if isUp then
call BlzFrameSetVisible(choiceArrow[1], flag)
endif
call BlzFrameSetVisible(choiceArrow[2], flag)
endmethod
static method setTechtreeArrowVisible takes integer techChunk, boolean isUp, boolean flag returns nothing
local integer index = 0
set techChunk = getBoundedIntValue(techChunk, 1, GetTechtreeChunkCount())
set index = (techChunk)*2
if isUp then
set index = index - 1
endif
call BlzFrameSetVisible(techtreeArrow[index], flag)
endmethod
static method setFactionNameVisible takes boolean flag returns nothing
call BlzFrameSetVisible(factFrame, flag)
endmethod
static method setTechtreeIconVisible takes integer contextID, boolean flag returns nothing
call BlzFrameSetVisible(techtreeIcons[contextID], flag)
endmethod
// ============================================================= //
// End External Struct API //
// ============================================================= //
private static method initMainFrame takes framehandle world returns nothing
// Assign variables
set main = BlzCreateFrame("CustomRaceMainFrame", world, 0, 0)
set iconFrame = BlzGetFrameByName("CustomRaceFactionDisplayIcon", 0)
set descArea = BlzGetFrameByName("CustomRaceFactionDescArea", 0)
set factFrame = BlzGetFrameByName("CustomRaceFactionName", 0)
set confirmFrame = BlzGetFrameByName("CustomRaceFactionConfirmButton", 0)
set choiceFrame = BlzGetFrameByName("CustomRaceFactionChoiceMain", 0)
set techFrame = BlzGetFrameByName("CustomRaceFactionTechtreeBackdrop", 0)
set slider = BlzGetFrameByName("CustomRaceFactionChoiceScrollbar", 0)
set bar = BlzGetFrameByName("CustomRaceFactionUpdateBar", 0)
set barParent = BlzFrameGetParent(bar)
set choiceArrow[1] = BlzGetFrameByName("CustomRaceFactionChoiceScrollbarIncButton", 0)
set choiceArrow[2] = BlzGetFrameByName("CustomRaceFactionChoiceScrollbarDecButton", 0)
set iconsPerChunk = GetTechtreeIconRowMax()*GetTechtreeIconColumnMax()
// Prepare actual frame for use.
call BlzFrameSetAbsPoint(main, FRAMEPOINT_CENTER, GetMainFrameCenterX(), GetMainFrameCenterY())
call BlzFrameSetTexture(bar, GetBarModel(), 0, true)
call BlzFrameSetAlpha(bar, R2I(255.0*(1.0 - GetBarTransparency())))
if not MainFrameInitiallyVisible() then
call BlzFrameSetVisible(main, false)
endif
endmethod
private static method initChildFrames takes nothing returns nothing
local integer i = 1
local integer j = 0
local integer k = 0
local integer row = GetTechtreeIconRowMax()
local integer col = GetTechtreeIconColumnMax()
local integer id = 0
local real width = BlzFrameGetWidth(choiceFrame)
local real size = (BlzFrameGetHeight(choiceFrame) - GetChoiceSizeOffset()) / R2I(GetMaxDisplayChoices())
local real dwidth = 0.0
local framehandle tempFrame
local framehandle oldTempFrame
// Create the choice buttons.
loop
exitwhen i > GetMaxDisplayChoices()
set choiceButton[i] = BlzCreateFrame("CustomRaceFactionChoiceButton", choiceFrame, /*
*/ 0, i)
set id = GetFrameIndex(choiceButton[i])
set choiceButtonId[id] = i
call BlzFrameSetPoint(choiceButton[i], FRAMEPOINT_TOP, choiceFrame, FRAMEPOINT_TOP, 0, /*
*/ -(GetChoiceSizeOffset() + (i-1)*size))
call BlzFrameSetSize(choiceButton[i], width, size)
set i = i + 1
endloop
// Create the tooltip frame.
set techTooltip = BlzCreateFrame("CustomRaceTechtreeTooltip", main, 0, 0)
set techTooltipName = BlzGetFrameByName("CustomRaceTechtreeTooltipName", 0)
set techTooltipDesc = BlzGetFrameByName("CustomRaceTechtreeTooltipNameExtended", 0)
call BlzFrameSetPoint(techTooltip, FRAMEPOINT_BOTTOMLEFT, techFrame, FRAMEPOINT_TOPRIGHT, /*
*/ GetTechtreeTooltipOffsetX(), GetTechtreeTooltipOffsetY())
// Create the techtree chunks and icons
set j = 1
loop
exitwhen j > GetTechtreeChunkCount()
set techtreeChunk[j] = BlzCreateFrame("CustomRaceTechtreeChunk", techFrame, 0, j)
call BlzFrameSetSize(techtreeChunk[j], BlzFrameGetWidth(techFrame), /*
*/ BlzFrameGetHeight(techFrame) / I2R(GetTechtreeChunkCount()))
if j == 1 then
call BlzFrameSetPoint(techtreeChunk[j], FRAMEPOINT_TOP, techFrame, /*
*/ FRAMEPOINT_TOP, 0.0, 0.0)
else
call BlzFrameSetPoint(techtreeChunk[j], FRAMEPOINT_TOP, techtreeChunk[j - 1], /*
*/ FRAMEPOINT_BOTTOM, 0.0, 0.0)
endif
set tempFrame = BlzGetFrameByName("CustomRaceTechtreeChunkTitle", j)
call BlzFrameSetText(tempFrame, techName[j])
call BlzFrameSetSize(tempFrame, BlzFrameGetWidth(techFrame), /*
*/ GetTechtreeChunkTextFrameHeight())
call BlzFrameSetPoint(tempFrame, FRAMEPOINT_TOP, techtreeChunk[j], /*
*/ FRAMEPOINT_TOP, 0.0, 0.0)
set oldTempFrame = tempFrame
set tempFrame = BlzGetFrameByName("CustomRaceTechtreeChunkHolder", j)
call BlzFrameSetSize(tempFrame, BlzFrameGetWidth(techFrame) - /*
*/ GetTechtreeChunkTextFrameWidth() , /*
*/ BlzFrameGetHeight(techtreeChunk[j]) - /*
*/ GetTechtreeChunkTextFrameHeight())
call BlzFrameSetPoint(tempFrame, FRAMEPOINT_TOPRIGHT, oldTempFrame, /*
*/ FRAMEPOINT_BOTTOMRIGHT, 0.0, 0.0)
set width = (BlzFrameGetWidth(tempFrame) - 2*GetTechtreeChunkHolderWidthOffset()) / I2R(col)
set size = (BlzFrameGetHeight(tempFrame) - 2*GetTechtreeChunkHolderHeightOffset()) / I2R(row)
set k = 1
loop
exitwhen k > row
set i = 1
loop
exitwhen i > col
set id = (j-1)*(col*row) + (k-1)*col + i
set techtreeIcons[id] = BlzCreateFrame("CustomRaceFactionTechtreeIcon", /*
*/ tempFrame, 0, id)
// DO NOT DELETE THESE LINES! This ensures that the amount of handle ids
// remains the same across all clients (also a pain to debug). (Relevant in JASS)
call BlzGetFrameByName("CustomRaceFactionTechtreeIconActiveBackdrop", id)
call BlzGetFrameByName("CustomRaceFactionTechtreeIconBackdrop", id)
// Again, too lazy to use hashtables here.
set techtreeIconContextId[GetFrameIndex(techtreeIcons[id])] = id
call BlzFrameSetSize(techtreeIcons[id], width, size)
if i == 1 then
if k == 1 then
// Reposition the first icon above
call BlzFrameSetPoint(techtreeIcons[id], FRAMEPOINT_TOPLEFT, /*
*/ tempFrame, FRAMEPOINT_TOPLEFT, /*
*/ GetTechtreeChunkHolderWidthOffset(), /*
*/ -GetTechtreeChunkHolderHeightOffset())
else
// First icon already defined. Just move
// this icon below that.
call BlzFrameSetPoint(techtreeIcons[id], FRAMEPOINT_TOPLEFT, /*
*/ techtreeIcons[id - col], FRAMEPOINT_BOTTOMLEFT, /*
*/ 0.0, 0.0)
endif
else
call BlzFrameSetPoint(techtreeIcons[id], FRAMEPOINT_LEFT, /*
*/ techtreeIcons[id - 1], FRAMEPOINT_RIGHT, /*
*/ 0.0, 0.0)
endif
set i = i + 1
endloop
set k = k + 1
endloop
set dwidth = BlzFrameGetWidth(techFrame) - BlzFrameGetWidth(tempFrame)
set size = BlzFrameGetHeight(tempFrame) / 2.0
set dwidth = RMinBJ(dwidth - GetTechtreeChunkHolderWidthOffset() / 2.0, /*
*/ GetTechtreeArrowMaxWidth())
set size = size - GetTechtreeChunkHolderHeightOffset() / 2.0
// Creating the slide arrows
set id = (j-1)*2 + 1
set techtreeArrow[id] = BlzCreateFrame("CustomRaceButton", techtreeChunk[j], 0, id)
call BlzFrameSetSize(techtreeArrow[id], dwidth, size)
call BlzFrameSetPoint(techtreeArrow[id], FRAMEPOINT_TOPRIGHT, tempFrame, FRAMEPOINT_TOPLEFT, /*
*/ GetTechtreeChunkHolderWidthOffset(), /*
*/ -GetTechtreeChunkHolderHeightOffset())
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonBG", id), /*
*/ GetUpArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonPushedBG", id), /*
*/ GetUpArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonDBG", id), /*
*/ GetUpArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonPushedDBG", id), /*
*/ GetUpArrowButtonModel(), 0, true)
set id = id + 1
set techtreeArrow[id] = BlzCreateFrame("CustomRaceButton", techtreeChunk[j], 0, id)
call BlzFrameSetSize(techtreeArrow[id], dwidth, size)
call BlzFrameSetPoint(techtreeArrow[id], FRAMEPOINT_BOTTOMRIGHT, tempFrame, FRAMEPOINT_BOTTOMLEFT, /*
*/ GetTechtreeChunkHolderWidthOffset(), /*
*/ GetTechtreeChunkHolderHeightOffset())
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonBG", id), /*
*/ GetDownArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonPushedBG", id), /*
*/ GetDownArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonDBG", id), /*
*/ GetDownArrowButtonModel(), 0, true)
call BlzFrameSetTexture(BlzGetFrameByName("CustomRaceButtonPushedDBG", id), /*
*/ GetDownArrowButtonModel(), 0, true)
set j = j + 1
endloop
set tempFrame = null
set oldTempFrame = null
endmethod
private static method init takes nothing returns nothing
local framehandle world = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
if not BlzLoadTOCFile(GetTOCPath()) then
static if IN_DEBUG_MODE then
call Debugger.prepWarning("thistype.init", "Unable to load toc path. Aborting! \n (" + GetTOCPath() + ")")
call Debugger.raiseWarning("thistype")
endif
return
endif
call InitChunkNames()
call thistype.initMainFrame(world)
call thistype.initChildFrames()
static if LIBRARY_FrameLoader then
call FrameLoaderAdd(function thistype.init)
endif
endmethod
implement Init
endstruct
endlibrary
library CustomRacePSelection requires /*
----------------------
*/ CustomRaceCore, /*
----------------------
----------------------
*/ CustomRaceUI, /*
----------------------
----------------------
*/ Init, /*
----------------------
---------------------------------------------------------------------------------------
|
| This library is intended to handle the selection of
| players who can select certain factions in addition
| to the regular races.
|
|---------------------------------------------------------------------------------------
|
| As an additional note, this library dictates whether
| Computer Units get to use custom factions or not via
| COMP_CUSTOM_FACTION (previously ComputerPlayersUseCustomFaction())
|
---------------------------------------------------------------------------------------
*/
globals
private constant boolean COMP_CUSTOM_FACTION = true
endglobals
struct CustomRacePSelection extends array
readonly integer raceIndex
readonly static boolean isSinglePlayer = false
private static integer userPlayerCount = 0
integer faction
integer baseChoice
integer focusFaction
integer focusFactionStack
static integer array baseTechID
integer techtree
integer focusTechtree
integer focusTechtreeStack
integer focusTechID
readonly static integer choicedPlayerSize = 0
readonly static integer unchoicedPlayerSize = 0
readonly static player array choicedPlayers
readonly static player array unchoicedPlayers
private static integer array choicedPlayerMap
private static integer array unchoicedPlayerMap
static method operator [] takes integer index returns thistype
return thistype(index + 1)
endmethod
method getBaseTechID takes integer index returns integer
return baseTechID[(integer(this)-1)*CustomRaceUI_GetTechtreeChunkCount() + index]
endmethod
method setBaseTechID takes integer index, integer value returns nothing
set baseTechID[(integer(this)-1)*CustomRaceUI_GetTechtreeChunkCount() + index] = value
endmethod
//! textmacro_once CRPSelect_ADD_REMOVE takes NAME, SUBNAME
static method add$NAME$Player takes player p returns boolean
local integer id = GetPlayerId(p) + 1
if $SUBNAME$PlayerMap[id] != 0 then
return false
endif
set $SUBNAME$PlayerSize = $SUBNAME$PlayerSize + 1
set $SUBNAME$Players[$SUBNAME$PlayerSize] = p
set $SUBNAME$PlayerMap[id] = 1
return true
endmethod
static method remove$NAME$Player takes player p returns boolean
local integer id = GetPlayerId(p) + 1
local integer i = 1
if $SUBNAME$PlayerMap[id] == 0 then
return false
endif
loop
// The second condition is unnecessary, but
// I want to make sure it really stops at
// that point. If it does, I have a bug to fix.
exitwhen ($SUBNAME$Players[i] == p) or (i > $SUBNAME$PlayerSize)
set i = i + 1
endloop
// Note: The distinction between id and i
// id refers to the player's ID + 1
// i refers to the position of the player in the array in question.
set $SUBNAME$Players[i] = $SUBNAME$Players[$SUBNAME$PlayerSize]
set $SUBNAME$Players[$SUBNAME$PlayerSize] = null
set $SUBNAME$PlayerSize = $SUBNAME$PlayerSize - 1
set $SUBNAME$PlayerMap[id] = 0
return true
endmethod
static method has$NAME$Player takes player p returns boolean
return $SUBNAME$PlayerMap[GetPlayerId(p) + 1] != 0
endmethod
//! endtextmacro
// Looking back, these given method names are quite strange.
//! runtextmacro CRPSelect_ADD_REMOVE("Choiced", "choiced")
//! runtextmacro CRPSelect_ADD_REMOVE("Unchoiced", "unchoiced")
// This initializing static method is invoked in CustomRaceUserUI.
static method init takes nothing returns nothing
local integer i = 0
local player p = null
local race r = null
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS - 4
set p = Player(i)
set r = GetPlayerRace(p)
set thistype[i].raceIndex = GetHandleId(r)
// For string synchronization purposes.
call GetPlayerName(p)
if (GetPlayerController(p) == MAP_CONTROL_USER) and /*
*/ (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING) then
set userPlayerCount = userPlayerCount + 1
if (CustomRace.getRaceFactionCount(r) > 1) then
call thistype.addChoicedPlayer(p)
else
set thistype[i].faction = 1
call thistype.addUnchoicedPlayer(p)
endif
elseif (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING) then
static if COMP_CUSTOM_FACTION then
set thistype[i].faction = GetRandomInt(1, CustomRace.getRaceFactionCount(r))
else
set thistype[i].faction = 1
endif
call thistype.addUnchoicedPlayer(p)
endif
set i = i + 1
endloop
set isSinglePlayer = (userPlayerCount == 1)
endmethod
endstruct
struct CRPSelection extends array
static method [] takes player p returns CustomRacePSelection
return CustomRacePSelection[GetPlayerId(p)]
endmethod
endstruct
endlibrary
library CustomRaceMatchConditions requires /*
----------------------
*/ CustomRaceCore, /*
----------------------
------------------------------
*/ CustomRacePSelection, /*
------------------------------
----------------------
*/ Init, /*
----------------------
---------------------------------------------------
|
| CustomRaceMatchConditions
|
|---------------------------------------------------
|
| The part of the Custom Race system that I abhor
| tinkering with. Making this behave as close to
| the original melee conditions as possible was
| quite tedious on my part, but I eventually succeeded.
|
| OPTIMIZE at your own risk!
|
---------------------------------------------------
*/
native UnitAlive takes unit id returns boolean
globals
private force array allyTeam
private force array enemyTeam
private integer array allyCount
private integer array enemyCount
private boolean array userOnStart
private boolean array activeOnStart
private boolean array controlShared
private real crippleTime = bj_MELEE_CRIPPLE_TIMEOUT
private integer reqDebug = 1
endglobals
struct CustomRaceForce extends array
readonly static force activePlayers = CreateForce()
readonly static player firstPlayer = null
private static method getFirst takes nothing returns nothing
if firstPlayer != null then
return
endif
set firstPlayer = GetEnumPlayer()
endmethod
static method operator first takes nothing returns player
set firstPlayer = null
call ForForce(activePlayers, function thistype.getFirst)
return firstPlayer
endmethod
endstruct
// ============================================================================= //
public function IsPlayerActive takes player whichPlayer returns boolean
return (GetPlayerSlotState(whichPlayer) == PLAYER_SLOT_STATE_PLAYING) and /*
*/ (not IsPlayerObserver(whichPlayer))
endfunction
private function WasPlayerActive takes player whichPlayer returns boolean
return activeOnStart[GetPlayerId(whichPlayer)]
endfunction
private function WasPlayerUser takes player whichPlayer returns boolean
return WasPlayerActive(whichPlayer) and /*
*/ userOnStart[GetPlayerId(whichPlayer)]
endfunction
private function IsPlayerOpponent takes integer id, integer opID returns boolean
local player thePlayer = Player(id)
local player theOpponent = Player(opID)
// The player himself is not an opponent.
// Players that aren't playing aren't opponents.
// Neither are players that are already defeated.
if (id == opID) or /*
*/ (GetPlayerSlotState(theOpponent) != PLAYER_SLOT_STATE_PLAYING) or /*
*/ (bj_meleeDefeated[opID]) then
return false
endif
// Allied players with allied victory set are not opponents.
if (GetPlayerAlliance(thePlayer, theOpponent, ALLIANCE_PASSIVE)) and /*
*/ (GetPlayerAlliance(theOpponent, thePlayer, ALLIANCE_PASSIVE)) and /*
*/ (GetPlayerState(thePlayer, PLAYER_STATE_ALLIED_VICTORY) == 1) and /*
*/ (GetPlayerState(theOpponent, PLAYER_STATE_ALLIED_VICTORY) == 1) then
return false
endif
return true
endfunction
// ============================================================================= //
// ============================================================================= //
private function UnitSurrender takes nothing returns nothing
call SetUnitOwner(GetEnumUnit(), Player(bj_PLAYER_NEUTRAL_VICTIM), false)
endfunction
private function PlayerSurrender takes player whichPlayer returns nothing
local group playerUnits = CreateGroup()
call CachePlayerHeroData(whichPlayer)
call GroupEnumUnitsOfPlayer(playerUnits, whichPlayer, null)
call ForGroup(playerUnits, function UnitSurrender)
call DestroyGroup(playerUnits)
set playerUnits = null
endfunction
private function TeamSurrenderEnum takes nothing returns nothing
call PlayerSurrender(GetEnumPlayer())
endfunction
private function TeamSurrender takes player whichPlayer returns nothing
local integer playerIndex = GetPlayerId(whichPlayer) + 1
call ForForce(allyTeam[playerIndex], function TeamSurrenderEnum)
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private player shareCheckPlayer = null
endglobals
private function TeamGainControl takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
if (PlayersAreCoAllied(shareCheckPlayer, enumPlayer)) and /*
*/ (shareCheckPlayer != enumPlayer) then
call SetPlayerAlliance(shareCheckPlayer, enumPlayer, ALLIANCE_SHARED_VISION, true)
call SetPlayerAlliance(shareCheckPlayer, enumPlayer, ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance(enumPlayer, shareCheckPlayer, ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance(shareCheckPlayer, enumPlayer, ALLIANCE_SHARED_ADVANCED_CONTROL, true)
endif
endfunction
private function TeamShare takes player whichPlayer returns nothing
local integer playerIndex = GetPlayerId(whichPlayer) + 1
local CustomRace curFaction = 0
set curFaction = CustomRace.getRaceFaction(GetPlayerRace(whichPlayer), /*
*/ CRPSelection[whichPlayer].faction)
set controlShared[playerIndex - 1] = true
set shareCheckPlayer = whichPlayer
call ForForce(allyTeam[playerIndex], function TeamGainControl)
call SetPlayerController(whichPlayer, MAP_CONTROL_COMPUTER)
call curFaction.execSetupAI()
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private integer allyStructures = 0
private integer allyKeyStructures = 0
private integer allyCountEnum = 0
private player checkPlayer = null
private constant group allyStructGroup = CreateGroup()
endglobals
private function AllyCountEnum takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
local integer playerIndex = GetPlayerId(enumPlayer)
if (not bj_meleeDefeated[playerIndex]) and /*
*/ (checkPlayer != enumPlayer) then
set allyCountEnum = allyCountEnum + 1
endif
endfunction
private function GetAllyCount takes player whichPlayer returns integer
set allyCountEnum = 0
set checkPlayer = whichPlayer
call ForForce(allyTeam[GetPlayerId(whichPlayer) + 1], function AllyCountEnum)
return allyCountEnum
endfunction
private function GetAllyKeyStructureCountEnum takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and /*
*/ CustomRace.isKeyStructure(GetUnitTypeId(GetFilterUnit()))
endfunction
private function OnEnumAllyStructureCount takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
call GroupEnumUnitsOfPlayer(allyStructGroup, enumPlayer, /*
*/ Filter(function GetAllyKeyStructureCountEnum))
set allyStructures = allyStructures + GetPlayerStructureCount(enumPlayer, true)
set allyKeyStructures = allyKeyStructures + BlzGroupGetSize(allyStructGroup)
endfunction
private function EnumAllyStructureCount takes player whichPlayer returns nothing
local integer playerIndex = GetPlayerId(whichPlayer) + 1
set allyStructures = 0
set allyKeyStructures = 0
call ForForce(allyTeam[playerIndex], function OnEnumAllyStructureCount)
endfunction
private function PlayerIsCrippled takes player whichPlayer returns boolean
call EnumAllyStructureCount(whichPlayer)
// Dead teams are not considered to be crippled.
return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
private function GetAllyStructureCount takes player whichPlayer returns integer
call EnumAllyStructureCount(whichPlayer)
return allyStructures
endfunction
private function GetAllyKeyStructureCount takes player whichPlayer returns integer
call EnumAllyStructureCount(whichPlayer)
return allyKeyStructures
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private player defeatCheckPlayer = null
private player defeatCurrPlayer = null
endglobals
// This removes the locally defeated player from the list
// of enemy players.
private function OnDefeatRemove takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
local integer index = GetPlayerId(enumPlayer) + 1
call ForceRemovePlayer(enemyTeam[index], defeatCheckPlayer)
call ForceRemovePlayer(CustomRaceForce.activePlayers, defeatCheckPlayer)
call CustomRacePSelection.removeUnchoicedPlayer(enumPlayer)
set enemyCount[index] = enemyCount[index] - 1
endfunction
private function DefeatRemove takes player whichPlayer returns nothing
local integer index = GetPlayerId(whichPlayer)
local player prevPlayer = defeatCheckPlayer
set defeatCheckPlayer = whichPlayer
call ForForce(enemyTeam[index + 1], function OnDefeatRemove)
call ForceClear(enemyTeam[index + 1])
call DestroyForce(enemyTeam[index + 1])
set enemyCount[index + 1] = 0
set defeatCheckPlayer = prevPlayer
endfunction
private function DoLeave takes player whichPlayer returns nothing
local player prevPlayer = defeatCurrPlayer
if (GetIntegerGameState(GAME_STATE_DISCONNECTED) != 0) then
call GameOverDialogBJ(whichPlayer, true )
call DefeatRemove(whichPlayer)
else
set bj_meleeDefeated[GetPlayerId(whichPlayer)] = true
call DefeatRemove(whichPlayer)
set defeatCurrPlayer = whichPlayer
call RemovePlayerPreserveUnitsBJ(whichPlayer, PLAYER_GAME_RESULT_DEFEAT, true)
set defeatCurrPlayer = prevPlayer
endif
endfunction
private function DoDefeat takes player whichPlayer returns nothing
local integer index = GetPlayerId(whichPlayer)
local player prevPlayer = defeatCurrPlayer
set bj_meleeDefeated[index] = true
call DefeatRemove(whichPlayer)
set defeatCurrPlayer = whichPlayer
call RemovePlayerPreserveUnitsBJ(whichPlayer, PLAYER_GAME_RESULT_DEFEAT, false)
set defeatCurrPlayer = prevPlayer
endfunction
private function DoDefeatEnum takes nothing returns nothing
local player thePlayer = GetEnumPlayer()
// needs to happen before ownership change
call TeamSurrender(thePlayer)
call DoDefeat(thePlayer)
endfunction
private function DoVictoryEnum takes nothing returns nothing
// Diagnose problems with VictoryEnum
call MeleeDoVictoryEnum()
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private constant force toExposeTo = CreateForce()
endglobals
private function ExposePlayer takes player whichPlayer, boolean expose returns nothing
local integer playerIndex = GetPlayerId(whichPlayer) + 1
call CripplePlayer(whichPlayer, toExposeTo, false)
set bj_playerIsExposed[playerIndex - 1] = expose
call CripplePlayer(whichPlayer, enemyTeam[playerIndex], expose)
endfunction
private function ExposeAllPlayers takes nothing returns nothing
local integer i = 1
loop
exitwhen i > CustomRacePSelection.unchoicedPlayerSize
call ExposePlayer(CustomRacePSelection.unchoicedPlayers[i], false)
set i = i + 1
endloop
endfunction
private function RevealTimerTimeout takes nothing returns nothing
local timer expiredTimer = GetExpiredTimer()
local integer playerIndex = 0
local player exposedPlayer
// Determine which player's timer expired.
set playerIndex = 0
loop
exitwhen (bj_crippledTimer[playerIndex] == expiredTimer)
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
if (playerIndex == bj_MAX_PLAYERS) then
set expiredTimer = null
return
endif
set exposedPlayer = Player(playerIndex)
if (GetLocalPlayer() == exposedPlayer) then
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
endif
// Display a text message to all players, explaining the exposure.
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, MeleeGetCrippledRevealedMessage(exposedPlayer))
// Expose the player.
call ExposePlayer(exposedPlayer, true)
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private force tempForce
private boolean loserVictorCheckRecursive = false
endglobals
private function CheckForVictors takes nothing returns force
local integer playerIndex
set tempForce = CreateForce()
// Check to see if any players have opponents remaining.
set playerIndex = 0
loop
if (not bj_meleeDefeated[playerIndex]) then
// Determine whether or not this player has any remaining opponents.
if enemyCount[playerIndex + 1] > 0 then
call DestroyForce(tempForce)
return null
endif
// Keep track of each opponentless player so that we can give
// them a victory later.
call ForceAddPlayer(tempForce, Player(playerIndex))
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
// Set the game over global flag
return tempForce
endfunction
private function CheckForLosersAndVictors takes nothing returns nothing
local integer playerIndex
local integer structureCount = 0
local player indexPlayer
local force defeatedPlayers = CreateForce()
local force victoriousPlayers
local boolean prevCheck = loserVictorCheckRecursive
// If the game is already over, do nothing
if (bj_meleeGameOver) then
call DestroyForce(defeatedPlayers)
set defeatedPlayers = null
return
endif
// If the game was disconnected then it is over, in this case we
// don't want to report results for anyone as they will most likely
// conflict with the actual game results
if (GetIntegerGameState(GAME_STATE_DISCONNECTED) != 0) then
set bj_meleeGameOver = true
call DestroyForce(defeatedPlayers)
set defeatedPlayers = null
return
endif
// Check each player to see if he or she has been defeated yet.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
if (not bj_meleeDefeated[playerIndex] and not bj_meleeVictoried[playerIndex]) then
set structureCount = GetAllyStructureCount(indexPlayer)
if (structureCount <= 0) then
// Keep track of each defeated player so that we can give
// them a defeat later.
call ForceAddPlayer(defeatedPlayers, Player(playerIndex))
// Set their defeated flag now so MeleeCheckForVictors
// can detect victors.
set bj_meleeDefeated[playerIndex] = true
endif
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
// Now that the defeated flags are set, check if there are any victors
set victoriousPlayers = CheckForVictors()
// Defeat all defeated players
call ForForce(defeatedPlayers, function DoDefeatEnum)
// Recheck victory conditions here
if loserVictorCheckRecursive and (victoriousPlayers != null) then
set bj_meleeGameOver = true
call ForForce(victoriousPlayers, function DoVictoryEnum)
call DestroyForce(victoriousPlayers)
call DestroyForce(defeatedPlayers)
set victoriousPlayers = null
set defeatedPlayers = null
return
endif
if (loserVictorCheckRecursive) then
return
endif
set loserVictorCheckRecursive = true
call CheckForLosersAndVictors()
set loserVictorCheckRecursive = prevCheck
// Give victory to all victorious players
// If the game is over we should remove all observers
if (bj_meleeGameOver) then
call MeleeRemoveObservers()
endif
call DestroyForce(victoriousPlayers)
call DestroyForce(defeatedPlayers)
set defeatedPlayers = null
set victoriousPlayers = null
endfunction
private function CheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local force crippledPlayers = CreateForce()
local boolean isNowCrippled
// The "finish soon" exposure of all players overrides any "crippled" exposure
if bj_finishSoonAllExposed then
call DestroyForce(crippledPlayers)
set crippledPlayers = null
return
endif
// Check each player to see if he or she has been crippled or uncrippled.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = PlayerIsCrippled(indexPlayer)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
// Player became crippled; start their cripple timer.
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], crippleTime, false, function RevealTimerTimeout)
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Show the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
// Display a warning message.
endif
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, MeleeGetCrippledWarningMessage(indexPlayer))
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
// Player became uncrippled; stop their cripple timer.
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
endif
// Display a confirmation message if the player's team is still alive.
if (GetAllyStructureCount(indexPlayer) > 0) then
if (bj_playerIsExposed[playerIndex]) then
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
else
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
endif
endif
// If the player granted shared vision, deny that vision now.
call ExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
endfunction
// ============================================================================= //
// ============================================================================= //
private function CheckAddedUnit takes unit whichUnit returns nothing
local player owner = GetOwningPlayer(whichUnit)
// If the player was crippled, this unit may have uncrippled him/her.
if (bj_playerIsCrippled[GetPlayerId(owner)]) then
call CheckForCrippledPlayers()
endif
endfunction
private function CheckLostUnit takes unit whichUnit returns nothing
local player owner = GetOwningPlayer(whichUnit)
local integer count = GetPlayerStructureCount(owner, true)
// We only need to check for mortality if this was the last building.
if (count <= 0) then
call CheckForLosersAndVictors()
endif
// Check if the lost unit has crippled or uncrippled the player.
// (A team with 0 units is dead, and thus considered uncrippled.)
call CheckForCrippledPlayers()
endfunction
// ============================================================================= //
// ============================================================================= //
private function OnObserverLeave takes nothing returns nothing
local player thePlayer = GetTriggerPlayer()
call RemovePlayerPreserveUnitsBJ(thePlayer, PLAYER_GAME_RESULT_NEUTRAL, false)
endfunction
private function StrTertiaryOp takes boolean flag, string s1, string s2 returns string
if flag then
return s1
endif
return s2
endfunction
public function OnAllianceChange takes nothing returns nothing
local player indexPlayer = GetTriggerPlayer()
local player otherPlayer
local integer index = GetPlayerId(indexPlayer)
local integer otherIndex = 0
// Took too long to find this glaring bug, but it's finally fixed.
// Bug: indexPlayer is null when this function is called directly
// and not because of an event, hence the need for indexPlayer
// to refer to CustomRaceForce.first in the first place.
// This bug resulted in PlayersAreCoAllied returning possible false
// negatives for Player 1.
if (indexPlayer == null) then
set indexPlayer = CustomRaceForce.first
set index = GetPlayerId(indexPlayer)
endif
loop
exitwhen otherIndex >= bj_MAX_PLAYERS
set otherPlayer = Player(otherIndex)
loop
exitwhen (index == otherIndex) or (not WasPlayerActive(otherPlayer))
if (BlzForceHasPlayer(allyTeam[index + 1], otherPlayer)) and /*
*/ (not PlayersAreCoAllied(indexPlayer, otherPlayer)) then
call ForceRemovePlayer(allyTeam[index + 1], otherPlayer)
call ForceRemovePlayer(allyTeam[otherIndex + 1], indexPlayer)
set allyCount[index + 1] = allyCount[index + 1] - 1
set allyCount[otherIndex + 1] = allyCount[otherIndex + 1] - 1
if (enemyCount[index + 1] > 0) and (enemyCount[otherIndex + 1] > 0) then
call ForceAddPlayer(enemyTeam[index + 1], otherPlayer)
call ForceAddPlayer(enemyTeam[otherIndex + 1], indexPlayer)
set enemyCount[index + 1] = enemyCount[index + 1] + 1
set enemyCount[otherIndex + 1] = enemyCount[otherIndex + 1] + 1
endif
if controlShared[index] then
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_VISION, false)
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_CONTROL, false)
call SetPlayerAlliance(otherPlayer, indexPlayer, ALLIANCE_SHARED_CONTROL, false)
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_ADVANCED_CONTROL, false)
endif
elseif (BlzForceHasPlayer(enemyTeam[index + 1], otherPlayer)) and /*
*/ (PlayersAreCoAllied(indexPlayer, otherPlayer)) then
call ForceRemovePlayer(enemyTeam[index + 1], otherPlayer)
call ForceRemovePlayer(enemyTeam[otherIndex + 1], indexPlayer)
set enemyCount[index + 1] = enemyCount[index + 1] - 1
set enemyCount[otherIndex + 1] = enemyCount[otherIndex + 1] - 1
call ForceAddPlayer(allyTeam[index + 1], otherPlayer)
call ForceAddPlayer(allyTeam[otherIndex + 1], indexPlayer)
set allyCount[index + 1] = allyCount[index + 1] + 1
set allyCount[otherIndex + 1] = allyCount[otherIndex + 1] + 1
if controlShared[index] then
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_VISION, true)
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance(otherPlayer, indexPlayer, ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance(indexPlayer, otherPlayer, ALLIANCE_SHARED_ADVANCED_CONTROL, true)
endif
endif
exitwhen true
endloop
set otherIndex = otherIndex + 1
endloop
call CheckForLosersAndVictors()
call CheckForCrippledPlayers()
endfunction
private function OnPlayerLeave takes nothing returns nothing
local player thePlayer = GetTriggerPlayer()
call CachePlayerHeroData(thePlayer)
// This is the same as defeat except the player generates the message
// "player left the game" as opposed to "player was defeated".
if (GetAllyCount(thePlayer) > 0) then
// If at least one ally is still alive and kicking, share units with
// them and proceed with death.
call TeamShare(thePlayer)
call DoLeave(thePlayer)
else
// If no living allies remain, swap all units and buildings over to
// neutral_passive and proceed with death.
call TeamSurrender(thePlayer)
call DoLeave(thePlayer)
endif
call CheckForLosersAndVictors()
endfunction
private function OnPlayerDefeat takes nothing returns nothing
local player thePlayer = GetTriggerPlayer()
call CachePlayerHeroData(thePlayer)
// Change it slightly so that control is automatically
// ceded to the computer.
if (GetAllyCount(thePlayer) > 0) then
// If at least one ally is still alive and kicking, share units with
// them and proceed with death.
call TeamShare(thePlayer)
if (not bj_meleeDefeated[GetPlayerId(thePlayer)]) then
call DoDefeat(thePlayer)
endif
else
// If no living allies remain, swap all units and buildings over to
// neutral_passive and proceed with death.
call TeamSurrender(thePlayer)
if (not bj_meleeDefeated[GetPlayerId(thePlayer)]) then
call DoDefeat(thePlayer)
endif
endif
if defeatCurrPlayer == thePlayer then
return
endif
call CheckForLosersAndVictors()
endfunction
private function OnConstructStart takes nothing returns nothing
call CheckAddedUnit(GetConstructingStructure())
endfunction
private function OnStructureDeath takes nothing returns nothing
local unit whichUnit = GetTriggerUnit()
if IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE) then
call CheckLostUnit(whichUnit)
endif
endfunction
private function OnConstructCancel takes nothing returns nothing
call CheckLostUnit(GetTriggerUnit())
endfunction
// ============================================================================= //
private function OnTournamentFinishRule takes integer multiplier returns nothing
local integer array playerScore
local integer array teamScore
local force array teamForce
local integer teamCount
local integer index
local player indexPlayer
local integer index2
local player indexPlayer2
local integer bestTeam
local integer bestScore
local boolean draw
// Compute individual player scores
set index = 0
loop
set indexPlayer = Player(index)
if WasPlayerUser(indexPlayer) then
set playerScore[index] = IMinBJ(GetTournamentScore(indexPlayer), 1)
else
set playerScore[index] = 0
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Compute team scores and team forces
set teamCount = 0
set index = 0
loop
if playerScore[index] != 0 then
set indexPlayer = Player(index)
set teamScore[teamCount] = 0
set teamForce[teamCount] = allyTeam[index + 1]
set index2 = index
loop
loop
exitwhen not IsPlayerInForce(Player(index2), teamForce[teamCount])
if playerScore[index2] != 0 then
set indexPlayer2 = Player(index2)
set teamScore[teamCount] = teamScore[teamCount] + playerScore[index2]
endif
exitwhen true
endloop
set index2 = index2 + 1
exitwhen index2 == bj_MAX_PLAYERS
endloop
set teamCount = teamCount + 1
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// The game is now over
set bj_meleeGameOver = true
// There should always be at least one team, but continue to work if not
if teamCount != 0 then
// Find best team score
set bestTeam = -1
set bestScore = -1
set index = 0
loop
if teamScore[index] > bestScore then
set bestTeam = index
set bestScore = teamScore[index]
endif
set index = index + 1
exitwhen index == teamCount
endloop
// Check whether the best team's score is 'multiplier' times better than
// every other team. In the case of multiplier == 1 and exactly equal team
// scores, the first team (which was randomly chosen by the server) will win.
set draw = false
set index = 0
loop
if index != bestTeam then
if bestScore < (multiplier * teamScore[index]) then
set draw = true
endif
endif
set index = index + 1
exitwhen index == teamCount
endloop
if draw then
// Give draw to all players on all teams
set index = 0
loop
call ForForce(teamForce[index], function MeleeDoDrawEnum)
set index = index + 1
exitwhen index == teamCount
endloop
else
// Give defeat to all players on teams other than the best team
set index = 0
loop
if index != bestTeam then
call ForForce(teamForce[index], function DoDefeatEnum)
endif
set index = index + 1
exitwhen index == teamCount
endloop
// Give victory to all players on the best team
call ForForce(teamForce[bestTeam], function DoVictoryEnum)
endif
endif
// Clean up leaks (Thanks to Karaulov's Jass Script Helper)
set index = 0
loop
exitwhen index == bj_MAX_PLAYERS
set teamForce[index] = null
set index = index + 1
endloop
endfunction
private function OnTournamentFinishSoon takes nothing returns nothing
// Note: We may get this trigger multiple times
local integer playerIndex
local player indexPlayer
local real timeRemaining = GetTournamentFinishSoonTimeRemaining()
if bj_finishSoonAllExposed then
return
endif
set bj_finishSoonAllExposed = true
// Reset all crippled players and their timers, and hide the local crippled timer dialog
set playerIndex = 0
loop
exitwhen playerIndex > CustomRacePSelection.unchoicedPlayerSize
set indexPlayer = CustomRacePSelection.unchoicedPlayers[playerIndex]
call ExposePlayer(indexPlayer, false)
/*
if bj_playerIsCrippled[playerIndex] then
// Uncripple the player
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
endif
endif
*/
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
// Expose all players
// call ExposeAllPlayers()
// Show the "finish soon" timer dialog and set the real time remaining
call TimerDialogDisplay(bj_finishSoonTimerDialog, true)
call TimerDialogSetRealTimeRemaining(bj_finishSoonTimerDialog, timeRemaining)
endfunction
private function OnTournamentFinishNow takes nothing returns nothing
local integer rule = GetTournamentFinishNowRule()
// If the game is already over, do nothing
if bj_meleeGameOver then
return
endif
if (rule == 1) then
// Finals games
call MeleeTournamentFinishNowRuleA(1)
else
// Preliminary games
call MeleeTournamentFinishNowRuleA(3)
endif
// Since the game is over we should remove all observers
call MeleeRemoveObservers()
endfunction
// ============================================================================= //
// ============================================================================= //
private function DefineTeamLineupEx takes integer index, integer otherIndex returns nothing
local integer id = index + 1
local integer otherID = otherIndex + 1
local player whichPlayer = Player(index)
local player otherPlayer
// One of the primary conditions for team lineup
// is that the player must be playing (obviously).
set activeOnStart[index] = IsPlayerActive(whichPlayer)
if not activeOnStart[index] then
return
endif
set userOnStart[index] = GetPlayerController(whichPlayer) == MAP_CONTROL_USER
call ForceAddPlayer(CustomRaceForce.activePlayers, whichPlayer)
if allyTeam[id] == null then
set allyTeam[id] = CreateForce()
set allyCount[id] = 1
call ForceAddPlayer(allyTeam[id], whichPlayer)
endif
if enemyTeam[id] == null then
set enemyTeam[id] = CreateForce()
set enemyCount[id] = 0
endif
loop
exitwhen otherIndex >= bj_MAX_PLAYERS
set otherPlayer = Player(otherIndex)
if IsPlayerActive(otherPlayer) then
// Instantiate the forces
if allyTeam[otherID] == null then
set allyTeam[otherID] = CreateForce()
set allyCount[otherID] = 1
call ForceAddPlayer(allyTeam[otherID], otherPlayer)
endif
if enemyTeam[otherID] == null then
set enemyTeam[otherID] = CreateForce()
set enemyCount[otherID] = 0
endif
if PlayersAreCoAllied(whichPlayer, otherPlayer) then
call ForceAddPlayer(allyTeam[id], otherPlayer)
call ForceAddPlayer(allyTeam[otherID], whichPlayer)
set allyCount[id] = allyCount[id] + 1
set allyCount[otherID] = allyCount[otherID] + 1
else
call ForceAddPlayer(enemyTeam[id], otherPlayer)
call ForceAddPlayer(enemyTeam[otherID], whichPlayer)
set enemyCount[id] = enemyCount[id] + 1
set enemyCount[otherID] = enemyCount[otherID] + 1
endif
endif
set otherIndex = otherIndex + 1
set otherID = otherIndex + 1
endloop
endfunction
private function DefineTeamLineup takes nothing returns nothing
local integer index = 0
local integer otherIndex = 0
loop
exitwhen index >= bj_MAX_PLAYERS
set otherIndex = index + 1
call DefineTeamLineupEx(index, otherIndex)
set index = index + 1
endloop
endfunction
private function DefineVictoryDefeatEx takes nothing returns nothing
local trigger constructCancelTrig = CreateTrigger()
local trigger deathTrig = CreateTrigger()
local trigger constructStartTrig = CreateTrigger()
local trigger defeatTrig = CreateTrigger()
local trigger leaveTrig = CreateTrigger()
local trigger allianceTrig = CreateTrigger()
local trigger obsLeaveTrig = CreateTrigger()
local trigger tournamentSoonTrig = CreateTrigger()
local trigger tournamentNowTrig = CreateTrigger()
local integer index
local player indexPlayer
call TriggerAddAction(constructCancelTrig, function OnConstructCancel)
call TriggerAddAction(deathTrig, function OnStructureDeath)
call TriggerAddAction(constructStartTrig, function OnConstructStart)
call TriggerAddAction(defeatTrig, function OnPlayerDefeat)
call TriggerAddAction(leaveTrig, function OnPlayerLeave)
call TriggerAddAction(allianceTrig, function OnAllianceChange)
call TriggerAddAction(obsLeaveTrig, function OnObserverLeave)
call TriggerAddAction(tournamentSoonTrig, function OnTournamentFinishSoon)
call TriggerAddAction(tournamentNowTrig, function OnTournamentFinishNow)
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
call TriggerRegisterGameEvent(tournamentSoonTrig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
// Set a trigger to fire when we receive a "finish now" game event
call TriggerRegisterGameEvent(tournamentNowTrig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if IsPlayerActive(indexPlayer) then
set bj_meleeDefeated[index] = false
set bj_meleeVictoried[index] = false
// Create a timer and timer window in case the player is crippled.
// Coder Notes: Better leave this section untouched.
set bj_playerIsCrippled[index] = false
set bj_playerIsExposed[index] = false
set bj_crippledTimer[index] = CreateTimer()
set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index], /*
*/ MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
call TriggerRegisterPlayerUnitEvent(constructCancelTrig, indexPlayer, /*
*/ EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
// Set a trigger to fire whenever a unit dies for this player.
call TriggerRegisterPlayerUnitEvent(deathTrig, indexPlayer, /*
*/ EVENT_PLAYER_UNIT_DEATH, null)
// Set a trigger to fire whenever a unit begins construction for this player
call TriggerRegisterPlayerUnitEvent(constructStartTrig, indexPlayer, /*
*/ EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
// Set a trigger to fire whenever this player defeats-out
call TriggerRegisterPlayerEvent(defeatTrig, indexPlayer, EVENT_PLAYER_DEFEAT)
// Set a trigger to fire whenever this player leaves
call TriggerRegisterPlayerEvent(leaveTrig, indexPlayer, EVENT_PLAYER_LEAVE)
// Set a trigger to fire whenever this player changes his/her alliances.
call TriggerRegisterPlayerAllianceChange(allianceTrig, indexPlayer, ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(allianceTrig, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
else
set bj_meleeDefeated[index] = true
set bj_meleeVictoried[index] = false
// Handle leave events for observers
if (IsPlayerObserver(indexPlayer)) then
// Set a trigger to fire whenever this player leaves
call TriggerRegisterPlayerEvent(obsLeaveTrig, indexPlayer, EVENT_PLAYER_LEAVE)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
public function DefineVictoryDefeat takes nothing returns nothing
// I have no idea why I didn't just place the contents of DefineVictoryDefeatEx here
// in the first place.
call DefineVictoryDefeatEx()
endfunction
// ============================================================================= //
private struct S extends array
private static method init takes nothing returns nothing
call DefineTeamLineup()
endmethod
implement Init
endstruct
endlibrary
//$ noimport
library CustomRaceMatch requires /*
--------------------------
*/ CustomRaceCore, /*
--------------------------
--------------------------
*/ CustomRaceUI, /*
--------------------------
------------------------------
*/ CustomRacePSelection, /*
------------------------------
----------------------------------
*/ CustomRaceMatchConditions, /*
----------------------------------
------------------------------
*/ optional Init /*
------------------------------
*/
globals
private constant boolean FOGGED_START = false
private constant boolean USE_EXTRA_TICK = true
public constant boolean APPLY_TIMER_IN_SINGLE_PLAYER = false
private constant integer GAME_START_TICKS = 3
private constant integer EXTRA_TICK_FOR_START = 1
private constant real TICK_INTERVAL = 1.0
private constant real DISPLAY_LIFETIME = 0.80
private constant real DISPLAY_INTERVAL = 1.0 / 100.0
endglobals
// ============================================================================= //
private function ClearMusicPlaylist takes nothing returns nothing
// Observers can't play any faction playlist,
// so return at this point. Comment later
// if this causes desyncs.
if IsPlayerObserver(GetLocalPlayer()) then
return
endif
call ClearMapMusic()
call StopMusic(false)
endfunction
// ============================================================================= //
// ============================================================================= //
// In previous versions, visibility was actually affected.
// In modern versions, visibility is kept intact and only
// the time of day is affected.
// ============================================================================= //
private function StartingVisibility takes nothing returns nothing
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, bj_MELEE_STARTING_TOD)
call SuspendTimeOfDay(true)
static if FOGGED_START then
call FogMaskEnable(true)
call FogEnable(true)
endif
endfunction
// ============================================================================= //
// ============================================================================= //
private function StartingHeroLimit takes nothing returns nothing
local integer index = 0
local integer i = 1
local integer maxHeroIndex = CustomRace.getGlobalHeroMaxIndex()
local player whichPlayer
loop
exitwhen index > bj_MAX_PLAYERS
set whichPlayer = Player(index)
set i = 1
call SetPlayerTechMaxAllowed(whichPlayer, 'HERO', bj_MELEE_HERO_LIMIT)
loop
exitwhen i > maxHeroIndex
call SetPlayerTechMaxAllowed(whichPlayer, CustomRace.getGlobalHero(i), /*
*/ bj_MELEE_HERO_TYPE_LIMIT)
set i = i + 1
endloop
set index = index + 1
endloop
endfunction
// ============================================================================= //
// ============================================================================= //
private function GrantItem takes unit hero returns nothing
if IsUnitType(hero, UNIT_TYPE_HERO) then
call MeleeGrantItemsToHero(hero)
endif
endfunction
private function OnNeutralHeroHired takes nothing returns nothing
call GrantItem(GetSoldUnit())
endfunction
private function OnTrainedHeroFinish takes nothing returns nothing
call GrantItem(GetTrainedUnit())
endfunction
private function GrantHeroItems takes nothing returns nothing
local integer index = 0
local trigger trig = CreateTrigger()
local player whichPlayer = null
call TriggerAddAction(trig, function OnTrainedHeroFinish)
loop
exitwhen index > bj_MAX_PLAYER_SLOTS
// Initialize the twinked hero counts.
set bj_meleeTwinkedHeroes[index] = 0
set whichPlayer = Player(index)
// Register for an event whenever a hero is trained, so that we can give
// him/her their starting items. Exclude
if (index < bj_MAX_PLAYERS) and CustomRaceMatchConditions_IsPlayerActive(whichPlayer) then
call TriggerRegisterPlayerUnitEvent(trig, whichPlayer, /*
*/ EVENT_PLAYER_UNIT_TRAIN_FINISH, null)
endif
set index = index + 1
endloop
// Register for an event whenever a neutral hero is hired, so that we
// can give him/her their starting items.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, Player(PLAYER_NEUTRAL_PASSIVE), /*
*/ EVENT_PLAYER_UNIT_SELL, null)
call TriggerAddAction(trig, function OnNeutralHeroHired)
set trig = null
// Flag that we are giving starting items to heroes, so that the melee
// starting units code can create them as necessary.
set bj_meleeGrantHeroItems = true
endfunction
// ============================================================================= //
// ============================================================================= //
private function StartingResources takes nothing returns nothing
local integer index
local player whichPlayer
local version v
local integer startingGold = bj_MELEE_STARTING_GOLD_V1
local integer startingLumber = bj_MELEE_STARTING_LUMBER_V1
set v = VersionGet()
if (v == VERSION_REIGN_OF_CHAOS) then
set startingGold = bj_MELEE_STARTING_GOLD_V0
set startingLumber = bj_MELEE_STARTING_LUMBER_V0
endif
// Set each player's starting resources.
set index = 0
loop
set whichPlayer = Player(index)
if CustomRaceMatchConditions_IsPlayerActive(whichPlayer) then
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, startingGold)
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_LUMBER, startingLumber)
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
// ============================================================================= //
// ============================================================================= //
private function RemoveNearbyUnits takes real x, real y, real radius returns nothing
local integer i = 0
local integer owner = 0
local integer size = 0
local group nearbyUnits = CreateGroup()
local unit enumUnit
call GroupEnumUnitsInRange(nearbyUnits, x, y, radius, null)
set size = BlzGroupGetSize(nearbyUnits)
loop
exitwhen i >= size
set enumUnit = BlzGroupUnitAt(nearbyUnits, i)
set owner = GetPlayerId(GetOwningPlayer(enumUnit))
if (owner == PLAYER_NEUTRAL_AGGRESSIVE) or /*
*/ ((owner == PLAYER_NEUTRAL_PASSIVE) and /*
*/ (not IsUnitType(enumUnit, UNIT_TYPE_STRUCTURE))) then
// Remove any Neutral Hostile units or
// Neutral Passive units (not structures) from the area.
call RemoveUnit(enumUnit)
endif
set i = i + 1
endloop
call DestroyGroup(nearbyUnits)
set enumUnit = null
set nearbyUnits = null
endfunction
private function ClearExcessUnits takes nothing returns nothing
local integer index = 0
local real locX
local real locY
local player indexPlayer
loop
set indexPlayer = Player(index)
// If the player slot is being used, clear any nearby creeps.
if CustomRaceMatchConditions_IsPlayerActive(indexPlayer) then
set locX = GetStartLocationX(GetPlayerStartLocation(indexPlayer))
set locY = GetStartLocationY(GetPlayerStartLocation(indexPlayer))
call RemoveNearbyUnits(locX, locY, bj_MELEE_CLEAR_UNITS_RADIUS)
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
// ============================================================================= //
// ============================================================================= //
private function DefineVictoryDefeat takes nothing returns nothing
// Unravelling this function will open a can of worms
// the likes which would not likely be appreciated.
// Leave it as it is, and make changes in a separate
// library specifically for this function.
call CustomRaceMatchConditions_DefineVictoryDefeat()
endfunction
// ============================================================================= //
// ============================================================================= //
private function OnStartCheckAlliance takes nothing returns nothing
local timer whichTimer = GetExpiredTimer()
call PauseTimer(whichTimer)
call DestroyTimer(whichTimer)
set whichTimer = null
call CustomRaceMatchConditions_OnAllianceChange()
endfunction
public function TestVictoryDefeat takes nothing returns nothing
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer(), 2.0, false, function OnStartCheckAlliance)
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private integer tempStart = 0
private location tempStartLoc = null
private player tempStartPlayer = null
endglobals
public function OnStartGetPlayer takes nothing returns player
return tempStartPlayer
endfunction
public function OnStartGetLoc takes nothing returns location
return tempStartLoc
endfunction
private function StartingUnits takes nothing returns nothing
local integer index = 1
local CustomRacePSelection obj = 0
local CustomRace faction = 0
local player indexPlayer
local race pRace
call Preloader( "scripts\\SharedMelee.pld" )
loop
exitwhen index > CustomRacePSelection.unchoicedPlayerSize
set indexPlayer = CustomRacePSelection.unchoicedPlayers[index]
set tempStartPlayer = indexPlayer
set tempStart = GetPlayerStartLocation(indexPlayer)
set tempStartLoc = GetStartLocationLoc(tempStart)
set pRace = GetPlayerRace(indexPlayer)
set obj = CRPSelection[indexPlayer]
set faction = CustomRace.getRaceFaction(pRace, obj.faction)
call faction.execSetup()
if GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER then
call faction.execSetupAI()
endif
call RemoveLocation(tempStartLoc)
set index = index + 1
endloop
// Do NOT make these usable afterwards!
set tempStartPlayer = null
set tempStart = 0
set tempStartLoc = null
endfunction
// ============================================================================= //
// ============================================================================= //
private struct FrameInterpolation
private static constant real FRAME_SCALE = 10.0
private static constant real FRAME_ENDSCALE = 2.0
private static constant real START_X = 0.40
private static constant real END_X = 0.40
private static constant real START_Y = 0.45
private static constant real END_Y = 0.25
private static constant framepointtype POINT = FRAMEPOINT_CENTER
private static thistype array objectList
private static integer objectCurIndex = 0
private static timer interpolator = CreateTimer()
private string message
private integer maxTicks
private integer ticks
private framehandle frame
private static method alphaResponse takes real x returns real
set x = x - 0.5
return -16.0*(x*x*x*x) + 1.0
endmethod
private static method slideResponse takes real x returns real
set x = x - 0.5
return -4.0*(x*x*x) + 0.5
endmethod
private static method scaleResponse takes real x returns real
return -(x*x*x*x*x*x) + 1.0
endmethod
private method destroy takes nothing returns nothing
set this.ticks = 0
set this.maxTicks = 0
call BlzFrameSetVisible(this.frame, false)
call BlzDestroyFrame(this.frame)
call this.deallocate()
endmethod
private static method onUpdate takes nothing returns nothing
local integer i = 1
local thistype this = 0
local real ratio = 0.0
local real resp = 0.0
local real cx = 0.0
local real cy = 0.0
local real scale = 0.0
loop
exitwhen i > objectCurIndex
set this = objectList[i]
set this.ticks = this.ticks + 1
set ratio = I2R(this.ticks) / I2R(this.maxTicks)
call BlzFrameSetAlpha(this.frame, R2I(255.0*thistype.alphaResponse(ratio)))
set resp = slideResponse(ratio)
set cx = START_X*resp + END_X*(1-resp)
set cy = START_Y*resp + END_Y*(1-resp)
set resp = scaleResponse(ratio)
set scale = FRAME_SCALE*resp + FRAME_ENDSCALE*(1-resp)
call BlzFrameSetAbsPoint(this.frame, POINT, cx, cy)
call BlzFrameSetScale(this.frame, scale)
if this.ticks >= this.maxTicks then
set objectList[i] = objectList[objectCurIndex]
set objectCurIndex = objectCurIndex - 1
set i = i - 1
call this.destroy()
endif
set i = i + 1
endloop
if objectCurIndex < 1 then
call PauseTimer(interpolator)
endif
endmethod
private static method insert takes thistype this returns nothing
set objectCurIndex = objectCurIndex + 1
set objectList[objectCurIndex] = this
if objectCurIndex == 1 then
call TimerStart(interpolator, DISPLAY_INTERVAL, true, function thistype.onUpdate)
endif
endmethod
static method request takes string msg, real lifetime returns nothing
local thistype this = thistype.allocate()
set this.message = msg
set this.maxTicks = R2I(lifetime / DISPLAY_INTERVAL + 0.01)
set this.ticks = 0
set this.frame = BlzCreateFrameByType("TEXT", "CustomRaceMatchDisplayText", /*
*/ BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), /*
*/ "", integer(this))
call BlzFrameSetText(this.frame, message)
call BlzFrameSetScale(this.frame, FRAME_SCALE)
call BlzFrameSetAlpha(this.frame, 0)
call BlzFrameSetAbsPoint(this.frame, POINT, START_X, START_Y)
call thistype.insert(this)
endmethod
endstruct
private function DisplayToWorld takes string msg, real lifetime returns nothing
call FrameInterpolation.request(msg, lifetime)
endfunction
// ============================================================================= //
// ============================================================================= //
globals
private integer beginTick = 0
private integer extraTick = 0
private group tickGroup = null
private sound tempSound = null
endglobals
private function GenerateTickSound takes nothing returns sound
set tempSound = CreateSound( "Sound\\Interface\\BattleNetTick.wav", false, false, false, 10, 10, "" )
call SetSoundParamsFromLabel( tempSound, "ChatroomTimerTick" )
call SetSoundDuration( tempSound, 476 )
return tempSound
endfunction
private function GenerateHornSound takes nothing returns sound
set tempSound = CreateSound( "Sound\\Ambient\\DoodadEffects\\TheHornOfCenarius.wav", false, false, false, 10, 10, "DefaultEAXON" )
call SetSoundParamsFromLabel( tempSound, "HornOfCenariusSound" )
call SetSoundDuration( tempSound, 12120 )
return tempSound
endfunction
private function PlaySoundForPlayer takes sound snd, player p returns nothing
if GetLocalPlayer() != p then
call SetSoundVolume(snd, 0)
endif
call StartSound(snd)
call KillSoundWhenDone(snd)
endfunction
// ============================================================================= //
// ============================================================================= //
private function SetupPlaylist takes nothing returns nothing
local player whichPlayer = GetLocalPlayer()
local CustomRacePSelection obj = CRPSelection[whichPlayer]
local CustomRace faction = CustomRace.getRaceFaction(GetPlayerRace(whichPlayer), obj.faction)
if faction == 0 then
return
endif
call SetMapMusic(faction.playlist, true, 0)
call PlayMusic(faction.playlist)
endfunction
private function ResetVisuals takes nothing returns nothing
call EnableDragSelect(true, true)
call EnablePreSelect(true, true)
call EnableSelect(true, true)
call EnableUserControl(true)
call EnableUserUI(true)
call SuspendTimeOfDay(false)
endfunction
private function MatchTickDown takes nothing returns nothing
local integer i = 0
local integer size = 0
local timer expTimer
set beginTick = beginTick - 1
if beginTick > 0 then
call StartSound(GenerateTickSound())
call KillSoundWhenDone(tempSound)
call DisplayToWorld(I2S(beginTick), DISPLAY_LIFETIME)
return
endif
set extraTick = extraTick - 1
if extraTick > 0 then
return
endif
call StartSound(GenerateHornSound())
call KillSoundWhenDone(tempSound)
call DisplayToWorld("|cffff4040Start!|r", 1.20)
set expTimer = GetExpiredTimer()
call PauseTimer(expTimer)
call DestroyTimer(expTimer)
set expTimer = null
call TestVictoryDefeat()
call ResetVisuals()
call SetupPlaylist()
set size = BlzGroupGetSize(tickGroup)
loop
exitwhen i >= size
call PauseUnit(BlzGroupUnitAt(tickGroup, i), false)
set i = i + 1
endloop
endfunction
private function SetupVisuals takes nothing returns nothing
local real zdist = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
local real ndist = zdist + 1250.0
if IsPlayerInForce(GetLocalPlayer(), CustomRaceForce.activePlayers) then
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, ndist, 0.00)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, zdist, 0.00)
endif
call EnableDragSelect(false, false)
call EnablePreSelect(false, false)
call EnableSelect(false, false)
call EnableUserControl(false)
call EnableUserUI(false)
endfunction
private function BeginMatch takes nothing returns nothing
local rect world = GetWorldBounds()
local integer i = 0
local integer size = 0
set tickGroup = CreateGroup()
set beginTick = GAME_START_TICKS + 1
if USE_EXTRA_TICK then
set extraTick = EXTRA_TICK_FOR_START
endif
call TimerStart(CreateTimer(), TICK_INTERVAL, true, function MatchTickDown)
call SetupVisuals()
call GroupEnumUnitsInRect(tickGroup, world, null)
set size = BlzGroupGetSize(tickGroup)
loop
exitwhen i >= size
call PauseUnit(BlzGroupUnitAt(tickGroup, i), true)
set i = i + 1
endloop
// Cleaned up, thanks to Jass Script Helper.
call RemoveRect(world)
set world = null
endfunction
// ============================================================================= //
// ============================================================================= //
public function MeleeInitialization takes nothing returns nothing
call ClearMusicPlaylist()
call StartingVisibility()
call StartingHeroLimit()
call GrantHeroItems()
call StartingResources()
call ClearExcessUnits()
endfunction
public function MeleeInitializationFinish takes nothing returns nothing
call DefineVictoryDefeat()
call StartingUnits()
call BeginMatch()
endfunction
endlibrary
//$ noimport
library CustomRaceObserverUI requires /*
--------------------------
*/ CustomRaceCore, /*
--------------------------
----------------------
*/ CustomRaceUI, /*
----------------------
------------------------------
*/ CustomRacePSelection, /*
------------------------------
--------------
*/ Init, /*
--------------
------------------------------
*/ optional FrameLoader /*
------------------------------
- By Tasyen
- You can find it in most of Tasyen's UI resources in the Spells section.
------------------
*/ GameStatus /*
------------------
- By TriggerHappy
- link: https://www.hiveworkshop.com/threads/gamestatus-replay-detection.293176/
-----------------------------------------------------
|
| CustomRaceObserverUI
|
|-----------------------------------------------------
|
| A library that handles displaying the list of players
| who have yet to select a faction. Hidden for actual
| players. Can be seen by observers and in replays.
|
-----------------------------------------------------
*/
globals
private player localPlayer = null
private boolean repVarAssigned = false
private boolean isReplay = false
endglobals
// This only applies to players. Observers will always see the
// faction choice.
private constant function DisplayPlayerFactionChoice takes nothing returns boolean
return false
endfunction
private constant function GetObserverFrameHeight takes nothing returns real
return 0.28
endfunction
private constant function GetObserverFrameWidth takes nothing returns real
return 0.28
endfunction
private constant function GetObserverFrameCenterX takes nothing returns real
return 0.40
endfunction
private constant function GetObserverFrameCenterY takes nothing returns real
return 0.35
endfunction
private constant function GetContainerWidthOffset takes nothing returns real
return 0.06
endfunction
private constant function GetContainerHeightOffset takes nothing returns real
return 0.10
endfunction
private constant function GetContainerFramePoint takes nothing returns framepointtype
return FRAMEPOINT_BOTTOM
endfunction
private constant function GetContainerOffsetX takes nothing returns real
return 0.00
endfunction
private constant function GetContainerOffsetY takes nothing returns real
return 0.01
endfunction
private constant function GetPlayerTextGuideHeight takes nothing returns real
return 0.03
endfunction
private constant function GetPlayerTextOffsetX takes nothing returns real
return 0.00
endfunction
private constant function GetPlayerTextOffsetY takes nothing returns real
return -0.0075
endfunction
private constant function GetPlayerTextGuidePlayerNameOffsetX takes nothing returns real
return 0.04
endfunction
private constant function GetPlayerTextGuidePlayerSelectionOffsetX takes nothing returns real
return 0.08
endfunction
private constant function GetSliderWidth takes nothing returns real
return 0.012
endfunction
private constant function GetSliderOffsetX takes nothing returns real
return -0.006
endfunction
private constant function GetSliderOffsetY takes nothing returns real
return 0.0
endfunction
private constant function GetPlayerFrameCount takes nothing returns integer
return 8
endfunction
private constant function GetPlayerFrameWidthOffset takes nothing returns real
return 0.006
endfunction
private constant function GetPlayerFrameOffsetX takes nothing returns real
return 0.003
endfunction
private constant function GetPlayerFrameOffsetY takes nothing returns real
return 0.0
endfunction
private function GetFrameIndex takes framehandle whichFrame returns integer
return ModuloInteger(GetHandleId(whichFrame) - 0x1000000, 0x8000)
endfunction
struct CustomRaceObserverUI extends array
static integer maxValue = 1
readonly static integer array basePlayerIndex
readonly static framehandle main = null
readonly static framehandle playerContainer = null
readonly static framehandle playerTextGuide = null
readonly static framehandle playerPanelSlider = null
readonly static framehandle array playerTextParams
readonly static framehandle array playerFrame
readonly static framehandle array playerFrameBG
readonly static framehandle array playerFrameHighlight
readonly static framehandle array playerFrameName
readonly static framehandle array playerFrameFaction
private static integer array playerFrameID
private static method initMainFrames takes nothing returns nothing
set main = BlzCreateFrameByType("BACKDROP", "CustomRaceObserverMainFrame", /*
*/ BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), /*
*/ "EscMenuButtonBackdropTemplate", 0)
call BlzFrameSetSize(main, GetObserverFrameWidth(), GetObserverFrameHeight())
call BlzFrameSetAbsPoint(main, FRAMEPOINT_CENTER, GetObserverFrameCenterX(), /*
*/ GetObserverFrameCenterY())
set playerContainer = BlzCreateFrameByType("BACKDROP", "CustomRaceObserverContainer", /*
*/ main, "EscMenuControlBackdropTemplate", 0)
call BlzFrameSetSize(playerContainer, BlzFrameGetWidth(main) - GetContainerWidthOffset() / 2.0, /*
*/ BlzFrameGetWidth(main) - GetContainerHeightOffset())
call BlzFrameSetPoint(playerContainer, GetContainerFramePoint(), main, FRAMEPOINT_BOTTOM, /*
*/ GetContainerOffsetX(), GetContainerOffsetY())
set playerTextGuide = BlzCreateFrameByType("BACKDROP", "CustomRaceObserverTextGuide", /*
*/ main, "EscMenuControlBackdropTemplate", 0)
call BlzFrameSetSize(playerTextGuide, BlzFrameGetWidth(playerContainer), /*
*/ GetPlayerTextGuideHeight())
call BlzFrameSetPoint(playerTextGuide, FRAMEPOINT_BOTTOM, playerContainer, /*
*/ FRAMEPOINT_TOP, GetPlayerTextOffsetX(), GetPlayerTextOffsetY())
set playerPanelSlider = BlzCreateFrameByType("SLIDER", "CustomRaceObserverPlayerPanelSlider", /*
*/ playerContainer, "EscMenuSliderTemplate", 0)
call BlzFrameSetPoint(playerPanelSlider, FRAMEPOINT_LEFT, playerContainer, FRAMEPOINT_RIGHT, /*
*/ GetSliderOffsetX(), GetSliderOffsetY())
call BlzFrameSetSize(playerPanelSlider, GetSliderWidth(), BlzFrameGetHeight(playerContainer))
call BlzFrameSetMinMaxValue(playerPanelSlider, 0.0, 1.0)
call BlzFrameSetValue(playerPanelSlider, 1.0)
set maxValue = 1
//call BlzFrameSetVisible(playerPanelSlider, false)
endmethod
private static method initChildFrames takes nothing returns nothing
local integer i = 1
local real height = BlzFrameGetHeight(playerContainer) / I2R(GetPlayerFrameCount())
local real guideWidth = 0.0
// Create player text parameters
set playerTextParams[1] = BlzCreateFrameByType("TEXT", "CustomRaceObserverTextGuidePlayerName", /*
*/ playerTextGuide, "", 0)
set playerTextParams[2] = BlzCreateFrameByType("TEXT", "CustomRaceObserverTextGuidePlayerSelection", /*
*/ playerTextGuide, "", 0)
set guideWidth = GetPlayerTextGuidePlayerSelectionOffsetX()
call BlzFrameSetSize(playerTextParams[1], guideWidth, BlzFrameGetHeight(playerTextGuide))
set guideWidth = BlzFrameGetWidth(playerTextGuide) - /*
*/ GetPlayerTextGuidePlayerNameOffsetX() - /*
*/ GetPlayerTextGuidePlayerSelectionOffsetX()
call BlzFrameSetSize(playerTextParams[2], guideWidth, BlzFrameGetHeight(playerTextGuide))
call BlzFrameSetPoint(playerTextParams[1], FRAMEPOINT_LEFT, playerTextGuide, FRAMEPOINT_LEFT, /*
*/ GetPlayerTextGuidePlayerNameOffsetX(), 0.0)
call BlzFrameSetPoint(playerTextParams[2], FRAMEPOINT_LEFT, playerTextParams[1], FRAMEPOINT_LEFT, /*
*/ GetPlayerTextGuidePlayerSelectionOffsetX(), 0.0)
call BlzFrameSetText(playerTextParams[1], "|cffffcc00Player:|r")
call BlzFrameSetText(playerTextParams[2], "|cffffcc00Current Faction:|r")
call BlzFrameSetTextAlignment(playerTextParams[1], TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_LEFT)
call BlzFrameSetTextAlignment(playerTextParams[2], TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_LEFT)
set guideWidth = BlzFrameGetWidth(playerContainer) - GetPlayerFrameWidthOffset()
loop
exitwhen i > GetPlayerFrameCount()
set playerFrame[i] = BlzCreateFrameByType("BUTTON", "CustomRaceObserverPlayerMainPanel", /*
*/ playerContainer, "", i)
set playerFrameBG[i] = BlzCreateFrameByType("BACKDROP", "CustomRaceObserverPlayerMainPanelBG", /*
*/ playerFrame[i], "CustomRaceSimpleBackdropTemplate", /*
*/ i)
set playerFrameID[GetFrameIndex(playerFrame[i])] = i
call BlzFrameSetSize(playerFrame[i], guideWidth, height)
call BlzFrameSetAllPoints(playerFrameBG[i], playerFrame[i])
if i == 1 then
call BlzFrameSetPoint(playerFrame[i], FRAMEPOINT_TOPLEFT, playerContainer, /*
*/ FRAMEPOINT_TOPLEFT, GetPlayerFrameOffsetX(), /*
*/ GetPlayerFrameOffsetY())
else
call BlzFrameSetPoint(playerFrame[i], FRAMEPOINT_TOP, playerFrame[i - 1], /*
*/ FRAMEPOINT_BOTTOM, 0.0, 0.0)
endif
set playerFrameHighlight[i] = BlzCreateFrameByType("HIGHLIGHT", "CustomRaceObserverPlayerMainPanelHighlight", /*
*/ playerFrame[i], "EscMenuButtonMouseOverHighlightTemplate", /*
*/ i)
call BlzFrameSetAllPoints(playerFrameHighlight[i], playerFrame[i])
call BlzFrameSetVisible(playerFrameHighlight[i], false)
set playerFrameName[i] = BlzCreateFrameByType("TEXT", "CustomRaceObserverPlayerPanelPlayerName", /*
*/ playerFrameBG[i], "", i)
set playerFrameFaction[i] = BlzCreateFrameByType("TEXT", "CustomRaceObserverPlayerPanelFaction", /*
*/ playerFrameBG[i], "", i)
call BlzFrameSetSize(playerFrameName[i], BlzFrameGetWidth(playerTextParams[1]), /*
*/ BlzFrameGetHeight(playerTextParams[1]))
call BlzFrameSetSize(playerFrameFaction[i], BlzFrameGetWidth(playerTextParams[2]), /*
*/ BlzFrameGetHeight(playerTextParams[2]))
call BlzFrameSetPoint(playerFrameName[i], FRAMEPOINT_LEFT, playerFrameBG[i], FRAMEPOINT_LEFT, /*
*/ GetPlayerTextGuidePlayerNameOffsetX(), 0.0)
call BlzFrameSetPoint(playerFrameFaction[i], FRAMEPOINT_LEFT, playerFrameName[i], FRAMEPOINT_LEFT, /*
*/ GetPlayerTextGuidePlayerSelectionOffsetX(), 0.0)
call BlzFrameSetTextAlignment(playerFrameName[i], TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_LEFT)
call BlzFrameSetTextAlignment(playerFrameFaction[i], TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_LEFT)
set i = i + 1
endloop
endmethod
private static method onPlayerPanelEnter takes nothing returns nothing
local player trigPlayer = GetTriggerPlayer()
local integer id = GetFrameIndex(BlzGetTriggerFrame())
local integer i = playerFrameID[id]
if localPlayer == trigPlayer then
call BlzFrameSetVisible(playerFrameHighlight[i], true)
endif
endmethod
private static method onPlayerPanelLeave takes nothing returns nothing
local player trigPlayer = GetTriggerPlayer()
local integer id = GetFrameIndex(BlzGetTriggerFrame())
local integer i = playerFrameID[id]
if localPlayer == trigPlayer then
call BlzFrameSetVisible(playerFrameHighlight[i], false)
endif
endmethod
private static method onSliderValueChange takes nothing returns nothing
local player trigPlayer = GetTriggerPlayer()
local integer id = GetPlayerId(trigPlayer)
local integer value = R2I(BlzGetTriggerFrameValue() + 0.01)
if CustomRacePSelection.choicedPlayerSize <= GetPlayerFrameCount() then
set basePlayerIndex[id] = 0
return
endif
set basePlayerIndex[id] = CustomRacePSelection.choicedPlayerSize - /*
*/ (GetPlayerFrameCount() + value)
endmethod
private static method addPlayerFrameEvents takes nothing returns nothing
local trigger enterTrig = CreateTrigger()
local trigger leaveTrig = CreateTrigger()
local integer i = 1
loop
exitwhen i > GetPlayerFrameCount()
call BlzTriggerRegisterFrameEvent(enterTrig, playerFrame[i], FRAMEEVENT_MOUSE_ENTER)
call BlzTriggerRegisterFrameEvent(leaveTrig, playerFrame[i], FRAMEEVENT_MOUSE_LEAVE)
set i = i + 1
endloop
call TriggerAddAction(enterTrig, function thistype.onPlayerPanelEnter)
call TriggerAddAction(leaveTrig, function thistype.onPlayerPanelLeave)
endmethod
private static method init takes nothing returns nothing
set localPlayer = GetLocalPlayer()
call thistype.initMainFrames()
call thistype.initChildFrames()
call thistype.addPlayerFrameEvents()
// Hide the frame upon at its' release state.
call BlzFrameSetVisible(main, false)
static if LIBRARY_FrameLoader then
call FrameLoaderAdd(function thistype.init)
endif
endmethod
implement Init
endstruct
private function CanPlayerSeeUI takes player whichPlayer returns boolean
local boolean result = CustomRacePSelection.hasUnchoicedPlayer(whichPlayer) or IsPlayerObserver(whichPlayer)
static if LIBRARY_GameStatus then
set result = (GetGameStatus() == GAME_STATUS_REPLAY) or result
endif
return result
endfunction
public function RenderFrame takes nothing returns nothing
local string factionText = "No Faction Selected"
local integer i = 1
local integer id = GetPlayerId(localPlayer)
local integer oldBase = CustomRaceObserverUI.maxValue
local real preValue = BlzFrameGetValue(CustomRaceObserverUI.playerPanelSlider)
local CustomRacePSelection obj = 0
local CustomRace faction = 0
local player whichPlayer
// This is guaranteed to be a synchronous action
if CustomRacePSelection.choicedPlayerSize > GetPlayerFrameCount() then
set CustomRaceObserverUI.maxValue = R2I(CustomRacePSelection.choicedPlayerSize - GetPlayerFrameCount() /*
*/ + 0.01)
else
set CustomRaceObserverUI.maxValue = 1
endif
if CustomRaceObserverUI.maxValue != oldBase then
call BlzFrameSetMinMaxValue(CustomRaceObserverUI.playerPanelSlider, 0, /*
*/ CustomRaceObserverUI.maxValue)
call BlzFrameSetValue(CustomRaceObserverUI.playerPanelSlider, preValue + /*
*/ R2I(oldBase - CustomRaceObserverUI.maxValue + 0.01))
endif
loop
exitwhen (i > GetPlayerFrameCount())
if (CustomRaceObserverUI.basePlayerIndex[id] + i > CustomRacePSelection.choicedPlayerSize) then
// Do not display anymore
call BlzFrameSetVisible(CustomRaceObserverUI.playerFrame[i], false)
else
set whichPlayer = CustomRacePSelection.choicedPlayers[CustomRaceObserverUI.basePlayerIndex[id] + i]
set obj = CRPSelection[whichPlayer]
if obj.faction != 0 then
set faction = CustomRace.getRaceFaction(GetPlayerRace(whichPlayer), obj.baseChoice + obj.faction)
set factionText = faction.name
endif
call BlzFrameSetVisible(CustomRaceObserverUI.playerFrame[i], true)
call BlzFrameSetText(CustomRaceObserverUI.playerFrameName[i], /*
*/ GetPlayerName(whichPlayer))
call BlzFrameSetText(CustomRaceObserverUI.playerFrameFaction[i], /*
*/ factionText)
if (not DisplayPlayerFactionChoice()) and /*
*/ (CustomRacePSelection.hasUnchoicedPlayer(localPlayer)) then
call BlzFrameSetVisible(CustomRaceObserverUI.playerFrameFaction[i], false)
else
call BlzFrameSetVisible(CustomRaceObserverUI.playerFrameFaction[i], true)
endif
endif
set i = i + 1
endloop
call BlzFrameSetVisible(CustomRaceObserverUI.main, CanPlayerSeeUI(localPlayer))
endfunction
public function UnrenderFrame takes nothing returns nothing
call BlzFrameSetVisible(CustomRaceObserverUI.main, false)
endfunction
endlibrary
//$ noimport
library CustomRaceUserUI requires /*
--------------------------
*/ CustomRaceCore, /*
--------------------------
--------------------------
*/ CustomRaceUI, /*
--------------------------
------------------------------
*/ CustomRacePSelection, /*
------------------------------
----------------------------------
*/ CustomRaceMatchConditions, /*
----------------------------------
----------------------------------
*/ CustomRaceMatch, /*
----------------------------------
----------------------------------
*/ CustomRaceObserverUI, /*
----------------------------------
----------------------
*/ Init, /*
----------------------
------------------------------
*/ GameStatus /*
------------------------------
------------------------------
*/ optional FrameLoader /*
------------------------------
--------------------------------------------------------------
|
| Custom Race User UI
|
|--------------------------------------------------------------
|
| A library that handles event processing of the generated
| framehandles, and the selection of desired factions and
| whatnot.
|
| This library outsources the actual creation of most of the
| frame handles to the Custom Race UI library.
|
--------------------------------------------------------------
*/
globals
// Discoveries made by Luashine on the tick rate of the game suggest
// that the game updates at a frequency of 50 Hz. Further insights on
// tick rate and all related stuff can be found here:
// https://www.hiveworkshop.com/threads/high-speed-triggers-or-a-slow-triggerregistertimereventperiodic.341024/
private constant real INTERVAL = 1.0 / 50.0
private constant real WAIT_DURATION = 30.0
private constant real EASE_IN = 1.75 // 0.5
private constant real EASE_OUT = 0.75 // 0.5
private constant real FINALIZE_DELAY = 0.50 // 0.5
private integer WAIT_MAX_TICKS = R2I(WAIT_DURATION / INTERVAL + 0.01)
private integer EASE_IN_TICKS = R2I(EASE_IN / INTERVAL + 0.01)
private integer EASE_OUT_TICKS = R2I(EASE_OUT / INTERVAL + 0.01)
private constant integer MODE_BAR_UPDATE = 1
private constant integer MODE_EASE_IN = 2
private constant integer MODE_EASE_OUT = 4
private constant real FRAME_START_DELAY = 0.25
private constant real DECAY_RATE = 8.0
private constant real OSCILLATE_RATE = 2.0
private constant real DELAY = 0.15
private constant real E = 2.7182818
endglobals
private constant function GetDefaultTechtreeIconTexture takes nothing returns string
return "UI\\Widgets\\EscMenu\\Human\\editbox-background.blp"
endfunction
// ============================================================================= //
// Originally, the ease in and out functions were going to have different
// responses. However, I liked the final ease in response so much that
// I used it all throughout instead.
// ============================================================================= //
private struct DecayResponse extends array
private static constant integer MAX_STEPS = 1000
private static real STEP_SIZE = 1.0 / I2R(MAX_STEPS)
readonly static real array value
private static method init takes nothing returns nothing
local integer i = 1
local real a = STEP_SIZE
local real mult = Pow(E, -a*DECAY_RATE)
local real curMult = mult
set value[0] = 0.0
loop
exitwhen i > MAX_STEPS
set value[i] = 1 - curMult*Cos(2*bj_PI*OSCILLATE_RATE*a)
set curMult = curMult*mult
set i = i + 1
set a = a + STEP_SIZE
endloop
set value[MAX_STEPS] = 1.0
endmethod
static method getValue takes real x returns real
local integer index
local real modulo
if x <= 0.0 then
return 0.0
elseif x >= 1.0 then
return 1.0
endif
set index = R2I(x / STEP_SIZE)
set modulo = ModuloReal(x, STEP_SIZE) / STEP_SIZE
return value[index]*(1 - modulo) + value[index + 1]*(modulo)
endmethod
implement Init
endstruct
private function StepResponse takes real x returns real
if x > 0 then
return 1.0
endif
return 0.0
endfunction
private function BarUpdateResponse takes real x returns real
return 1.0 - x
endfunction
private function EaseInResponse takes real x returns real
set x = x - 0.25
return DecayResponse.getValue(x)
endfunction
private function EaseOutResponse takes real x returns real
return (x*(x*(x*(x*(0.20*x-0.55)+0.47)-0.1))) / 0.02
endfunction
private function EaseInPosResponse takes real x returns real
return EaseInResponse(x)
endfunction
private function EaseOutPosResponse takes real x returns real
return EaseOutResponse(x)
endfunction
private constant function GetMainFrameStartCenterX takes nothing returns real
return CustomRaceUI_GetMainFrameCenterX()
endfunction
private constant function GetMainFrameStartCenterY takes nothing returns real
return 0.30
endfunction
private struct FrameInterpolation extends array
readonly static timer timer = CreateTimer()
readonly static player localPlayer = null
readonly static boolean isReplay = false
private static constant integer MAX_POWER_INDEX = 3
private static integer instanceCount = 0
private static integer array powersOf2
private static integer array tickMap
private static thistype array activeInstances
static integer array currentTicks
static integer array maxTicks
readonly integer mode
readonly integer activeTicks
private static method getPowerIndex takes integer mode returns integer
if mode == MODE_EASE_OUT then
return 3
elseif mode == MODE_EASE_IN then
return 2
elseif mode == MODE_BAR_UPDATE then
return 1
endif
return 0
endmethod
private method setTick takes integer mode, integer newval returns nothing
set mode = thistype.getPowerIndex(mode)
set currentTicks[MAX_POWER_INDEX*integer(this) + mode] = newval
endmethod
private method getTick takes integer mode returns integer
set mode = thistype.getPowerIndex(mode)
return currentTicks[MAX_POWER_INDEX*integer(this) + mode]
endmethod
private method getMaxTick takes integer mode returns integer
set mode = thistype.getPowerIndex(mode)
return maxTicks[MAX_POWER_INDEX*integer(this) + mode]
endmethod
private static method onUpdate takes nothing returns nothing
local integer i = 1
local thistype this
local real ratio
local real posRatio
local real cx
local real cy
local player whichPlayer
loop
exitwhen i > instanceCount
set this = activeInstances[i]
set whichPlayer = Player(integer(this))
if BlzBitAnd(this.mode, MODE_BAR_UPDATE) != 0 then
call this.setTick(MODE_BAR_UPDATE, this.getTick(MODE_BAR_UPDATE) + 1)
set ratio = I2R(this.getTick(MODE_BAR_UPDATE)) / /*
*/ I2R(this.getMaxTick(MODE_BAR_UPDATE))
set ratio = BarUpdateResponse(ratio)
if this.getTick(MODE_BAR_UPDATE) >= this.getMaxTick(MODE_BAR_UPDATE) then
set this.mode = this.mode - MODE_BAR_UPDATE
endif
if thistype.localPlayer == whichPlayer then
call CustomRaceInterface.setBarProgress(ratio)
endif
endif
if BlzBitAnd(this.mode, MODE_EASE_IN) != 0 then
if (thistype.localPlayer == whichPlayer) and /*
*/ (not CustomRaceInterface.isMainVisible()) then
if (not isReplay) then
call CustomRaceInterface.setMainVisible(true)
endif
endif
call this.setTick(MODE_EASE_IN, this.getTick(MODE_EASE_IN) + 1)
set ratio = I2R(this.getTick(MODE_EASE_IN)) / /*
*/ I2R(this.getMaxTick(MODE_EASE_IN))
set posRatio = EaseInPosResponse(ratio)
set ratio = EaseInResponse(ratio)
set cx = GetMainFrameStartCenterX()*(1 - posRatio) + /*
*/ CustomRaceUI_GetMainFrameCenterX()*posRatio
set cy = GetMainFrameStartCenterY()*(1 - posRatio) + /*
*/ CustomRaceUI_GetMainFrameCenterY()*posRatio
if thistype.localPlayer == whichPlayer then
call CustomRaceInterface.setMainAlpha(ratio)
call CustomRaceInterface.setMainPos(cx, cy)
endif
if this.getTick(MODE_EASE_IN) >= this.getMaxTick(MODE_EASE_IN) then
set this.mode = this.mode - MODE_EASE_IN
endif
elseif BlzBitAnd(this.mode, MODE_EASE_OUT) != 0 then
call this.setTick(MODE_EASE_OUT, this.getTick(MODE_EASE_OUT) + 1)
set ratio = I2R(this.getTick(MODE_EASE_OUT)) / /*
*/ I2R(this.getMaxTick(MODE_EASE_OUT))
set posRatio = EaseOutPosResponse(ratio)
set ratio = 1.0 - RMinBJ(EaseOutResponse(ratio), 1.0)
set cx = CustomRaceUI_GetMainFrameCenterX()*(1 - posRatio) + /*
*/ GetMainFrameStartCenterX()*posRatio
set cy = CustomRaceUI_GetMainFrameCenterY()*(1 - posRatio) + /*
*/ GetMainFrameStartCenterY()*posRatio
if thistype.localPlayer == whichPlayer then
call CustomRaceInterface.setMainAlpha(ratio)
call CustomRaceInterface.setMainPos(cx, cy)
endif
if this.getTick(MODE_EASE_OUT) >= this.getMaxTick(MODE_EASE_OUT) then
set this.mode = this.mode - MODE_EASE_OUT
if (thistype.localPlayer == whichPlayer) then
if (not isReplay) then
call CustomRaceInterface.setMainVisible(false)
endif
call CustomRaceInterface.setMainAlpha(1.0)
endif
endif
endif
// Remove this instance from the instance list
if this.mode == 0 then
set activeInstances[i] = activeInstances[instanceCount]
set instanceCount = instanceCount - 1
set i = i - 1
endif
set i = i + 1
endloop
if instanceCount <= 0 then
call PauseTimer(timer)
endif
endmethod
private static method startTimer takes nothing returns nothing
if instanceCount == 1 then
call TimerStart(timer, INTERVAL, true, function thistype.onUpdate)
endif
endmethod
private method setCurrentTicks takes integer mode returns nothing
set mode = thistype.getPowerIndex(mode)
set currentTicks[MAX_POWER_INDEX*integer(this) + mode] = 0
set maxTicks[MAX_POWER_INDEX*integer(this) + mode] = tickMap[mode]
endmethod
method isTransitioning takes integer mode returns boolean
return BlzBitAnd(this.mode, mode) != 0
endmethod
method stop takes integer mode returns boolean
if not this.isTransitioning(mode) then
return false
endif
call this.setTick(mode, this.getTick(mode) - 1)
set this.mode = this.mode - mode
return true
endmethod
method request takes integer mode returns boolean
if BlzBitAnd(this.mode, mode) != 0 then
return false
endif
if this.mode == 0 then
set instanceCount = instanceCount + 1
set activeInstances[instanceCount] = this
call thistype.startTimer()
endif
set this.mode = this.mode + mode
call this.setCurrentTicks(mode)
return true
endmethod
static method [] takes player whichPlayer returns thistype
return thistype(GetPlayerId(whichPlayer))
endmethod
private static method init takes nothing returns nothing
set powersOf2[1] = 1
set powersOf2[2] = 2
set powersOf2[3] = 4
set tickMap[1] = WAIT_MAX_TICKS
set tickMap[2] = EASE_IN_TICKS
set tickMap[3] = EASE_OUT_TICKS
set localPlayer = GetLocalPlayer()
set isReplay = GetGameStatus() == GAME_STATUS_REPLAY
endmethod
implement Init
endstruct
// ========================================================================== //
// UI Drawing API //
// ========================================================================== //
private function GetObjectIdDescription takes integer objectID returns string
return BlzGetAbilityExtendedTooltip(objectID, 0)
endfunction
private function GetObjectIdIcon takes integer objectID returns string
return BlzGetAbilityIcon(objectID)
endfunction
private function GetObjectIdFromChunk takes integer i, integer j, integer baseTechID, CustomRace faction /*
*/ returns integer
if (i == 1) then
return faction.getUnit(baseTechID + j)
elseif (i == 2) then
return faction.getStructure(baseTechID + j)
elseif (i == 3) then
return faction.getHero(baseTechID + j)
endif
return 0
endfunction
private function GetTechtreeArrowMaxValue takes integer i, CustomRace faction returns integer
if (i == 1) then
return faction.getUnitMaxIndex()
elseif (i == 2) then
return faction.getStructureMaxIndex()
elseif (i == 3) then
return faction.getHeroMaxIndex()
endif
return 0
endfunction
private function CheckTechtreeChunkForDraw takes integer i, CustomRace faction returns boolean
return GetTechtreeArrowMaxValue(i, faction) > 0
endfunction
private function CheckTechtreeIconForDraw takes integer i, integer j, CustomRace faction, /*
*/ CustomRacePSelection obj returns boolean
// Draw units?
local integer max = GetTechtreeArrowMaxValue(i, faction)
return obj.getBaseTechID(i) + j <= max
endfunction
private function DrawTechtreeIcon takes player whichPlayer, integer i, integer j, integer baseTechID, /*
*/ CustomRace faction returns nothing
local integer objectID = GetObjectIdFromChunk(i, j, baseTechID, faction)
local integer baseIndex = (i-1)*CustomRaceInterface.iconsPerChunk
local string desc = ""
/*
if (i == 1) then
set objectID = faction.getUnit(baseTechID + j)
elseif (i == 2) then
set objectID = faction.getStructure(baseTechID + j)
endif
*/
set desc = GetObjectIdIcon(objectID)
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTechtreeIconVisible(baseIndex + j, true)
call CustomRaceInterface.setTechtreeIconDisplayByID(baseIndex + j, desc)
endif
endfunction
private function DrawUIFromPlayerData takes player whichPlayer, CustomRacePSelection obj returns nothing
local integer i = 1
local integer j = 0
local integer objectID = 0
local integer baseIndex = 0
local race pRace = GetPlayerRace(whichPlayer)
local CustomRace faction = 0
// Draw the choice buttons first
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setChoiceArrowVisible(true, obj.baseChoice != 0)
call CustomRaceInterface.setSliderVisible(CustomRace.getRaceFactionCount(pRace) > CustomRaceUI_GetMaxDisplayChoices())
call BlzFrameSetEnable(CustomRaceInterface.confirmFrame, obj.faction != 0)
endif
loop
exitwhen i > CustomRaceUI_GetMaxDisplayChoices()
if obj.baseChoice + i > CustomRace.getRaceFactionCount(pRace) then
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setChoiceName(i, "")
call CustomRaceInterface.setChoiceButtonVisible(i, false)
endif
else
if (FrameInterpolation.localPlayer == whichPlayer) then
call CustomRaceInterface.setChoiceArrowVisible(false, /*
*/ obj.baseChoice + i < CustomRace.getRaceFactionCount(pRace))
endif
set faction = CustomRace.getRaceFaction(pRace, obj.baseChoice + i)
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setChoiceName(i, faction.name)
call CustomRaceInterface.setChoiceButtonVisible(i, true)
endif
endif
set i = i + 1
endloop
// If a faction was selected, show the name, display
// and race description, and continue with techtree
// visuals. Otherwise, hide techtree visuals.
if obj.focusFaction != 0 then
set faction = CustomRace.getRaceFaction(pRace, obj.baseChoice + obj.focusFaction)
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setFactionNameVisible(true)
call CustomRaceInterface.setFactionName(faction.name)
call CustomRaceInterface.setDescription(faction.desc)
call CustomRaceInterface.setFactionDisplay(faction.racePic)
endif
else
set faction = 0
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setFactionNameVisible(false)
call CustomRaceInterface.setFactionName("")
call CustomRaceInterface.setDescription("")
call CustomRaceInterface.setFactionDisplay("")
endif
endif
// Since no faction in particular was selected, terminate
// the drawing process here by hiding the techtree chunks.
if (faction == 0) then
set i = 1
loop
exitwhen i > CustomRaceUI_GetTechtreeChunkCount()
call obj.setBaseTechID(i, 0)
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTechtreeChunkVisible(i, false)
endif
set i = i + 1
endloop
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.techtree = 0
set obj.focusTechtreeStack = 0
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTooltipVisible(false)
endif
return
endif
// Draw the techtree chunks if data exists
set i = 1
loop
exitwhen i > CustomRaceUI_GetTechtreeChunkCount()
loop
if CheckTechtreeChunkForDraw(i, faction) then
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTechtreeChunkVisible(i, true)
endif
else
/*
if obj.focusTechtree == i then
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.techtree = 0
set obj.focusTechtreeStack = 0
call obj.setBaseTechID(i, 0)
endif
*/
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTechtreeChunkVisible(i, false)
endif
exitwhen true
endif
set j = 1
set baseIndex = (i-1)*CustomRaceInterface.iconsPerChunk
// Draw the choice buttons first
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTechtreeArrowVisible(i, true, obj.getBaseTechID(i) != 0)
endif
loop
exitwhen j > CustomRaceInterface.iconsPerChunk
if CheckTechtreeIconForDraw(i, j, faction, obj) then
call DrawTechtreeIcon(whichPlayer, i, j, obj.getBaseTechID(i), faction)
if (FrameInterpolation.localPlayer == whichPlayer) then
call CustomRaceInterface.setTechtreeArrowVisible(i, false, /*
*/ (obj.getBaseTechID(i) + j) < /*
*/ (GetTechtreeArrowMaxValue(i, faction)))
endif
else
if (FrameInterpolation.localPlayer == whichPlayer) then
call CustomRaceInterface.setTechtreeIconVisible(baseIndex + j, false)
endif
endif
set j = j + 1
endloop
exitwhen true
endloop
set i = i + 1
endloop
// If a techtree icon was selected, show the name, display
// and race description.
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTooltipVisible(obj.focusTechID != 0)
call CustomRaceInterface.setTooltipName("")
call CustomRaceInterface.setTooltipDesc("")
endif
if (obj.focusTechID != 0) then
set objectID = GetObjectIdFromChunk(obj.focusTechtree, obj.focusTechID, /*
*/ obj.getBaseTechID(obj.focusTechtree), faction)
if FrameInterpolation.localPlayer == whichPlayer then
call CustomRaceInterface.setTooltipName(GetObjectName(objectID))
call CustomRaceInterface.setTooltipDesc(GetObjectIdDescription(objectID))
endif
endif
endfunction
// ========================================================================== //
// Sound Generating Functions //
// ========================================================================== //
globals
private sound tempSound = null
endglobals
private function GenerateClunkDownSound takes nothing returns sound
set tempSound = CreateSound("Sound\\Interface\\LeftAndRightGlueScreenPopDown.wav", false, false, false, 10, 10, "DefaultEAXON")
call SetSoundParamsFromLabel(tempSound, "BothGlueScreenPopDown")
call SetSoundDuration(tempSound, 2246)
call SetSoundVolume(tempSound, 127)
return tempSound
endfunction
private function GenerateClunkUpSound takes nothing returns sound
set tempSound = CreateSound("Sound\\Interface\\LeftAndRightGlueScreenPopUp.wav", false, false, false, 10, 10, "DefaultEAXON")
call SetSoundParamsFromLabel(tempSound, "BothGlueScreenPopUp")
call SetSoundDuration(tempSound, 1953)
call SetSoundVolume(tempSound, 127)
return tempSound
endfunction
private function GenerateClickSound takes nothing returns sound
set tempSound = CreateSound("Sound\\Interface\\MouseClick1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(tempSound, "InterfaceClick")
call SetSoundDuration(tempSound, 239)
return tempSound
endfunction
private function GenerateWarningSound takes nothing returns sound
set tempSound = CreateSound("Sound\\Interface\\CreepAggroWhat1.wav", false, false, false, 10, 10, "DefaultEAXON")
call SetSoundParamsFromLabel(tempSound, "CreepAggro")
call SetSoundDuration(tempSound, 1236)
return tempSound
endfunction
private function PlaySoundForPlayer takes sound snd, player whichPlayer returns nothing
if FrameInterpolation.localPlayer == whichPlayer then
call SetSoundVolume(snd, 127)
else
call SetSoundVolume(snd, 0)
endif
call StartSound(snd)
call KillSoundWhenDone(snd)
endfunction
// ========================================================================== //
// ========================================================================== //
globals
private code onDefaultFinalize = null
private timer finalizer = null
endglobals
private function IsFrameUseable takes player whichPlayer returns boolean
return (not FrameInterpolation[whichPlayer].isTransitioning(MODE_EASE_IN)) and /*
*/ (not FrameInterpolation[whichPlayer].isTransitioning(MODE_EASE_OUT))
endfunction
private function HideCustomFrame takes player whichPlayer returns nothing
if FrameInterpolation[whichPlayer].isTransitioning(MODE_EASE_IN) then
return
endif
call PlaySoundForPlayer(GenerateClunkUpSound(), whichPlayer)
call FrameInterpolation[whichPlayer].request(MODE_EASE_OUT)
endfunction
private function ShowCustomFrame takes player whichPlayer returns nothing
if FrameInterpolation[whichPlayer].isTransitioning(MODE_EASE_OUT) then
return
endif
call PlaySoundForPlayer(GenerateClunkDownSound(), whichPlayer)
call FrameInterpolation[whichPlayer].request(MODE_EASE_IN)
endfunction
// ========================================================================== //
// ========================================================================== //
private function HideCustomFrameEnum takes nothing returns nothing
call HideCustomFrame(GetEnumPlayer())
endfunction
private function HideCustomFrameAll takes nothing returns nothing
call ForForce(CustomRaceForce.activePlayers, function HideCustomFrameEnum)
endfunction
private function ShowCustomFrameEnum takes nothing returns nothing
if CustomRacePSelection.hasChoicedPlayer(GetEnumPlayer()) then
call ShowCustomFrame(GetEnumPlayer())
endif
endfunction
private function ShowCustomFrameAll takes nothing returns nothing
call ForForce(CustomRaceForce.activePlayers, function ShowCustomFrameEnum)
endfunction
// ========================================================================== //
// ========================================================================== //
private function OnBarTimerStart takes nothing returns nothing
local integer i = 1
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
// Apply timer only when in a multiplayer setting
// or when the following flag is true.
if (not CustomRaceMatch_APPLY_TIMER_IN_SINGLE_PLAYER) and /*
*/ (CustomRacePSelection.isSinglePlayer) then
return
endif
loop
exitwhen i > CustomRacePSelection.choicedPlayerSize
call FrameInterpolation[CustomRacePSelection.choicedPlayers[i]].request(MODE_BAR_UPDATE)
set i = i + 1
endloop
set finalizer = CreateTimer()
call TimerStart(finalizer, WAIT_DURATION, false, onDefaultFinalize)
endfunction
private function OnPrepUI takes nothing returns nothing
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
call TimerStart(CreateTimer(), EASE_IN, false, function OnBarTimerStart)
call ShowCustomFrameAll()
endfunction
private function PrepUI takes nothing returns nothing
local integer i = 1
loop
exitwhen i > CustomRaceUI_GetTechtreeChunkCount()
call CustomRaceInterface.setTechtreeChunkVisible(i, false)
set i = i + 1
endloop
set i = 1
loop
exitwhen i > CustomRaceUI_GetMaxDisplayChoices()
call CustomRaceInterface.setChoiceButtonVisible(i, false)
set i = i + 1
endloop
call CustomRaceInterface.setSliderVisible(false)
call CustomRaceInterface.setFactionNameVisible(false)
call CustomRaceInterface.setFactionDisplay("")
call CustomRaceInterface.setBarProgress(1.00)
call CustomRaceInterface.setTooltipVisible(false)
// No players with a choice in their faction..
if CustomRacePSelection.choicedPlayerSize < 1 then
return
endif
call TimerStart(CreateTimer(), FRAME_START_DELAY, false, function OnPrepUI)
endfunction
// ========================================================================== //
// ========================================================================== //
private struct UIFrameEvents extends array
readonly static trigger abandonTrig = CreateTrigger()
// ========================================================================== //
// Finalization Events //
// ========================================================================== //
static method onFinalizeEnd takes nothing returns nothing
call DisableTrigger(thistype.abandonTrig)
call DestroyTrigger(thistype.abandonTrig)
call CustomRaceMatch_MeleeInitializationFinish()
endmethod
static method finalize takes nothing returns nothing
call TimerStart(CreateTimer(), FINALIZE_DELAY + EASE_OUT, false, /*
*/ function thistype.onFinalizeEnd)
endmethod
static method onFinalize takes nothing returns nothing
local player indexPlayer
local CustomRacePSelection obj
local integer i
loop
exitwhen CustomRacePSelection.choicedPlayerSize < 1
set indexPlayer = CustomRacePSelection.choicedPlayers[CustomRacePSelection.choicedPlayerSize]
set obj = CRPSelection[indexPlayer]
set obj.focusFaction = 0
set obj.faction = 0
set obj.focusFactionStack = 0
set obj.techtree = 0
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.focusTechtreeStack = 0
set i = 1
loop
exitwhen i > CustomRaceUI_GetTechtreeChunkCount()
call obj.setBaseTechID(i, 0)
set i = i + 1
endloop
call DrawUIFromPlayerData(indexPlayer, obj)
set obj.faction = 1
call CustomRacePSelection.removeChoicedPlayer(indexPlayer)
call CustomRacePSelection.addUnchoicedPlayer(indexPlayer)
call HideCustomFrame(indexPlayer)
endloop
call thistype.finalize()
endmethod
static method onExpireFinalize takes nothing returns nothing
local timer whichTimer = GetExpiredTimer()
call PauseTimer(whichTimer)
call DestroyTimer(whichTimer)
set whichTimer = null
call thistype.onFinalize()
endmethod
// ========================================================================== //
// Enter and Leave Events //
// ========================================================================== //
static method onChoiceButtonEnter takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getChoiceButtonID(zabutton)
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
if obj.focusFactionStack < 1 then
set obj.focusFaction = i
endif
set obj.focusFactionStack = obj.focusFactionStack + 1
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onChoiceButtonLeave takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getChoiceButtonID(zabutton)
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
// obj.focusFactionStack can only be equal to 2
// if a choice button was already selected.
if obj.focusFactionStack < 2 then
set obj.focusFaction = 0
endif
set obj.focusFactionStack = obj.focusFactionStack - 1
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onTechtreeIconEnter takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getTechtreeIconID(zabutton)
local integer curChunk = CustomRaceInterface.getChunkFromIndex(i)
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
if obj.focusTechtreeStack < 1 then
set obj.focusTechtree = curChunk
set obj.focusTechID = ModuloInteger(i, CustomRaceInterface.iconsPerChunk)
if obj.focusTechID == 0 then
set obj.focusTechID = CustomRaceInterface.iconsPerChunk
endif
endif
set obj.focusTechtreeStack = obj.focusTechtreeStack + 1
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onTechtreeIconLeave takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getTechtreeIconID(zabutton)
local integer curChunk = CustomRaceInterface.getChunkFromIndex(i)
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
if obj.focusTechtreeStack < 2 then
set obj.focusTechtree = 0
set obj.focusTechID = 0
endif
set obj.focusTechtreeStack = obj.focusTechtreeStack - 1
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
// ========================================================================== //
// Click Events //
// ========================================================================== //
static method onChoiceButtonClick takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getChoiceButtonID(zabutton)
local integer j = 0
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
// obj.focusFactionStack can only be equal to 2
// if a choice button was already selected.
if obj.faction == 0 then
set obj.focusFactionStack = obj.focusFactionStack + 1
set obj.focusFaction = i
set obj.faction = obj.focusFaction
else
set obj.focusFactionStack = obj.focusFactionStack - 1
if FrameInterpolation.localPlayer == trigPlayer then
call BlzFrameSetEnable(CustomRaceInterface.getChoiceButton(obj.focusFaction), false)
call BlzFrameSetEnable(CustomRaceInterface.getChoiceButton(obj.focusFaction), true)
endif
if i != obj.focusFaction then
set obj.focusFactionStack = obj.focusFactionStack + 1
set obj.focusFaction = i
set obj.faction = i
// Update techtree tooltip and icons as well
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.techtree = 0
set obj.focusTechtreeStack = 0
set j = 1
loop
exitwhen j > CustomRaceUI_GetTechtreeChunkCount()
call obj.setBaseTechID(j, 0)
set j = j + 1
endloop
else
set obj.faction = 0
endif
endif
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
call CustomRaceObserverUI_RenderFrame()
endmethod
static method onTechtreeIconClick takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getTechtreeIconID(zabutton)
local integer index = 0
local integer curChunk = CustomRaceInterface.getChunkFromIndex(i)
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
if obj.techtree == 0 then
set obj.focusTechtreeStack = obj.focusTechtreeStack + 1
set obj.focusTechtree = curChunk
set obj.focusTechID = ModuloInteger(i, CustomRaceInterface.iconsPerChunk)
if obj.focusTechID == 0 then
set obj.focusTechID = CustomRaceInterface.iconsPerChunk
endif
set obj.techtree = obj.focusTechID
else
set obj.focusTechtreeStack = obj.focusTechtreeStack - 1
set index = (obj.focusFaction-1)
set index = index*CustomRaceInterface.iconsPerChunk + obj.focusTechID
if FrameInterpolation.localPlayer == trigPlayer then
call BlzFrameSetEnable(CustomRaceInterface.getTechtreeIconRaw(index), false)
call BlzFrameSetEnable(CustomRaceInterface.getTechtreeIconRaw(index), true)
endif
set i = ModuloInteger(i, CustomRaceInterface.iconsPerChunk)
if i == 0 then
set i = CustomRaceInterface.iconsPerChunk
endif
if i != obj.focusTechID then
set obj.focusTechtreeStack = obj.focusTechtreeStack + 1
set obj.focusTechtree = curChunk
set obj.focusTechID = i
set obj.techtree = obj.focusTechID
else
set obj.techtree = 0
endif
endif
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onChoiceArrowClick takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getChoiceArrowID(zabutton)
local player trigPlayer = GetTriggerPlayer()
local integer incr = 1
call PlaySoundForPlayer(GenerateClickSound(), trigPlayer)
if BlzBitAnd(i, 1) == 0 then
set incr = -1
endif
if FrameInterpolation.localPlayer == trigPlayer then
call CustomRaceInterface.setSliderValue(CustomRaceInterface.getSliderValue() + incr)
endif
endmethod
static method onTechtreeArrowClick takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local integer i = CustomRaceInterface.getTechtreeArrowID(zabutton)
local integer techChunk = ((i - 1) / CustomRaceUI_GetTechtreeChunkCount()) + 1
local integer inc = CustomRaceUI_GetTechtreeIconColumnMax()
local integer newBase = 0
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
// If the direction is up, decrease the base choice instead.
if BlzBitAnd(i, 1) != 0 then
set inc = -inc
endif
set newBase = IMaxBJ(obj.getBaseTechID(techChunk) + inc, 0)
if newBase == obj.getBaseTechID(techChunk) then
return
endif
call obj.setBaseTechID(techChunk, newBase)
if obj.techtree != 0 then
set obj.techtree = obj.techtree - inc
// The techtree icon previously highlighted is out of bounds
if (obj.techtree <= 0) or (obj.techtree > CustomRaceInterface.iconsPerChunk) then
set obj.techtree = 0
set obj.focusTechID = 0
set obj.focusTechtree = 0
set obj.focusTechtreeStack = 0
else
set obj.focusTechID = obj.techtree
endif
endif
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onConfirmButtonClick takes nothing returns nothing
local framehandle zabutton = BlzGetTriggerFrame()
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
local integer finalChoice = 0
local integer i = 0
// obj.focusFactionStack can only be equal to 2
// if a choice button was already selected.
if obj.faction == 0 then
call PlaySoundForPlayer(GenerateWarningSound(), trigPlayer)
return
endif
if not IsFrameUseable(trigPlayer) then
return
endif
set finalChoice = obj.faction + obj.baseChoice
set obj.focusFaction = 0
set obj.faction = 0
set obj.focusFactionStack = 0
set obj.techtree = 0
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.focusTechtreeStack = 0
loop
exitwhen i > CustomRaceUI_GetTechtreeChunkCount()
call obj.setBaseTechID(i, 0)
set i = i + 1
endloop
call DrawUIFromPlayerData(trigPlayer, obj)
set obj.faction = finalChoice
call CustomRacePSelection.removeChoicedPlayer(trigPlayer)
call CustomRacePSelection.addUnchoicedPlayer(trigPlayer)
call FrameInterpolation[trigPlayer].stop(MODE_BAR_UPDATE)
call HideCustomFrame(trigPlayer)
call CustomRaceObserverUI_RenderFrame()
if CustomRacePSelection.choicedPlayerSize < 1 then
call PauseTimer(finalizer)
call DestroyTimer(finalizer)
call thistype.finalize()
call CustomRaceObserverUI_UnrenderFrame()
endif
endmethod
// ========================================================================== //
// Scroll Events //
// ========================================================================== //
static method onSliderValueChange takes nothing returns nothing
local integer value = R2I(BlzGetTriggerFrameValue() + 0.01)
local integer maxBase = 0
local integer newBase = 0
local integer oldBase = 0
local player trigPlayer = GetTriggerPlayer()
local CustomRacePSelection obj = CRPSelection[trigPlayer]
set maxBase = IMaxBJ(CustomRace.getRaceFactionCount(GetPlayerRace(trigPlayer)) - CustomRaceUI_GetMaxDisplayChoices(), /*
*/ 0)
set newBase = maxBase - value
if obj.baseChoice == newBase then
return
endif
set oldBase = obj.baseChoice
set obj.baseChoice = newBase
if FrameInterpolation.localPlayer == trigPlayer then
call BlzFrameSetFocus(CustomRaceInterface.getChoiceButton(obj.faction), false)
endif
if obj.faction != 0 then
set obj.focusFaction = obj.focusFaction + oldBase - obj.baseChoice
set obj.faction = obj.focusFaction
// If the faction in focus is out of the list of choices displayed,
// clear out.
if (obj.focusFaction <= 0) or (obj.focusFaction > CustomRaceUI_GetMaxDisplayChoices()) then
set obj.focusFaction = 0
set obj.faction = 0
set obj.focusFactionStack = 0
set obj.focusTechtree = 0
set obj.focusTechID = 0
set obj.techtree = 0
set obj.focusTechtreeStack = 0
endif
endif
if not IsFrameUseable(trigPlayer) then
return
endif
call DrawUIFromPlayerData(trigPlayer, obj)
endmethod
static method onSliderDetectWheel takes nothing returns nothing
local real value = BlzGetTriggerFrameValue()
if value > 0 then
call CustomRaceInterface.setSliderValue(CustomRaceInterface.getSliderValue() + 1)
else
call CustomRaceInterface.setSliderValue(CustomRaceInterface.getSliderValue() - 1)
endif
endmethod
// ========================================================================== //
// Abandon Event //
// ========================================================================== //
static method onPlayerAbandon takes nothing returns nothing
local player trigPlayer = GetTriggerPlayer()
call FrameInterpolation[trigPlayer].stop(MODE_BAR_UPDATE)
call CustomRacePSelection.removeChoicedPlayer(trigPlayer)
call CustomRacePSelection.removeUnchoicedPlayer(trigPlayer)
if CustomRacePSelection.choicedPlayerSize < 1 then
call PauseTimer(finalizer)
call DestroyTimer(finalizer)
call thistype.finalize()
call CustomRaceObserverUI_UnrenderFrame()
else
call CustomRaceObserverUI_RenderFrame()
endif
call DisplayTimedTextToPlayer(FrameInterpolation.localPlayer, 0.0, 0.0, 20.0, /*
*/ GetPlayerName(trigPlayer) + " has abandoned the game.")
endmethod
private static method init takes nothing returns nothing
set onDefaultFinalize = function thistype.onExpireFinalize
endmethod
implement Init
endstruct
private function PrepHoverEvents takes nothing returns nothing
local trigger enterTrig = CreateTrigger()
local trigger leaveTrig = CreateTrigger()
local integer i = 1
local integer j = 1
// Add events to the choice buttons
loop
exitwhen i > CustomRaceUI_GetMaxDisplayChoices()
call BlzTriggerRegisterFrameEvent(enterTrig, CustomRaceInterface.getChoiceButton(i), /*
*/FRAMEEVENT_MOUSE_ENTER)
call BlzTriggerRegisterFrameEvent(leaveTrig, CustomRaceInterface.getChoiceButton(i), /*
*/FRAMEEVENT_MOUSE_LEAVE)
set i = i + 1
endloop
call TriggerAddAction(enterTrig, function UIFrameEvents.onChoiceButtonEnter)
call TriggerAddAction(leaveTrig, function UIFrameEvents.onChoiceButtonLeave)
// Add events to the techtree buttons
set enterTrig = CreateTrigger()
set leaveTrig = CreateTrigger()
set i = 1
set j = CustomRaceUI_GetTechtreeChunkCount()*CustomRaceUI_GetTechtreeIconColumnMax()
set j = j*CustomRaceUI_GetTechtreeIconRowMax()
loop
exitwhen i > j
call BlzTriggerRegisterFrameEvent(enterTrig, CustomRaceInterface.getTechtreeIconRaw(i), /*
*/FRAMEEVENT_MOUSE_ENTER)
call BlzTriggerRegisterFrameEvent(leaveTrig, CustomRaceInterface.getTechtreeIconRaw(i), /*
*/FRAMEEVENT_MOUSE_LEAVE)
set i = i + 1
endloop
call TriggerAddAction(enterTrig, function UIFrameEvents.onTechtreeIconEnter)
call TriggerAddAction(leaveTrig, function UIFrameEvents.onTechtreeIconLeave)
endfunction
private function PrepClickEvents takes nothing returns nothing
local trigger clickTrig = CreateTrigger()
local integer i = 1
local integer j = 1
// Add events to the choice buttons
loop
exitwhen i > CustomRaceUI_GetMaxDisplayChoices()
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getChoiceButton(i), /*
*/FRAMEEVENT_CONTROL_CLICK)
set i = i + 1
endloop
call TriggerAddAction(clickTrig, function UIFrameEvents.onChoiceButtonClick)
// Add events to the techtree buttons
set clickTrig = CreateTrigger()
set i = 1
set j = CustomRaceUI_GetTechtreeChunkCount()*CustomRaceUI_GetTechtreeIconColumnMax()
set j = j*CustomRaceUI_GetTechtreeIconRowMax()
loop
exitwhen i > j
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getTechtreeIconRaw(i), /*
*/FRAMEEVENT_CONTROL_CLICK)
set i = i + 1
endloop
call TriggerAddAction(clickTrig, function UIFrameEvents.onTechtreeIconClick)
// Add events to the choice arrows
set clickTrig = CreateTrigger()
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getChoiceArrow(true), /*
*/ FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getChoiceArrow(false), /*
*/ FRAMEEVENT_CONTROL_CLICK)
call TriggerAddAction(clickTrig, function UIFrameEvents.onChoiceArrowClick)
// Add events to the techtree arrows
set clickTrig = CreateTrigger()
set i = 1
set j = CustomRaceUI_GetTechtreeChunkCount()
loop
exitwhen i > j
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getTechtreeArrow(i, true), /*
*/FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.getTechtreeArrow(i, false), /*
*/FRAMEEVENT_CONTROL_CLICK)
set i = i + 1
endloop
call TriggerAddAction(clickTrig, function UIFrameEvents.onTechtreeArrowClick)
// Add the final event to the confirm button.
set clickTrig = CreateTrigger()
call BlzTriggerRegisterFrameEvent(clickTrig, CustomRaceInterface.confirmFrame, /*
*/FRAMEEVENT_CONTROL_CLICK)
call TriggerAddAction(clickTrig, function UIFrameEvents.onConfirmButtonClick)
endfunction
private function PrepScrollEvents takes nothing returns nothing
local trigger trig = CreateTrigger()
call BlzTriggerRegisterFrameEvent(trig, CustomRaceInterface.slider, /*
*/FRAMEEVENT_SLIDER_VALUE_CHANGED)
call TriggerAddAction(trig, function UIFrameEvents.onSliderValueChange)
set trig = CreateTrigger()
call BlzTriggerRegisterFrameEvent(trig, CustomRaceInterface.slider, /*
*/FRAMEEVENT_MOUSE_WHEEL)
call TriggerAddAction(trig, function UIFrameEvents.onSliderDetectWheel)
endfunction
private function PrepAbandonEvent takes nothing returns nothing
local integer i = 1
loop
exitwhen i > CustomRacePSelection.choicedPlayerSize
call TriggerRegisterPlayerEvent(UIFrameEvents.abandonTrig, CustomRacePSelection.choicedPlayers[i], /*
*/ EVENT_PLAYER_LEAVE)
set i = i + 1
endloop
set i = 1
loop
exitwhen i > CustomRacePSelection.unchoicedPlayerSize
call TriggerRegisterPlayerEvent(UIFrameEvents.abandonTrig, CustomRacePSelection.unchoicedPlayers[i], /*
*/ EVENT_PLAYER_LEAVE)
set i = i + 1
endloop
call TriggerAddAction(UIFrameEvents.abandonTrig, function UIFrameEvents.onPlayerAbandon)
endfunction
private function PrepEvents takes nothing returns nothing
call PrepHoverEvents()
call PrepClickEvents()
call PrepScrollEvents()
call PrepAbandonEvent()
endfunction
// ========================================================================== //
// ========================================================================== //
private function FillWithPlayerData takes player whichPlayer returns nothing
local CustomRacePSelection obj = CRPSelection[whichPlayer]
local integer maxSteps = CustomRace.getRaceFactionCount(GetPlayerRace(whichPlayer))
set maxSteps = IMaxBJ(maxSteps - CustomRaceUI_GetMaxDisplayChoices(), 0)
if (maxSteps != 0) and (FrameInterpolation.localPlayer == whichPlayer) then
call CustomRaceInterface.setSliderMaxValue(maxSteps)
endif
call DrawUIFromPlayerData(whichPlayer, obj)
endfunction
private function PopulateUI takes nothing returns nothing
local integer i = 1
loop
exitwhen i > CustomRacePSelection.choicedPlayerSize
call FillWithPlayerData(CustomRacePSelection.choicedPlayers[i])
set i = i + 1
endloop
// All players don't have a faction choice, proceed with game
// as normal
if CustomRacePSelection.choicedPlayerSize < 1 then
call UIFrameEvents.onFinalizeEnd()
else
call CustomRaceObserverUI_RenderFrame()
endif
endfunction
// ========================================================================== //
public function Initialization takes nothing returns nothing
call CustomRacePSelection.init()
call CustomRaceMatch_MeleeInitialization()
call PrepUI()
call PopulateUI()
call PrepEvents()
endfunction
endlibrary
//$ noimport
library CustomRaceDefault requires /*
----------------------
*/ CustomRaceCore, /*
----------------------
--------------------------
*/ CustomRaceMatch, /*
--------------------------
----------------------
*/ Init, /*
----------------------
*/
globals
private CustomRace array defaultRace
endglobals
//! textmacro CRDefault_DEF_SETUP takes NAME, SUBNAME
private function On$NAME$Setup takes nothing returns nothing
call MeleeStartingUnits$NAME$(CustomRaceMatch_OnStartGetPlayer(), /*
*/ CustomRaceMatch_OnStartGetLoc(), true, true, true)
endfunction
private function On$NAME$SetupAI takes nothing returns nothing
call PickMeleeAI(CustomRaceMatch_OnStartGetPlayer(), "$SUBNAME$.ai", null, null)
endfunction
//! endtextmacro
//! runtextmacro CRDefault_DEF_SETUP("Human", "human")
//! runtextmacro CRDefault_DEF_SETUP("Orc", "orc")
//! runtextmacro CRDefault_DEF_SETUP("NightElf", "elf")
private function OnUndeadSetup takes nothing returns nothing
call MeleeStartingUnitsUndead(CustomRaceMatch_OnStartGetPlayer(), /*
*/ CustomRaceMatch_OnStartGetLoc(), true, true, true)
endfunction
private function OnUndeadSetupAI takes nothing returns nothing
call PickMeleeAI(CustomRaceMatch_OnStartGetPlayer(), "undead.ai", null, null)
call RecycleGuardPosition(bj_ghoul[GetPlayerId(CustomRaceMatch_OnStartGetPlayer())])
endfunction
private struct S extends array
private static method init takes nothing returns nothing
set defaultRace[1] = CustomRace.create(RACE_HUMAN, "Alliance")
call defaultRace[1].defDescription("A coalition of Humans, Dwarves and Elves bound " + /*
*/ "together through the forging of bonds as old as " + /*
*/ "their kingdoms themselves.")
call defaultRace[1].defRacePic("war3mapImported\\humanseal.blp")
call defaultRace[1].addUnit('hpea')
call defaultRace[1].addUnit('hfoo')
call defaultRace[1].addUnit('hrif')
call defaultRace[1].addUnit('hkni')
call defaultRace[1].addUnit('hmtm')
call defaultRace[1].addUnit('hgyr')
call defaultRace[1].addUnit('hmpr')
call defaultRace[1].addUnit('hsor')
call defaultRace[1].addUnit('hspt')
call defaultRace[1].addUnit('hgry')
call defaultRace[1].addUnit('hmtt')
call defaultRace[1].addHall('htow')
call defaultRace[1].addHall('hkee')
call defaultRace[1].addHall('hcas')
call defaultRace[1].addStructure('htow')
call defaultRace[1].addStructure('hkee')
call defaultRace[1].addStructure('hcas')
call defaultRace[1].addStructure('hhou')
call defaultRace[1].addStructure('hbar')
call defaultRace[1].addStructure('halt')
call defaultRace[1].addStructure('hlum')
call defaultRace[1].addStructure('hbla')
call defaultRace[1].addStructure('hwtw')
call defaultRace[1].addStructure('hvlt')
call defaultRace[1].addStructure('harm')
call defaultRace[1].addStructure('hars')
call defaultRace[1].addStructure('hgra')
call defaultRace[1].addHero('Hpal')
call defaultRace[1].addHero('Hamg')
call defaultRace[1].addHero('Hmkg')
call defaultRace[1].addHero('Hblm')
call defaultRace[1].defSetup(function OnHumanSetup)
call defaultRace[1].defAISetup(function OnHumanSetupAI)
call defaultRace[1].defPlaylist("Sound\\Music\\mp3Music\\HumanX1.mp3;Sound\\Music\\mp3Music\\Human3.mp3;Sound\\Music\\mp3Music\\Human2.mp3;Sound\\Music\\mp3Music\\Human1.mp3")
set defaultRace[2] = CustomRace.create(RACE_ORC, "Horde")
call defaultRace[2].defDescription("Once beings with shamanic roots, these creatures " + /*
*/ "became as bloodthirsty as the demons. Seeking " + /*
*/ "refuge from their destroyed homeworld, they seek " + /*
*/ "even now to establish a new home in Azeroth, even " + /*
*/ "at the price of eternal bloodshed.")
call defaultRace[2].defRacePic("war3mapImported\\orcseal.blp")
call defaultRace[2].addUnit('opeo')
call defaultRace[2].addUnit('ogru')
call defaultRace[2].addUnit('ohun')
call defaultRace[2].addUnit('ocat')
call defaultRace[2].addUnit('orai')
call defaultRace[2].addUnit('okod')
call defaultRace[2].addUnit('oshm')
call defaultRace[2].addUnit('odoc')
call defaultRace[2].addUnit('otau')
call defaultRace[2].addUnit('ospw')
call defaultRace[2].addUnit('owvy')
call defaultRace[2].addUnit('otbr')
call defaultRace[2].addHall('ogre')
call defaultRace[2].addHall('ostr')
call defaultRace[2].addHall('ofrt')
call defaultRace[2].addStructure('ogre')
call defaultRace[2].addStructure('ostr')
call defaultRace[2].addStructure('ofrt')
call defaultRace[2].addStructure('otrb')
call defaultRace[2].addStructure('obar')
call defaultRace[2].addStructure('oalt')
call defaultRace[2].addStructure('ofor')
call defaultRace[2].addStructure('owtw')
call defaultRace[2].addStructure('ovln')
call defaultRace[2].addStructure('obea')
call defaultRace[2].addStructure('osld')
call defaultRace[2].addStructure('obea')
call defaultRace[2].addHero('Obla')
call defaultRace[2].addHero('Ofar')
call defaultRace[2].addHero('Otch')
call defaultRace[2].addHero('Oshd')
call defaultRace[2].defSetup(function OnOrcSetup)
call defaultRace[2].defAISetup(function OnOrcSetupAI)
call defaultRace[2].defPlaylist("Sound\\Music\\mp3Music\\OrcX1.mp3;Sound\\Music\\mp3Music\\Orc3.mp3;Sound\\Music\\mp3Music\\Orc2.mp3;Sound\\Music\\mp3Music\\Orc1.mp3")
set defaultRace[3] = CustomRace.create(RACE_UNDEAD, "Scourge")
call defaultRace[3].defDescription("Once living creatures robbed of their sweet release " + /*
*/ "from life, these undead beings are relentless and " + /*
*/ "ferocious creatures, tempered by their bond to the " + /*
*/ "master, the Lich King.")
call defaultRace[3].defRacePic("war3mapImported\\undeadseal.blp")
call defaultRace[3].addUnit('uaco')
call defaultRace[3].addUnit('ugho')
call defaultRace[3].addUnit('ucry')
call defaultRace[3].addUnit('ugar')
call defaultRace[3].addUnit('umtw')
call defaultRace[3].addUnit('uobs')
call defaultRace[3].addUnit('unec')
call defaultRace[3].addUnit('uban')
call defaultRace[3].addUnit('ushd')
call defaultRace[3].addUnit('uabo')
call defaultRace[3].addUnit('ufro')
call defaultRace[3].addUnit('ubsp')
call defaultRace[3].addHall('unpl')
call defaultRace[3].addHall('unp1')
call defaultRace[3].addHall('unp2')
call defaultRace[3].addStructure('unpl')
call defaultRace[3].addStructure('unp1')
call defaultRace[3].addStructure('unp2')
call defaultRace[3].addStructure('uzig')
call defaultRace[3].addStructure('usep')
call defaultRace[3].addStructure('uaod')
call defaultRace[3].addStructure('ugrv')
call defaultRace[3].addStructure('utom')
call defaultRace[3].addStructure('ugol')
call defaultRace[3].addStructure('uslh')
call defaultRace[3].addStructure('utod')
call defaultRace[3].addStructure('usap')
call defaultRace[3].addStructure('ubon')
call defaultRace[3].addHero('Udea')
call defaultRace[3].addHero('Udre')
call defaultRace[3].addHero('Ulic')
call defaultRace[3].addHero('Ucrl')
call defaultRace[3].defSetup(function OnUndeadSetup)
call defaultRace[3].defAISetup(function OnUndeadSetupAI)
call defaultRace[3].defPlaylist("Sound\\Music\\mp3Music\\UndeadX1.mp3;Sound\\Music\\mp3Music\\Undead3.mp3;Sound\\Music\\mp3Music\\Undead2.mp3;Sound\\Music\\mp3Music\\Undead1.mp3")
set defaultRace[4] = CustomRace.create(RACE_NIGHTELF, "Sentinels")
call defaultRace[4].defDescription("Once prominent arcane magic practitioners, their " + /*
*/ "use of magic to reckless abandon had nearly torn " + /*
*/ "their world asunder, as the Burning Legion lay " + /*
*/ "waste to their world. After defeating the Burning " + /*
*/ "Legion, they vowed never to use arcane magic and " + /*
*/ "embraced druidism under the tutelage of Cenarius. " + /*
*/ "For centuries past, they had become a force to " + /*
*/ "be reckoned with.")
call defaultRace[4].defRacePic("war3mapImported\\nightelfseal.blp")
call defaultRace[4].addUnit('ewsp')
call defaultRace[4].addUnit('earc')
call defaultRace[4].addUnit('esen')
call defaultRace[4].addUnit('ebal')
call defaultRace[4].addUnit('edry')
call defaultRace[4].addUnit('emtg')
call defaultRace[4].addUnit('edoc')
call defaultRace[4].addUnit('edot')
call defaultRace[4].addUnit('efdr')
call defaultRace[4].addUnit('ehip')
call defaultRace[4].addUnit('echm')
call defaultRace[4].addUnit('edcm')
call defaultRace[4].addHall('etol')
call defaultRace[4].addHall('etoa')
call defaultRace[4].addHall('etoe')
call defaultRace[4].addStructure('etol')
call defaultRace[4].addStructure('etoa')
call defaultRace[4].addStructure('etoe')
call defaultRace[4].addStructure('emow')
call defaultRace[4].addStructure('eaom')
call defaultRace[4].addStructure('eate')
call defaultRace[4].addStructure('edob')
call defaultRace[4].addStructure('etrp')
call defaultRace[4].addStructure('eden')
call defaultRace[4].addStructure('eaoe')
call defaultRace[4].addStructure('eaow')
call defaultRace[4].addStructure('edos')
call defaultRace[4].addHero('Ekee')
call defaultRace[4].addHero('Emoo')
call defaultRace[4].addHero('Edem')
call defaultRace[4].addHero('Ewar')
call defaultRace[4].defSetup(function OnNightElfSetup)
call defaultRace[4].defAISetup(function OnNightElfSetupAI)
call defaultRace[4].defPlaylist("Sound\\Music\\mp3Music\\NightElfX1.mp3;Sound\\Music\\mp3Music\\NightElf3.mp3;Sound\\Music\\mp3Music\\NightElf2.mp3;Sound\\Music\\mp3Music\\NightElf1.mp3")
call CustomRace.addGlobalHero('Npbm')
call CustomRace.addGlobalHero('Nbrn')
call CustomRace.addGlobalHero('Nngs')
call CustomRace.addGlobalHero('Nplh')
call CustomRace.addGlobalHero('Nbst')
call CustomRace.addGlobalHero('Nalc')
call CustomRace.addGlobalHero('Ntin')
call CustomRace.addGlobalHero('Nfir')
endmethod
implement Init
endstruct
endlibrary
//$ noimport
library CustomRaceTemplate requires /*
----------------------
*/ CustomRaceCore, /*
----------------------
------------------------------
*/ CustomRacePSelection, /*
------------------------------
--------------------------
*/ CustomRaceMatch, /*
--------------------------
*/
globals
private constant boolean IMPORTED_GUI_VARIABLES = true
private constant integer MAX_LOC_AUTO_CLEANUP = 20
endglobals
module CustomRaceTemplate
// private static race FACTION_RACE
// private static string FACTION_NAME
// private static string FACTION_DESCRIPTION
// private static string FACTION_DISPLAY
// private static string FACTION_PLAYLIST
// private static integer FACTION_HALL
// private static integer FACTION_WORKER
private static CustomRace faction = 0
static if not thistype.onSetup.exists then
private static method onSetup takes player whichPlayer, location startLoc, boolean doHeroes, boolean doCamera, boolean doPreload returns nothing
local boolean useRandomHero = IsMapFlagSet(MAP_RANDOM_HERO)
local real unitSpacing = 64.00
local unit nearestMine
local unit randomHero
local location mineLoc
local location nearMineLoc
local location heroLoc
local real peonX
local real peonY
local unit townHall = null
static if thistype.preloadPld.exists then
if (doPreload) then
call thistype.preloadPld()
endif
endif
set nearestMine = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
static if thistype.onSetupCreateUnits.exists then
call thistype.onSetupCreateUnits(whichPlayer, nearestMine, startLoc)
else
if (nearestMine != null) then
// Spawn Town Hall at the start location.
set townHall = CreateUnitAtLoc(whichPlayer, FACTION_HALL, startLoc, bj_UNIT_FACING)
// Spawn Peasants near the mine.
set mineLoc = GetUnitLoc(nearestMine)
set nearMineLoc = MeleeGetProjectedLoc(mineLoc, startLoc, 320, 0)
set peonX = GetLocationX(nearMineLoc)
set peonY = GetLocationY(nearMineLoc)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 0.00 * unitSpacing, peonY + 1.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX - 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX - 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
call RemoveLocation(nearMineLoc)
// Set random hero spawn point to be off to the side of the start location.
set heroLoc = MeleeGetProjectedLoc(mineLoc, startLoc, 384, 45)
call RemoveLocation(mineLoc)
else
// Spawn Town Hall at the start location.
set townHall = CreateUnitAtLoc(whichPlayer, FACTION_HALL, startLoc, bj_UNIT_FACING)
// Spawn Peasants directly south of the town hall.
set peonX = GetLocationX(startLoc)
set peonY = GetLocationY(startLoc) - 224.00
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX + 0.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX - 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, FACTION_WORKER, peonX - 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
// Set random hero spawn point to be just south of the start location.
// (Sorry, got lazy here.)
set heroLoc = Location(peonX, peonY - 2.00 * unitSpacing)
endif
static if thistype.initTownhall.exists then
call thistype.initTownhall(whichPlayer, townHall)
endif
endif
if (doHeroes) then
// If the "Random Hero" option is set, start the player with a random hero.
// Otherwise, give them a "free hero" token.
if useRandomHero then
set randomHero = CreateUnit(whichPlayer, faction.getRandomHero(), GetLocationX(heroLoc), GetLocationY(heroLoc), bj_UNIT_FACING)
if bj_meleeGrantHeroItems then
call MeleeGrantItemsToHero(randomHero)
endif
set randomHero = null
else
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_HERO_TOKENS, bj_MELEE_STARTING_HERO_TOKENS)
endif
endif
call RemoveLocation(heroLoc)
if (doCamera) then
// Center the camera on the initial Peasants.
call SetCameraPositionForPlayer(whichPlayer, peonX, peonY)
call SetCameraQuickPositionForPlayer(whichPlayer, peonX, peonY)
endif
set nearestMine = null
set randomHero = null
set mineLoc = null
set nearMineLoc = null
set heroLoc = null
endmethod
endif
private static method onSetupPrep takes nothing returns nothing
call thistype.onSetup(CustomRaceMatch_OnStartGetPlayer(), /*
*/ CustomRaceMatch_OnStartGetLoc(), true, true, true)
endmethod
private static method onSetupPrepAI takes nothing returns nothing
static if thistype.onSetupAI.exists then
call thistype.onSetupAI(CustomRaceMatch_OnStartGetPlayer())
endif
endmethod
private static method onInit takes nothing returns nothing
set faction = CustomRace.create(FACTION_RACE, FACTION_NAME)
if faction == 0 then
return
endif
call faction.defDescription(FACTION_DESCRIPTION)
call faction.defRacePic(FACTION_DISPLAY)
call faction.defPlaylist(FACTION_PLAYLIST)
static if thistype.initTechtree.exists then
call thistype.initTechtree(faction)
endif
call faction.defSetup(function thistype.onSetupPrep)
call faction.defAISetup(function thistype.onSetupPrepAI)
endmethod
endmodule
static if IMPORTED_GUI_VARIABLES then
struct CustomRaceTemplateGUI
readonly CustomRace faction
trigger setupTrig
trigger setupTrigAI
trigger preloadTrig
integer factionHall
integer factionWorker
private static thistype array factionMap
static if not thistype.onSetup.exists then
private static method onSetup takes player whichPlayer, location startLoc, boolean doHeroes, boolean doCamera, boolean doPreload returns nothing
local boolean useRandomHero = IsMapFlagSet(MAP_RANDOM_HERO)
local real unitSpacing = 64.00
local unit nearestMine
local unit randomHero
local location nearMineLoc
local location heroLoc
local real peonX
local real peonY
local real mineAngle
local unit townHall = null
local CustomRacePSelection obj = CRPSelection[whichPlayer]
local CustomRace faction = CustomRace.getRaceFaction(GetPlayerRace(whichPlayer), obj.faction)
local thistype this = factionMap[faction]
local integer iter = 0
if (doPreload) then
set udg_CustomRace_Player = whichPlayer
call ConditionalTriggerExecute(this.preloadTrig)
endif
set nearestMine = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
if setupTrig != null then
// Introduce GUI Constants here
set udg_CustomRace_Player = whichPlayer
set udg_CustomRace_StartLocation = startLoc
set udg_CustomRace_PlayerMine = nearestMine
if (nearestMine != null) then
set mineAngle = Atan2(GetUnitY(nearestMine) - GetLocationY(startLoc), /*
*/ GetUnitX(nearestMine) - GetLocationX(startLoc))
set udg_CustomRace_StartPeonCenterLoc = Location(GetLocationX(startLoc) + 320*Cos(mineAngle), /*
*/ GetLocationY(startLoc) + 320*Sin(mineAngle))
else
set udg_CustomRace_StartPeonCenterLoc = Location(GetLocationX(startLoc), /*
*/ GetLocationY(startLoc) - 224.0)
endif
call ConditionalTriggerExecute(this.setupTrig)
loop
// MAX_LOC_AUTO_CLEANUP (20) seems more than reasonable enough for automatic location handle clean up.
// All indices higher than or equal to MAX_LOC_AUTO_CLEANUP should be cleaned up by the user himself.
exitwhen ((iter > MAX_LOC_AUTO_CLEANUP) and (udg_CustomRace_StartPeonLoc[iter] == null))
if (udg_CustomRace_StartPeonLoc[iter] != null) then
call RemoveLocation(udg_CustomRace_StartPeonLoc[iter])
endif
set udg_CustomRace_StartPeonLoc[iter] = null
set iter = iter + 1
endloop
call RemoveLocation(udg_CustomRace_StartPeonCenterLoc)
set udg_CustomRace_StartPeonCenterLoc = null
set udg_CustomRace_StartLocation = null
else
if (nearestMine != null) then
// Spawn Town Hall at the start location.
set townHall = CreateUnitAtLoc(whichPlayer, this.factionHall, startLoc, bj_UNIT_FACING)
// Spawn Peasants near the mine.
set mineAngle = Atan2(GetUnitY(nearestMine) - GetLocationY(startLoc), /*
*/ GetUnitX(nearestMine) - GetLocationX(startLoc))
set peonX = GetLocationX(startLoc) + 320*Cos(mineAngle)
set peonY = GetLocationY(startLoc) + 320*Sin(mineAngle)
call CreateUnit(whichPlayer, this.factionWorker, peonX + 0.00 * unitSpacing, peonY + 1.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX + 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX - 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX + 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX - 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
// Set random hero spawn point to be off to the side of the start location.
set mineAngle = mineAngle + bj_PI / 4.0
set heroLoc = Location(GetLocationX(startLoc) + 384*Cos(mineAngle), /*
*/ GetLocationY(startLoc) + 384*Sin(mineAngle))
else
// Spawn Town Hall at the start location.
set townHall = CreateUnitAtLoc(whichPlayer, this.factionHall, startLoc, bj_UNIT_FACING)
// Spawn Peasants directly south of the town hall.
set peonX = GetLocationX(startLoc)
set peonY = GetLocationY(startLoc) - 224.00
call CreateUnit(whichPlayer, this.factionWorker, peonX + 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX + 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX + 0.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX - 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
call CreateUnit(whichPlayer, this.factionWorker, peonX - 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
// Set random hero spawn point to be just south of the start location.
set heroLoc = Location(peonX, peonY - 2.00 * unitSpacing)
endif
endif
if (doHeroes) then
// If the "Random Hero" option is set, start the player with a random hero.
// Otherwise, give them a "free hero" token.
if useRandomHero then
set randomHero = CreateUnit(whichPlayer, faction.getRandomHero(), GetLocationX(heroLoc), GetLocationY(heroLoc), bj_UNIT_FACING)
if bj_meleeGrantHeroItems then
call MeleeGrantItemsToHero(randomHero)
endif
set randomHero = null
else
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_HERO_TOKENS, bj_MELEE_STARTING_HERO_TOKENS)
endif
endif
call RemoveLocation(heroLoc)
if (doCamera) then
// Center the camera on the initial Peasants.
call SetCameraPositionForPlayer(whichPlayer, peonX, peonY)
call SetCameraQuickPositionForPlayer(whichPlayer, peonX, peonY)
endif
set nearestMine = null
set randomHero = null
set nearMineLoc = null
set heroLoc = null
endmethod
endif
private static method onSetupPrep takes nothing returns nothing
call thistype.onSetup(CustomRaceMatch_OnStartGetPlayer(), /*
*/ CustomRaceMatch_OnStartGetLoc(), true, true, true)
endmethod
private static method onSetupPrepAI takes nothing returns nothing
local player whichPlayer = CustomRaceMatch_OnStartGetPlayer()
local CustomRacePSelection obj = CRPSelection[whichPlayer]
local CustomRace faction = CustomRace.getRaceFaction(GetPlayerRace(whichPlayer), obj.faction)
local thistype this = factionMap[faction]
set udg_CustomRace_Player = whichPlayer
call ConditionalTriggerExecute(this.setupTrigAI)
endmethod
static method create takes race whichRace, string whichName returns thistype
local thistype this = thistype.allocate()
set this.faction = CustomRace.create(whichRace, whichName)
if this.faction == 0 then
call this.deallocate()
return 0
endif
set factionMap[this.faction] = this
call this.faction.defSetup(function thistype.onSetupPrep)
call this.faction.defAISetup(function thistype.onSetupPrepAI)
return this
endmethod
endstruct
public function Create takes nothing returns nothing
local CustomRaceTemplateGUI template = CustomRaceTemplateGUI.create(udg_CustomRace_DefRace, udg_CustomRace_DefName)
local integer i = 1
call template.faction.defDescription(udg_CustomRace_Description)
call template.faction.defRacePic(udg_CustomRace_Display)
call template.faction.defPlaylist(udg_CustomRace_Playlist)
set udg_CustomRace_DefRace = null
set udg_CustomRace_DefName = ""
set udg_CustomRace_Description = ""
set udg_CustomRace_Display = ""
set udg_CustomRace_Playlist = ""
set template.setupTrig = udg_CustomRace_SetupTrig
set template.setupTrigAI = udg_CustomRace_AISetupTrig
set template.preloadTrig = udg_CustomRace_PreloadPLDTrig
set udg_CustomRace_SetupTrig = null
set udg_CustomRace_AISetupTrig = null
set udg_CustomRace_PreloadPLDTrig = null
set template.factionHall = udg_CustomRace_FactionHall
set template.factionWorker = udg_CustomRace_FactionWorker
set udg_CustomRace_FactionHall = 0
set udg_CustomRace_FactionWorker = 0
// Add all units
loop
exitwhen udg_CustomRace_UnitID[i] == 0
call template.faction.addUnit(udg_CustomRace_UnitID[i])
set udg_CustomRace_UnitID[i] = 0
set i = i + 1
endloop
// Add all Heroes
set i = 1
loop
exitwhen udg_CustomRace_HeroID[i] == 0
call template.faction.addHero(udg_CustomRace_HeroID[i])
set udg_CustomRace_HeroID[i] = 0
set i = i + 1
endloop
// Add all Halls
set i = 1
loop
exitwhen udg_CustomRace_HallID[i] == 0
call template.faction.addHall(udg_CustomRace_HallID[i])
set udg_CustomRace_HallID[i] = 0
set i = i + 1
endloop
// Add all Structures
set i = 1
loop
exitwhen udg_CustomRace_BuildingID[i] == 0
call template.faction.addStructure(udg_CustomRace_BuildingID[i])
set udg_CustomRace_BuildingID[i] = 0
set i = i + 1
endloop
endfunction
endif
endlibrary
scope NewFaction
// Sample template
private struct S extends array
private static race FACTION_RACE = RACE_HUMAN
private static string FACTION_NAME = "High Elves"
private static string FACTION_DISPLAY = ""
private static string FACTION_PLAYLIST = "Sound\\Music\\mp3Music\\NagaTheme.mp3;Sound\\Music\\mp3Music\\BloodElfTheme.mp3;Sound\\Music\\mp3Music\\Human1.mp3"
private static integer FACTION_HALL = 'h000'
private static integer FACTION_WORKER = 'n000'
private static string FACTION_DESCRIPTION = "Humans, but more advanced in magic."
private static method initTechtree takes CustomRace faction returns nothing
call faction.addUnit('n000')
call faction.addUnit('h001')
call faction.addUnit('n002')
call faction.addHall('h000')
call faction.addStructure('h000')
call faction.addStructure('n003')
call faction.addStructure('n001')
call faction.addStructure('h003')
call faction.addStructure('h002')
call faction.addStructure('n004')
endmethod
implement CustomRaceTemplate
endstruct
endscope