- Joined
- Jan 9, 2005
- Messages
- 2,126
Hmmm, sure, I guess regions are fine.
I use the regions to create crabs on the river. There is a techtree upgrade in my race that grants you vision of those crabs. Nothing special. If you actually want to import the race then you have to set the crab spawns somewhere else![]()
//===========================================================================
// Function to figure out if a point is in shallow water
//===========================================================================
function SpawnCrabsValidLoc takes location crabPoint returns boolean
if (IsTerrainPathableBJ(crabPoint, PATHING_TYPE_FLOATABILITY) == false) then
return false
endif
if (IsTerrainPathableBJ(crabPoint, PATHING_TYPE_WALKABILITY) == false) then
return false
endif
return true
endfunction
//===========================================================================
// This trigger picks random points on the map and checks to see if they
// are shallow water. If so, it makes a crab at the point. This loops
// over and over until it makes 10 crabs. That right there would crash the
// game if there was no shallow water. Watch out!
//===========================================================================
function Trig_SpawnCrabs_Actions takes nothing returns nothing
local integer crabCounter = 0
local real crabX = 0.0
local real crabY = 0.0
local location crabPoint = Location(0,0)
loop
exitwhen crabCounter >= 10
set crabX = GetRandomReal(GetRectMinX(GetPlayableMapRect()),GetRectMaxX(GetPlayableMapRect()))
set crabY = GetRandomReal(GetRectMinY(GetPlayableMapRect()),GetRectMaxY(GetPlayableMapRect()))
call MoveLocation(crabPoint,crabX,crabY)
if ( SpawnCrabsValidLoc(crabPoint)) then
call CreateNUnitsAtLoc( 1, 'ncrb', Player(PLAYER_NEUTRAL_PASSIVE), crabPoint, bj_UNIT_FACING )
set crabCounter = crabCounter + 1
else
endif
endloop
call RemoveLocation(crabPoint)
endfunction
//===========================================================================
// This InitTrig runs at the start and puts together the SpawnCrabs
// trigger. It might be a bit redundand, I don't know, I'm not a JASS
// expert or anything.
//===========================================================================
function InitTrig_SpawnCrabs takes nothing returns nothing
set gg_trg_SpawnCrabs = CreateTrigger()
call TriggerAddAction( gg_trg_SpawnCrabs, function Trig_SpawnCrabs_Actions )
endfunction
ikrOh come on, who doesn't love crabs?
Humidils
Use Humidils' Puddle Lashes to slow enemies' attack speed. If you take large numbers of Humidils, try to attack different targets to make them most out of the attack speed debuff.
Rivulets
Although Reef Shot may not seem to be a great passive ability, any damage boost is always better for your units. About 4-6 Rivulets is enough to take down a mage or flying unit in seconds.
Seatapper
This guy is your main tanker. Put them in the frontlines so they can soak up the damage for your squishier targets so they can safely damage your enemies. The regeneration upgrade will heal your Seatappers faster, making them quite durable in long fights.
Ascended
Ascended can deal tons of damage to the back line, and Relentless Charge makes it easier for them to reach their targets. Conquerer is a great passive if you're planning to take a lot of Ascendeds, although it is not recommended to take more than 6 of them.
Volley Basin
Your basic and only siege unit. As with all siege units, they are very vulnerable to melee and flying units, so be sure to put them in a safe distance. With the Crushing Tide upgrade, time your attacks properly to knock enemies up multiple times if you have many Volley Basins.
Runic Watcher
Flying ranged unit with bouncing attacks. Sounds intriguing, but don't overdo it. If you're planning to take large amounts of Runic Watchers, get the Ethereal Body upgrade for the increased durability.
Abyssal Guardian
The Wellings' Ultimate unit. Position your attacks properly to make the most out of Staggering Blows. Use Safeguard on important targets such as heroes and mages.
Madlord
It's best to know which spell you want to cast first. Casting Deranged Fling and then Tidal Prison will crowd control your enemy even longer. However, casting Tidal Prison and then Deranged Fling is a good way to chase priority targets. If you still want the bonus damage, you can wait out the snare duration and cast fling at the near-end of the duration to get the bonus damage while still crowd controlling them for a long time. While using Insanity's bonus movement speed to reach important enemies at the backline may sound like a good idea, the Madlord is quite squishy without Safeguard.
Aquachanter
Land a group stun with Shimmering Bubble and use Call of Ascended on them to burst down squishy targets. Blob Attack synergies well with Essence Rift as more units means more mana restored.
Tide Priest
Predict where your enemies will move to land a perfect Seastriker Orb as it has a 1.2 second delay. Salvation's cast range is quite short, but the channel range is unlimited. After you cast it, the target can move wherever it wants and still get the healing. Abyssal Voyage is situational. If you use it in battle, it puts the spell on a long cooldown to save just one allied unit, so proper usage of the spell is required.
Ocean Vanguard
Use Riptide to disable a clumped group of enemies. It's best to use Titan's Endurance after casting Waterway Reversion so the hero can sustain all the damage he receives from taunted units.
Verah Noice! (I really oughta start on mine...) Looks really cohesive overall (aesthetically). Two questions:
- Is the Abyssal Guardian a tinted version of the alternate version of Direfury's little "Gnome Wizard" model?
- Where did you get the Ascended model from?
I have a question:
Can I use models or textures without teamcolor? I was planning to use some of Mr.Goblin's Horror Textures but they don't have TC.
You can, but keep in mind that if there isn't some other way to identify the unit's player colour, you might lose points.I have a question:
Can I use models or textures without teamcolor? I was planning to use some of Mr.Goblin's Horror Textures but they don't have TC.
Sadly they cannot be the basic units since they need to be more or less immobile, building bound harvester. And they cannot come prebuild else it would give 100% gold harvest rate from the get go.
Edit: for the crab spawning trigger, i would highly suggest instead of picking random points to iterate through every 68x68 area (brush size) of the map once and save the valid locstioms. Would only require a simple 2d array (for the x and y of the valid squares) and one iteration through the map. Then you can just always pick a random number out of the valid locations wothout much iterations. Because depending on the map, chances are you pick through masses of points.
The polyps will rip the trees out in one go, giving you the full amount of lumber without returning to the forgotten one. Problem is that you have to wait until they accumulated that amount equal to the trees hp. I don't know if i want to add an option to give you less lumber but more directly.
The contest shall begin on 30 April 2018 and conclude on 31 July 2018 GMT (day is included).
10 days?
so we are allowed to replace a race, right? We're not expected to have our race playable with the 4 other races simultaneously?
The current four melee races may not be edited; copy and paste the default units you are about to edit.
library CustomBuildSystem /*
*/ requires /*
Legend:
#? -> optional resource
# -> required resource
*||------------------------||*
*/ DockingSystem /*
#? SmartTrack
#? Table
-> Spellbound
link: https://www.hiveworkshop.com/threads/dockingsystem-v1-05-2.299959/#resource-78986
*||------------------------||*
*||------------------------||*
*/ Table /*
-> Bribe
link: https://www.hiveworkshop.com/threads/snippet-new-table.188084/
*||------------------------||*
*||------------------------||*
*/ ListT /*
# Table
# Alloc
-> Bannar
link: https://www.hiveworkshop.com/threads/containers-list-t.249011/
*||------------------------||*
*||------------------------||*
*/ Alloc /*
-> Sevion
link: https://hiveworkshop.com/threads/snippet-alloc.192348/
*||------------------------||*
*||------------------------||*
*/ UnitDex /*
-> TriggerHappy
link: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
*||------------------------||*
*||------------------------||*
*/ RegisterPlayerUnitEvent /*
# RegisterNativeEvent
-> Bannar
link: https://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*||------------------------||*
*||------------------------||*
*/ UnitEventsEx /*
# UnitDex
# RegisterPlayerUnitEvent
#? ListT
#? WorldBounds
-> Spellbound
link: https://www.hiveworkshop.com/threads/vjass-version-of-gui-unit-event.306289/#post-3270559
*||------------------------||*
*/ SimError /*
-> Vexorian
link: http://www.wc3c.net/showthread.php?t=101260
*||------------------------||*
*||------------------------||*
*/ BuilderTrace /*
# UnitDex
# Table
# OrderIndex
-> MyPad
link: Not yet defined...
*/
native GetUnitGoldCost takes integer unitid returns integer
native GetUnitWoodCost takes integer unitid returns integer
globals
private group copyGroup_tempGroup = null
endglobals
private function OnCopyGroup takes nothing returns nothing
call GroupAddUnit(copyGroup_tempGroup, GetEnumUnit())
endfunction
private function CopyGroup takes group whichGroup, group tempGroup returns nothing
set copyGroup_tempGroup = whichGroup
call GroupClear(whichGroup)
call ForGroup(tempGroup, function OnCopyGroup)
endfunction
static if DEBUG_MODE then
private function printError takes string msg returns nothing
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cffff0000Error:|r |cffffcc00" + msg + "|r")
endfunction
endif
private module Initializer
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
private struct BuildSystemEx extends array
readonly static Table constructType = 0
readonly static Table stationHolder = 0
readonly static TableArray unitTypeLimit = 0
readonly static TableArray dataBase = 0
static method operator construct takes nothing returns integer
return 1
endmethod
static method operator upgrade takes nothing returns integer
return 2
endmethod
static method operator train takes nothing returns integer
return 3
endmethod
static method getConstructType takes integer abilId returns integer
return thistype.constructType.integer[abilId]
endmethod
static method increment takes player p, integer unitId returns nothing
local integer pIndex = GetPlayerId(p) + 1
set thistype.unitTypeLimit[pIndex].integer[unitId] = thistype.unitTypeLimit[pIndex].integer[unitId] + 1
call SetPlayerTechMaxAllowed(p, unitId, thistype.unitTypeLimit[pIndex].integer[unitId])
endmethod
static method decrement takes player p, integer unitId returns nothing
local integer pIndex = GetPlayerId(p) + 1
set thistype.unitTypeLimit[pIndex].integer[unitId] = thistype.unitTypeLimit[pIndex].integer[unitId] - 1
call SetPlayerTechMaxAllowed(p, unitId, thistype.unitTypeLimit[pIndex].integer[unitId])
endmethod
private static method init takes nothing returns nothing
set thistype.stationHolder = Table.create()
set thistype.constructType = Table.create()
set thistype.dataBase = TableArray[12]
set thistype.unitTypeLimit = TableArray[bj_MAX_PLAYER_SLOTS + 1]
endmethod
implement Initializer
endstruct
private struct SubBuildList extends array
implement Alloc
// Ability is unique, so...
private static Table abilityTable = 0
readonly integer unitId
readonly integer abilId
readonly integer count
readonly boolean consumesWorker
static method getInstance takes integer abilId returns thistype
return thistype.abilityTable.integer[abilId]
endmethod
static method create takes integer unitId, integer abilId, boolean consumesWorker, integer count returns thistype
local thistype result = thistype.abilityTable.integer[abilId]
if result == 0 then
set result = thistype.allocate()
set result.unitId = unitId
set result.abilId = abilId
set result.count = count
set result.consumesWorker = consumesWorker
set thistype.abilityTable.integer[abilId] = result
endif
return result
endmethod
private static method initVar takes nothing returns nothing
set thistype.abilityTable = Table.create()
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
endmethod
implement Initializer
endstruct
private struct BuildList extends array
implement Alloc
private static constant player NEUTRAL = Player(PLAYER_NEUTRAL_PASSIVE)
private static Table holderTable = 0
private static Table subRefTable = 0
private static SubBuildList currentTemp = 0
private integer abilHolder
private IntegerList subList
static method create takes integer unitId, integer abilId, integer abilHolder, boolean consumesWorker, integer count returns thistype
local thistype result = thistype.holderTable.integer[abilHolder]
local SubBuildList temp = 0
if result == 0 then
set result = thistype.allocate()
set result.subList = IntegerList.create()
set result.abilHolder = abilHolder
set thistype.holderTable.integer[abilHolder] = result
endif
set temp = SubBuildList.getInstance(abilId)
if temp == 0 then
set temp = SubBuildList.create(unitId, abilId, consumesWorker, count)
call result.subList.push(temp)
set thistype.subRefTable.integer[temp] = result
endif
return result
endmethod
private static method onSpellCastHide takes nothing returns nothing
local unit enum = GetEnumUnit()
call SetUnitInvulnerable(enum, true)
if thistype.currentTemp.consumesWorker then
call SetUnitUseFood(enum, false)
endif
call PauseUnit(enum, true)
call ShowUnit(enum, false)
set enum = null
endmethod
private static method onSpellCastUndock takes nothing returns nothing
call DockingSystem.undock(GetEnumUnit())
call thistype.onSpellCastHide()
endmethod
private static method onSpellCast takes nothing returns nothing
local unit station = GetTriggerUnit()
local unit plug
local BuildSystem whichBuild
local SubBuildList temp = SubBuildList.getInstance(GetSpellAbilityId())
local thistype handler = thistype.subRefTable.integer[temp]
local integer constructType = BuildSystemEx.getConstructType(handler.abilHolder)
local integer stationHandle = GetHandleId(station)
local integer stationId = GetUnitTypeId(station)
local integer plugHandle
local integer plugCount = 0
local IntegerListItem iter
local player stationOwner = GetOwningPlayer(station)
local trigger trig
local trigger detector
set whichBuild = BuildSystem(BuildSystemEx.stationHolder.integer[stationId])
if constructType == BuildSystemEx.construct then
set BuildSystemEx.dataBase[1].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[2].real[stationHandle] = GetUnitX(station)
set BuildSystemEx.dataBase[3].real[stationHandle] = GetUnitY(station)
set BuildSystemEx.dataBase[4].group[stationHandle] = CreateGroup()
// Get the number of available plugs...
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0 or (plugCount >= temp.count)
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
call GroupAddUnit(BuildSystemEx.dataBase[4].group[stationHandle], plug)
set plugCount = plugCount + 1
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Construction of " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
call DestroyGroup(BuildSystemEx.dataBase[4].group[stationHandle])
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
set station = null
set plug = null
return
endif
call ShowUnit(station, false)
call SetUnitX(station, WorldBounds.minX)
call SetUnitY(station, WorldBounds.minY)
call SetUnitInvulnerable(station, true)
/*
set detector = CreateTrigger()
call TriggerRegisterPlayerStateEvent(detector, stationOwner, PLAYER_STATE_RESOURCE_GOLD, NOT_EQUAL, GetPlayerState(stationOwner, PLAYER_STATE_RESOURCE_GOLD))
call TriggerRegisterPlayerStateEvent(detector, stationOwner, PLAYER_STATE_RESOURCE_LUMBER, NOT_EQUAL, GetPlayerState(stationOwner, PLAYER_STATE_RESOURCE_LUMBER))
*/
set plug = FirstOfGroup(BuildSystemEx.dataBase[4].group[stationHandle])
call DockingSystem.undock(plug)
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueBuildOrderById(plug, temp.unitId, BuildSystemEx.dataBase[2].real[stationHandle], BuildSystemEx.dataBase[3].real[stationHandle]) then
set thistype.currentTemp = temp
call ForGroup(BuildSystemEx.dataBase[4].group[stationHandle], function thistype.onSpellCastUndock)
call ShowUnit(plug, true)
call PauseUnit(plug, false)
// Reissue the order...
// call IssueBuildOrderById(plug, temp.unitId, BuildSystemEx.dataBase[2].real[stationHandle], BuildSystemEx.dataBase[3].real[stationHandle])
set plugHandle = GetHandleId(plug)
// Let the builder point at the station ...
set BuildSystemEx.dataBase[5].unit[plugHandle] = station
set BuildSystemEx.dataBase[6].integer[plugHandle] = temp
call SetUnitX(plug, BuildSystemEx.dataBase[2].real[stationHandle])
call SetUnitY(plug, BuildSystemEx.dataBase[3].real[stationHandle])
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
loop
exitwhen plug == null
call GroupRemoveUnit(BuildSystemEx.dataBase[4].group[stationHandle], plug)
set plug = FirstOfGroup(BuildSystemEx.dataBase[4].group[stationHandle])
endloop
call SetUnitInvulnerable(station, false)
call SetUnitX(station, BuildSystemEx.dataBase[2].real[stationHandle])
call SetUnitY(station, BuildSystemEx.dataBase[3].real[stationHandle])
call ShowUnit(station, true)
call DestroyGroup(BuildSystemEx.dataBase[4].group[stationHandle])
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
set station = null
set plug = null
return
endif
elseif constructType == BuildSystemEx.upgrade then
set BuildSystemEx.dataBase[7].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[8].group[stationHandle] = CreateGroup()
// Get the number of available plugs...
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0 or (plugCount >= temp.count)
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
call GroupAddUnit(BuildSystemEx.dataBase[8].group[stationHandle], plug)
set plugCount = plugCount + 1
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Upgrading to " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
call DestroyGroup(BuildSystemEx.dataBase[2].group[stationHandle])
call BuildSystemEx.dataBase[7].player.remove(stationHandle)
call BuildSystemEx.dataBase[8].group.remove(stationHandle)
set station = null
set plug = null
return
endif
call UnitRemoveAbility(station, handler.abilHolder)
call UnitAddAbility(station, handler.abilHolder)
call PauseUnit(station, true)
call IssueImmediateOrderById(station, 851972)
call PauseUnit(station, false)
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueImmediateOrderById(station, temp.unitId) then
set thistype.currentTemp = temp
call ForGroup(BuildSystemEx.dataBase[8].group[stationHandle], function thistype.onSpellCastUndock)
set BuildSystemEx.dataBase[9].integer[stationHandle] = temp
set BuildSystemEx.dataBase[10].integer[stationHandle] = stationId
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
loop
set plug = FirstOfGroup(BuildSystemEx.dataBase[8].group[stationHandle])
exitwhen plug == null
call GroupRemoveUnit(BuildSystemEx.dataBase[8].group[stationHandle], plug)
endloop
call DestroyGroup(BuildSystemEx.dataBase[8].group[stationHandle])
call BuildSystemEx.dataBase[7].player.remove(stationHandle)
call BuildSystemEx.dataBase[8].group.remove(stationHandle)
set station = null
set plug = null
return
endif
elseif constructType == BuildSystemEx.train then
/*
set BuildSystemEx.dataBase[1].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[2].group[stationHandle] = CreateGroup()
// Get the number of available plugs...
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0 or (plugCount >= temp.count)
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
call GroupAddUnit(BuildSystemEx.dataBase[2].group[stationHandle], plug)
set plugCount = plugCount + 1
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Upgrading to " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
call DestroyGroup(BuildSystemEx.dataBase[2].group[stationHandle])
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].group.remove(stationHandle)
set station = null
set plug = null
return
endif
call UnitRemoveAbility(station, handler.abilHolder)
call UnitAddAbility(station, handler.abilHolder)
call PauseUnit(station, true)
call IssueImmediateOrderById(station, 851972)
call PauseUnit(station, false)
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueImmediateOrderById(station, temp.unitId) then
set thistype.currentTemp = temp
call ForGroup(BuildSystemEx.dataBase[2].group[stationHandle], function thistype.onSpellCastUndock)
set BuildSystemEx.dataBase[3].integer[stationHandle] = temp
set BuildSystemEx.dataBase[4].integer[stationHandle] = stationId
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
loop
set plug = FirstOfGroup(BuildSystemEx.dataBase[2].group[stationHandle])
exitwhen plug == null
call GroupRemoveUnit(BuildSystemEx.dataBase[2].group[stationHandle], plug)
endloop
call DestroyGroup(BuildSystemEx.dataBase[2].group[stationHandle])
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].group.remove(stationHandle)
set station = null
set plug = null
return
endif
*/
endif
set station = null
endmethod
private static method initVar takes nothing returns nothing
set thistype.holderTable = Table.create()
set thistype.subRefTable = Table.create()
endmethod
private static method initListener takes nothing returns nothing
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onSpellCast)
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
call thistype.initListener()
endmethod
implement Initializer
endstruct
struct BuildSystem extends array
implement Alloc
private static constant integer DEFAULT_WORKER_COUNT = 4
private static constant real DEFAULT_WORKER_DIST = 45.
private static constant real DEFAULT_WORKER_HEIGHT = 30.
private static constant real DEFAULT_WORKER_RAD = 0.
private static constant real DEFAULT_DETECT_DIST = 250.
private static constant boolean DEFAULT_CONSUMES_WORKER = true
// These store the unit types which have been passed into the BuildSystem
private static Table unitTypeList = 0
// This stores the owner of the unit whose unit type has been registered
private static Table unitOwner = 0
// This stores the flag of the unit whether it triggered a unit death
// event or not
private static Table unitDeathFlag = 0
// This stores the flag for all stations...
private static Table stationFlag = 0
// Main members. Can be read, but not written.
readonly integer workerId
readonly integer buildingId
private trigger onPredock
private trigger onDock
private trigger onUndock
private IntegerList constructList
private IntegerList upgradeList
private IntegerList trainList
integer workerCount
real workerHeight
real workerDist
real workerStartRad
real workerDetectDist
boolean workerConsumed
static method create takes integer workerId, integer buildingId returns thistype
local thistype result = BuildSystemEx.stationHolder.integer[buildingId]
if result == 0 then
set result = thistype.allocate()
set result.workerId = workerId
set result.buildingId = buildingId
set result.constructList = IntegerList.create()
set result.upgradeList = IntegerList.create()
set result.trainList = IntegerList.create()
set result.workerCount = DEFAULT_WORKER_COUNT
set result.workerHeight = DEFAULT_WORKER_HEIGHT
set result.workerDist = DEFAULT_WORKER_DIST
set result.workerStartRad = DEFAULT_WORKER_RAD
set result.workerDetectDist = DEFAULT_DETECT_DIST
set result.workerConsumed = DEFAULT_CONSUMES_WORKER
set result.onPredock = CreateTrigger()
set result.onDock = CreateTrigger()
set result.onUndock = CreateTrigger()
set BuildSystemEx.stationHolder.integer[buildingId] = result
endif
return result
endmethod
private static method precheckAbil takes integer abilHolder returns boolean
return BuildSystemEx.constructType.integer.has(abilHolder)
endmethod
private static method addUnitType takes integer unitId returns nothing
if unitId == 0 then
debug call printError("thistype.addUnitType: Invalid unit type!")
return
endif
if not thistype.unitTypeList.integer.has(unitId) then
set thistype.unitTypeList.integer[unitId] = IntegerList(thistype.unitTypeList.integer[0]).push(unitId).last
endif
endmethod
private static method isUnitPhysical takes unit u returns boolean
return (not IsUnitType(u, UNIT_TYPE_SUMMONED)) and (not IsUnitIllusion(u))
endmethod
method addConstructAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addConstructAbil: Ability type was already defined.")
return
endif
call this.constructList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.construct
endmethod
method addUpgradeAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addUpgradeAbil: Ability type was already defined.")
return
endif
call this.upgradeList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.upgrade
endmethod
method addTrainAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addTrainAbil: Ability type was already defined.")
return
endif
call this.trainList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.train
endmethod
method addConstructUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.construct then
debug call printError("thistype.addConstructUnit: Ability id is not of type construct.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method addUpgradeUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.upgrade then
debug call printError("thistype.addUpgradeUnit: Ability id is not of type upgrade.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method addTrainUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.train then
debug call printError("thistype.addTrainUnit: Ability id is not of type train.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method setOnDockEvent takes integer dockEvent, code whichHandler returns nothing
if dockEvent == EVENT_ON_PRE_DOCK then
call DestroyTrigger(this.onPredock)
set this.onPredock = CreateTrigger()
call TriggerAddCondition(this.onPredock, Condition(whichHandler))
elseif dockEvent == EVENT_ON_DOCK then
call DestroyTrigger(this.onDock)
set this.onDock = CreateTrigger()
call TriggerAddCondition(this.onDock, Condition(whichHandler))
elseif dockEvent == EVENT_ON_UNDOCK then
call DestroyTrigger(this.onUndock)
set this.onUndock = CreateTrigger()
call TriggerAddCondition(this.onUndock, Condition(whichHandler))
debug else
debug call printError("thistype.setOnDockEvent: Unrecognized dock event!")
endif
endmethod
private method initStation takes unit station returns nothing
local integer i = 0
local integer stationHandle = GetHandleId(station)
local real pSlice = 2*bj_PI/(this.workerCount)
local real stationX = GetUnitX(station)
local real stationY = GetUnitY(station)
if not thistype.stationFlag.boolean.has(stationHandle) then
set thistype.stationFlag.boolean[stationHandle] = false
call DockingSystem.createStation(station, this.workerDetectDist)
loop
exitwhen i >= this.workerCount
call DockingSystem.addSocket(station, /*
*/stationX + this.workerDist*Cos(I2R(i)*pSlice + this.workerStartRad),/*
*/stationY + this.workerDist*Sin(I2R(i)*pSlice + this.workerStartRad),/*
*/this.workerHeight, (I2R(i)*pSlice + this.workerStartRad + (bj_PI/2))/*
*/ * bj_RADTODEG)
set i = i + 1
endloop
endif
endmethod
private method removeStation takes unit station returns nothing
local integer stationHandle = GetHandleId(station)
if thistype.stationFlag.boolean.has(stationHandle) then
call thistype.stationFlag.boolean.remove(stationHandle)
call DockingSystem.terminateStation(station)
endif
endmethod
/*
-----------------------------------
| Handler methods |
-----------------------------------
*/
private static method onConstructStart takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local SubBuildList buildList = BuildSystemEx.dataBase[6].integer[buildingId]
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
// If building is a station...
if temp != 0 then
call temp.removeStation(building)
endif
if BuildSystemEx.dataBase[5].unit.has(builderHandle) then
// Move data reference to the building currently being built...
set station = BuildSystemEx.dataBase[5].unit[builderHandle]
set BuildSystemEx.dataBase[5].unit[buildingHandle] = station
set BuildSystemEx.dataBase[6].integer[buildingHandle] = BuildSystemEx.dataBase[6].integer[builderHandle]
call BuildSystemEx.dataBase[5].unit.remove(builderHandle)
call BuildSystemEx.dataBase[6].integer.remove(builderHandle)
// Correct the incremental value...
call BuildSystemEx.decrement(buildingOwner, buildingId)
if buildList.consumesWorker then
call UnitAddAbility(builder, 'Aloc')
endif
endif
set builder = null
set building = null
endmethod
private static method onConstructCancel takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station
local unit plug
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local integer stationHandle
local real stationX
local real stationY
local player stationOwner
local group stationGrp
local trigger trig
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
local SubBuildList buildList = 0
// Triggered by removal
if GetTriggerEventId() == null then
set building = GetIndexedUnit()
set builder = GetBuilder(building)
set buildingId = GetUnitTypeId(building)
set buildingHandle = GetHandleId(building)
set builderHandle = GetHandleId(builder)
endif
if BuildSystemEx.dataBase[5].unit.has(buildingHandle) then
set station = BuildSystemEx.dataBase[5].unit[buildingHandle]
set stationHandle = GetHandleId(station)
set stationOwner = BuildSystemEx.dataBase[1].player[stationHandle]
set stationX = BuildSystemEx.dataBase[2].real[stationHandle]
set stationY = BuildSystemEx.dataBase[3].real[stationHandle]
set stationGrp = BuildSystemEx.dataBase[4].group[stationHandle]
set buildList = BuildSystemEx.dataBase[6].integer[buildingHandle]
call BuildSystemEx.dataBase[5].unit.remove(buildingHandle)
call BuildSystemEx.dataBase[6].integer.remove(buildingHandle)
if buildList.consumesWorker then
call UnitRemoveAbility(builder, 'Aloc')
endif
call SetUnitInvulnerable(station, false)
call SetUnitX(station, stationX)
call SetUnitY(station, stationY)
call ShowUnit(station, true)
set plug = FirstOfGroup(stationGrp)
loop
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, stationX, stationY)
call PauseUnit(plug, false)
if GetLocalPlayer() == stationOwner then
call SelectUnit(plug, true)
endif
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(stationGrp, plug)
set plug = FirstOfGroup(stationGrp)
endloop
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
call DestroyGroup(stationGrp)
set station = null
set stationGrp = null
endif
set builder = null
set building = null
endmethod
private static method onConstructFinish takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station = null
local unit plug
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local integer stationHandle
local real stationX
local real stationY
local player stationOwner
local group stationTempGrp = null
local group stationGrp
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
local SubBuildList buildList = 0
if BuildSystemEx.dataBase[5].unit.has(buildingHandle) then
set station = BuildSystemEx.dataBase[5].unit[buildingHandle]
set stationHandle = GetHandleId(station)
set stationOwner = BuildSystemEx.dataBase[1].player[stationHandle]
set stationX = BuildSystemEx.dataBase[2].real[stationHandle]
set stationY = BuildSystemEx.dataBase[3].real[stationHandle]
set stationGrp = BuildSystemEx.dataBase[4].group[stationHandle]
set buildList = BuildSystemEx.dataBase[6].integer[stationHandle]
set stationTempGrp = CreateGroup()
call CopyGroup(stationTempGrp, stationGrp)
endif
call thistype.onConstructCancel()
if station != null then
set plug = FirstOfGroup(stationTempGrp)
loop
exitwhen plug == null
call GroupRemoveUnit(stationTempGrp, plug)
if buildList.consumesWorker then
call RemoveUnit(plug)
endif
set plug = FirstOfGroup(stationTempGrp)
endloop
call RemoveUnit(station)
endif
if stationTempGrp != null then
call DestroyGroup(stationTempGrp)
endif
if temp != 0 then
call temp.initStation(building)
endif
set stationTempGrp = null
set station = null
set stationGrp = null
set builder = null
set building = null
endmethod
/*
------------------
| |
| Upgrades |
| |
------------------
*/
private static method onUpgradeStart takes nothing returns nothing
local unit building = GetTriggerUnit()
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
if temp != 0 then
call DockingSystem.undockAll(building)
endif
if BuildSystemEx.dataBase[9].integer.has(buildingHandle) then
// Raise a flag telling the system that the unit is upgrading.
set BuildSystemEx.dataBase[11].boolean[buildingHandle] = true
endif
set building = null
endmethod
private static method onUpgradeCancel takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit plug
local real buildingX = GetUnitX(building)
local real buildingY = GetUnitY(building)
local group plugGroup
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer upgradeId
local SubBuildList buildList
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
if BuildSystemEx.dataBase[9].integer.has(buildingHandle) then
set plugGroup = BuildSystemEx.dataBase[8].group[buildingHandle]
set buildList = SubBuildList(BuildSystemEx.dataBase[9].integer[buildingHandle])
set upgradeId = buildList.unitId
call BuildSystemEx.decrement(buildingOwner, upgradeId)
// Show the units...
set plug = FirstOfGroup(plugGroup)
loop
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, buildingX, buildingY)
call PauseUnit(plug, false)
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(plugGroup, plug)
set plug = FirstOfGroup(plugGroup)
endloop
call DestroyGroup(plugGroup)
set plugGroup = null
call BuildSystemEx.dataBase[7].player.remove(buildingHandle)
call BuildSystemEx.dataBase[8].group.remove(buildingHandle)
call BuildSystemEx.dataBase[9].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[10].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[11].boolean.remove(buildingHandle)
endif
set building = null
endmethod
private static method onUpgradeFinish takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit plug
local real buildingX = GetUnitX(building)
local real buildingY = GetUnitY(building)
local group plugGroup
local group plugGroupCopy = null
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer upgradeId
local integer lastBuildingId
local SubBuildList buildList
local thistype temp
if BuildSystemEx.dataBase[3].integer.has(buildingHandle) then
set plugGroup = BuildSystemEx.dataBase[2].group[buildingHandle]
set buildList = SubBuildList(BuildSystemEx.dataBase[3].integer[buildingHandle])
set upgradeId = buildList.unitId
set lastBuildingId = BuildSystemEx.dataBase[4].integer[buildingHandle]
set temp = BuildSystemEx.stationHolder.integer[lastBuildingId]
set plugGroupCopy = CreateGroup()
call CopyGroup(plugGroupCopy, plugGroup)
if temp != 0 then
call temp.removeStation(building)
// Outsource it to transformation.
/*
if thistype.unitTypeList.has(lastBuildingId) then
call BuildSystemEx.decrement(buildingOwner, lastBuildingId)
endif
*/
endif
// Counter the effects of decrement when calling onUpgradeCancel...
call BuildSystemEx.increment(buildingOwner, buildingId)
endif
call thistype.onUpgradeCancel()
set plug = FirstOfGroup(plugGroupCopy)
loop
exitwhen plug == null
call GroupRemoveUnit(plugGroupCopy, plug)
if buildList.consumesWorker then
call RemoveUnit(plug)
endif
set plug = FirstOfGroup(plugGroupCopy)
endloop
if plugGroupCopy != null then
call DestroyGroup(plugGroupCopy)
endif
set plugGroupCopy = null
set building = null
endmethod
private static method onUnitEnter takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
// Unit is a station.
if inst != 0 then
call inst.initStation(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.increment(uOwner, unitId)
set thistype.unitOwner.player[uHandle] = uOwner
set thistype.unitDeathFlag.boolean[uHandle] = false
endif
set u = null
endmethod
private static method onUnitExit takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call inst.removeStation(u)
endif
// Unit must have undergone construction when it was removed...
if BuildSystemEx.dataBase[5].unit.has(uHandle) then
debug call BJDebugMsg("Unit was undergoing construction!")
call thistype.onConstructCancel()
endif
if thistype.unitTypeList.integer.has(unitId) then
if not thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.decrement(uOwner, unitId)
endif
call thistype.unitOwner.player.remove(uHandle)
call thistype.unitDeathFlag.boolean.remove(uHandle)
endif
set u = null
endmethod
private static method onUnitDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if GetTriggerEventId() == null then
// Called on reincarnation
set u = GetEventUnit()
endif
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
if GetNumberOfOccupiedSockets(u) != 0 then
call DockingSystem.undockAll(u)
endif
endif
// Unit must have undergone construction when it was destroyed...
if BuildSystemEx.dataBase[5].unit.has(uHandle) then
call thistype.onConstructCancel()
endif
if thistype.unitTypeList.integer.has(unitId) then
if not thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.decrement(uOwner, unitId)
set thistype.unitDeathFlag.boolean[uHandle] = true
endif
endif
set u = null
endmethod
private static method onUnitChangeOwner takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call DockingSystem.undockAll(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.decrement(thistype.unitOwner.player[uHandle], unitId)
set thistype.unitOwner.player[uHandle] = uOwner
call BuildSystemEx.increment(thistype.unitOwner.player[uHandle], unitId)
endif
set u = null
endmethod
private static method onUnitRevive takes nothing returns nothing
local unit u = GetEventUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if thistype.unitTypeList.integer.has(unitId) then
if thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.increment(uOwner, unitId)
set thistype.unitDeathFlag.boolean[uHandle] = false
endif
endif
set u = null
endmethod
private static method onUnitTransform takes nothing returns nothing
local unit u = GetEventUnit()
local integer prevUnitId = GetEventTransformType()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[prevUnitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call inst.removeStation(u)
endif
if thistype.unitTypeList.integer.has(GetEventTransformType()) then
call BuildSystemEx.decrement(uOwner, GetEventTransformType())
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.increment(uOwner, unitId)
endif
set u = null
endmethod
private static method onPreDockHandler takes nothing returns nothing
local unit station = GetStation()
local unit plug = GetPlug()
local integer stationId = GetUnitTypeId(station)
local integer stationHandle = GetHandleId(station)
local integer plugId = GetUnitTypeId(plug)
local integer plugHandle = GetHandleId(plug)
local player plugOwner = GetOwningPlayer(plug)
local thistype temp = BuildSystemEx.stationHolder.integer[stationId]
// Nothing to do here...
if (temp == 0) then
// Don't interfere with other stations...
set plug = null
set station = null
return
endif
if (temp.workerId != plugId) then
call InterruptDocking()
set plug = null
set station = null
return
endif
if (GetOwningPlayer(plug) != GetOwningPlayer(station)) then
call InterruptDocking()
call SimError(plugOwner, "Cannot dock into a station owned by another player!")
set plug = null
set station = null
endif
// Unit is being upgraded. Don't allow docking!
if BuildSystemEx.dataBase[7].boolean.has(stationHandle) then
call InterruptDocking()
call SimError(plugOwner, "Upgrade is in progress... you cannot dock at this moment.")
set plug = null
set station = null
return
endif
call ConditionalTriggerExecute(temp.onPredock)
set plug = null
set station = null
endmethod
private static method onDockHandler takes nothing returns nothing
local thistype temp = BuildSystemEx.stationHolder.integer[GetUnitTypeId(GetStation())]
if temp != 0 then
call ConditionalTriggerExecute(temp.onDock)
endif
endmethod
private static method onUndockHandler takes nothing returns nothing
local thistype temp = BuildSystemEx.stationHolder.integer[GetUnitTypeId(GetStation())]
if temp != 0 then
call ConditionalTriggerExecute(temp.onUndock)
endif
endmethod
private static method initVar takes nothing returns nothing
set thistype.unitTypeList = Table.create()
set thistype.unitOwner = Table.create()
set thistype.unitDeathFlag = Table.create()
set thistype.stationFlag = Table.create()
set thistype.unitTypeList.integer[0] = IntegerList.create()
endmethod
private static method initListener takes nothing returns nothing
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function thistype.onConstructStart)
//call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function thistype.onConstructCancel)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.onConstructFinish)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_START, function thistype.onUpgradeStart)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL, function thistype.onUpgradeCancel)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH, function thistype.onUpgradeFinish)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onUnitDeath)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CHANGE_OWNER, function thistype.onUnitChangeOwner)
call RegisterUnitIndexEvent(Condition(function thistype.onUnitEnter), EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onUnitExit), EVENT_UNIT_DEINDEX)
call RegisterNativeEvent(EVENT_ON_REINCARNATION_START, function thistype.onUnitDeath)
call RegisterNativeEvent(EVENT_ON_RESURRECTION, function thistype.onUnitRevive)
call RegisterNativeEvent(EVENT_ON_REINCARNATION_FINISH, function thistype.onUnitRevive)
call RegisterNativeEvent(EVENT_ON_TRANSFORM, function thistype.onUnitTransform)
call RegisterNativeEvent(EVENT_ON_PRE_DOCK, function thistype.onPreDockHandler)
call RegisterNativeEvent(EVENT_ON_DOCK, function thistype.onDockHandler)
call RegisterNativeEvent(EVENT_ON_UNDOCK, function thistype.onUndockHandler)
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
call thistype.initListener()
endmethod
static method onGameStart takes nothing returns nothing
local integer i = 1
local player p = Player(i - 1)
local IntegerListItem firstIter = IntegerList(thistype.unitTypeList.integer[0]).first
local IntegerListItem iter = firstIter
loop
loop
exitwhen iter == 0
set BuildSystemEx.unitTypeLimit[i].integer[iter.data] = 0
call SetPlayerTechMaxAllowed(p, iter.data, BuildSystemEx.unitTypeLimit[i].integer[iter.data])
set iter = iter.next
endloop
set iter = firstIter
exitwhen i >= bj_MAX_PLAYER_SLOTS
set p = Player(i)
set i = i + 1
endloop
endmethod
implement Initializer
endstruct
// This function is required. Don't edit this. (functionally private)
function InitTrig_CustomBuildSystem takes nothing returns nothing
call ForForce(bj_FORCE_PLAYER[0], function BuildSystem.onGameStart)
endfunction
endlibrary
Oops, didn't realize I already had a second WIP.
Now, here are some more WIP's (of course, all models found therein are not set in stone)
View attachment 300638
Units before creation of another unit...
View attachment 300639
Units after creation of unit...
library CustomBuildSystem /*
*/ requires /*
Legend:
#? -> optional resource
# -> required resource
*||------------------------||*
*/ DockingSystem /*
#? SmartTrack
#? Table
-> Spellbound
link: https://www.hiveworkshop.com/threads/dockingsystem-v1-05-2.299959/#resource-78986
*||------------------------||*
*||------------------------||*
*/ Table /*
-> Bribe
link: https://www.hiveworkshop.com/threads/snippet-new-table.188084/
*||------------------------||*
*||------------------------||*
*/ ListT /*
# Table
# Alloc
-> Bannar
link: https://www.hiveworkshop.com/threads/containers-list-t.249011/
*||------------------------||*
*||------------------------||*
*/ Alloc /*
-> Sevion
link: https://hiveworkshop.com/threads/snippet-alloc.192348/
*||------------------------||*
*||------------------------||*
*/ UnitDex /*
-> TriggerHappy
link: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
*||------------------------||*
*||------------------------||*
*/ RegisterPlayerUnitEvent /*
# RegisterNativeEvent
-> Bannar
link: https://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*||------------------------||*
*||------------------------||*
*/ UnitEventsEx /*
# UnitDex
# RegisterPlayerUnitEvent
#? ListT
#? WorldBounds
-> Spellbound
link: https://www.hiveworkshop.com/threads/vjass-version-of-gui-unit-event.306289/#post-3270559
*||------------------------||*
*/ SimError /*
-> Vexorian
link: http://www.wc3c.net/showthread.php?t=101260
*||------------------------||*
*||------------------------||*
*/ BuilderTrace /*
# UnitDex
# Table
# OrderIndex
-> MyPad
link: Not yet defined...
*/
native GetUnitGoldCost takes integer unitid returns integer
native GetUnitWoodCost takes integer unitid returns integer
//! runtextmacro DEFINE_LIST("", "PlayerList", "player")
//! runtextmacro DEFINE_LIST("", "UnitGroupList", "group")
globals
private group copyGroup_tempGroup = null
endglobals
private function OnCopyGroup takes nothing returns nothing
call GroupAddUnit(copyGroup_tempGroup, GetEnumUnit())
endfunction
private function CopyGroup takes group whichGroup, group tempGroup returns nothing
set copyGroup_tempGroup = whichGroup
call GroupClear(whichGroup)
call ForGroup(tempGroup, function OnCopyGroup)
endfunction
static if DEBUG_MODE then
private function printError takes string msg returns nothing
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cffff0000Error:|r |cffffcc00" + msg + "|r")
endfunction
endif
private module Initializer
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
private struct BuildSystemEx extends array
readonly static Table constructType = 0
readonly static Table stationHolder = 0
readonly static TableArray unitTypeLimit = 0
readonly static TableArray dataBase = 0
static method operator construct takes nothing returns integer
return 1
endmethod
static method operator upgrade takes nothing returns integer
return 2
endmethod
static method operator train takes nothing returns integer
return 3
endmethod
static method getConstructType takes integer abilId returns integer
return thistype.constructType.integer[abilId]
endmethod
static method increment takes player p, integer unitId returns nothing
local integer pIndex = GetPlayerId(p) + 1
set thistype.unitTypeLimit[pIndex].integer[unitId] = thistype.unitTypeLimit[pIndex].integer[unitId] + 1
call SetPlayerTechMaxAllowed(p, unitId, thistype.unitTypeLimit[pIndex].integer[unitId])
endmethod
static method decrement takes player p, integer unitId returns nothing
local integer pIndex = GetPlayerId(p) + 1
set thistype.unitTypeLimit[pIndex].integer[unitId] = thistype.unitTypeLimit[pIndex].integer[unitId] - 1
call SetPlayerTechMaxAllowed(p, unitId, thistype.unitTypeLimit[pIndex].integer[unitId])
endmethod
private static method init takes nothing returns nothing
set thistype.stationHolder = Table.create()
set thistype.constructType = Table.create()
set thistype.dataBase = TableArray[15]
set thistype.unitTypeLimit = TableArray[bj_MAX_PLAYER_SLOTS + 1]
endmethod
implement Initializer
endstruct
private struct SubBuildList extends array
implement Alloc
// Ability is unique, so...
private static Table abilityTable = 0
readonly integer unitId
readonly integer abilId
readonly integer count
readonly boolean consumesWorker
static method getInstance takes integer abilId returns thistype
return thistype.abilityTable.integer[abilId]
endmethod
static method create takes integer unitId, integer abilId, boolean consumesWorker, integer count returns thistype
local thistype result = thistype.abilityTable.integer[abilId]
if result == 0 then
set result = thistype.allocate()
set result.unitId = unitId
set result.abilId = abilId
set result.count = count
set result.consumesWorker = consumesWorker
set thistype.abilityTable.integer[abilId] = result
endif
return result
endmethod
private static method initVar takes nothing returns nothing
set thistype.abilityTable = Table.create()
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
endmethod
implement Initializer
endstruct
private struct BuildList extends array
implement Alloc
private static constant player NEUTRAL = Player(PLAYER_NEUTRAL_PASSIVE)
private static Table holderTable = 0
private static Table subRefTable = 0
private static SubBuildList currentTemp = 0
private integer abilHolder
private IntegerList subList
static method create takes integer unitId, integer abilId, integer abilHolder, boolean consumesWorker, integer count returns thistype
local thistype result = thistype.holderTable.integer[abilHolder]
local SubBuildList temp = 0
if result == 0 then
set result = thistype.allocate()
set result.subList = IntegerList.create()
set result.abilHolder = abilHolder
set thistype.holderTable.integer[abilHolder] = result
endif
set temp = SubBuildList.getInstance(abilId)
if temp == 0 then
set temp = SubBuildList.create(unitId, abilId, consumesWorker, count)
call result.subList.push(temp)
set thistype.subRefTable.integer[temp] = result
endif
return result
endmethod
private static method onSpellCastHide takes nothing returns nothing
local unit enum = GetEnumUnit()
call SetUnitInvulnerable(enum, true)
if thistype.currentTemp.consumesWorker then
call SetUnitUseFood(enum, false)
endif
call PauseUnit(enum, true)
call ShowUnit(enum, false)
set enum = null
endmethod
private static method onSpellCastUndock takes nothing returns nothing
call DockingSystem.undock(GetEnumUnit())
call thistype.onSpellCastHide()
endmethod
private static method onSpellCast takes nothing returns nothing
local unit station = GetTriggerUnit()
local unit plug
local BuildSystem whichBuild
local SubBuildList temp = SubBuildList.getInstance(GetSpellAbilityId())
local thistype handler = thistype.subRefTable.integer[temp]
local TableArray trainList
local integer constructType = BuildSystemEx.getConstructType(handler.abilHolder)
local integer stationHandle = GetHandleId(station)
local integer stationId = GetUnitTypeId(station)
local integer plugHandle
local integer plugCount = 0
local IntegerListItem iter
local IntegerListItem iter2
local player stationOwner = GetOwningPlayer(station)
local group grp
set whichBuild = BuildSystem(BuildSystemEx.stationHolder.integer[stationId])
if constructType == BuildSystemEx.construct then
set BuildSystemEx.dataBase[1].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[2].real[stationHandle] = GetUnitX(station)
set BuildSystemEx.dataBase[3].real[stationHandle] = GetUnitY(station)
set BuildSystemEx.dataBase[4].group[stationHandle] = CreateGroup()
set grp = CreateGroup()
// Get the number of available plugs...
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
// Remove the unit from the station
call DockingSystem.undock(plug)
call GroupAddUnit(grp, plug)
if (plugCount < temp.count) then
call GroupAddUnit(BuildSystemEx.dataBase[4].group[stationHandle], plug)
set plugCount = plugCount + 1
endif
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Construction of " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
// Redock the units...
set plug = FirstOfGroup(grp)
loop
exitwhen plug == null
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
endloop
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
call DestroyGroup(grp)
call DestroyGroup(BuildSystemEx.dataBase[4].group[stationHandle])
set grp = null
set station = null
set plug = null
return
endif
call ShowUnit(station, false)
call SetUnitX(station, WorldBounds.minX)
call SetUnitY(station, WorldBounds.minY)
call SetUnitInvulnerable(station, true)
set plug = FirstOfGroup(BuildSystemEx.dataBase[4].group[stationHandle])
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueBuildOrderById(plug, temp.unitId, BuildSystemEx.dataBase[2].real[stationHandle], BuildSystemEx.dataBase[3].real[stationHandle]) then
set thistype.currentTemp = temp
call ForGroup(BuildSystemEx.dataBase[4].group[stationHandle], function thistype.onSpellCastUndock)
call ShowUnit(plug, true)
call PauseUnit(plug, false)
set plugHandle = GetHandleId(plug)
// Let the builder point at the station ...
set BuildSystemEx.dataBase[5].unit[plugHandle] = station
set BuildSystemEx.dataBase[6].integer[plugHandle] = temp
call SetUnitX(plug, BuildSystemEx.dataBase[2].real[stationHandle])
call SetUnitY(plug, BuildSystemEx.dataBase[3].real[stationHandle])
// The group is unnecessary at this point.
call DestroyGroup(grp)
set grp = null
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
loop
exitwhen plug == null
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
endloop
call SetUnitInvulnerable(station, false)
call SetUnitX(station, BuildSystemEx.dataBase[2].real[stationHandle])
call SetUnitY(station, BuildSystemEx.dataBase[3].real[stationHandle])
call ShowUnit(station, true)
call DestroyGroup(BuildSystemEx.dataBase[4].group[stationHandle])
call DestroyGroup(grp)
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
set grp = null
set station = null
set plug = null
return
endif
elseif constructType == BuildSystemEx.upgrade then
set BuildSystemEx.dataBase[7].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[8].group[stationHandle] = CreateGroup()
set grp = BuildSystemEx.dataBase[8].group[stationHandle]
// Get the number of available plugs...
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0 or (plugCount >= temp.count)
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
call DockingSystem.undock(plug)
call GroupAddUnit(BuildSystemEx.dataBase[8].group[stationHandle], plug)
set plugCount = plugCount + 1
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Upgrading to " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
set plug = FirstOfGroup(grp)
loop
exitwhen plug == null
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
endloop
call DestroyGroup(BuildSystemEx.dataBase[8].group[stationHandle])
call BuildSystemEx.dataBase[7].player.remove(stationHandle)
call BuildSystemEx.dataBase[8].group.remove(stationHandle)
set grp = null
set station = null
set plug = null
return
endif
call UnitRemoveAbility(station, handler.abilHolder)
call UnitAddAbility(station, handler.abilHolder)
call PauseUnit(station, true)
call IssueImmediateOrderById(station, 851972)
call PauseUnit(station, false)
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueImmediateOrderById(station, temp.unitId) then
set thistype.currentTemp = temp
call ForGroup(BuildSystemEx.dataBase[8].group[stationHandle], function thistype.onSpellCastUndock)
set BuildSystemEx.dataBase[9].integer[stationHandle] = temp
set BuildSystemEx.dataBase[10].integer[stationHandle] = stationId
set grp = null
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
loop
exitwhen plug == null
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
endloop
call DestroyGroup(grp)
call BuildSystemEx.dataBase[7].player.remove(stationHandle)
call BuildSystemEx.dataBase[8].group.remove(stationHandle)
set grp = null
set station = null
set plug = null
return
endif
elseif constructType == BuildSystemEx.train then
if not BuildSystemEx.dataBase[12].player.has(stationHandle) then
set BuildSystemEx.dataBase[12].player[stationHandle] = stationOwner
set BuildSystemEx.dataBase[13].integer[stationHandle] = 0
endif
set grp = CreateGroup()
loop
exitwhen GetNumberOfOccupiedSockets(station) == 0 or (plugCount >= temp.count)
set plug = GetSocketPlug(GetRandomSocketWithState(station, true))
call DockingSystem.undock(plug)
call GroupAddUnit(grp, plug)
set plugCount = plugCount + 1
endloop
if plugCount < temp.count then
call SimError(stationOwner, "Upgrading to " + GetObjectName(temp.unitId) + " requires "/*
*/ + "at least " + I2S(temp.count) + " " + GetObjectName(whichBuild.workerId))
set plug = FirstOfGroup(grp)
loop
exitwhen plug == null
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
endloop
call DestroyGroup(grp)
if BuildSystemEx.dataBase[13].integer[stationHandle] == 0 then
call BuildSystemEx.dataBase[12].player.remove(stationHandle)
call BuildSystemEx.dataBase[13].integer.remove(stationHandle)
endif
set grp = null
set station = null
set plug = null
return
endif
call PauseUnit(station, true)
call IssueImmediateOrderById(station, 851972)
call PauseUnit(station, false)
call UnitRemoveAbility(station, handler.abilHolder)
call UnitAddAbility(station, handler.abilHolder)
// Using a counter mechanism
call BlzUnitDisableAbility(station, handler.abilHolder, false, false)
call BlzUnitHideAbility(station, handler.abilHolder, true)
call BuildSystemEx.increment(stationOwner, temp.unitId)
if IssueImmediateOrderById(station, temp.unitId) then
set thistype.currentTemp = temp
call ForGroup(grp, function thistype.onSpellCastUndock)
if not BuildSystemEx.dataBase[14].integer.has(stationHandle) then
set trainList = TableArray[3]
set trainList[1].integer[0] = IntegerList.create()
set trainList[2].integer[0] = IntegerList.create()
set trainList[1].integer[-2] = IntegerList.create()
set BuildSystemEx.dataBase[14].integer[stationHandle] = integer(trainList)
else
set trainList = BuildSystemEx.dataBase[14].integer[stationHandle]
endif
// Store the size().
set BuildSystemEx.dataBase[13].integer[stationHandle] = BuildSystemEx.dataBase[13].integer[stationHandle] + 1
if not trainList[1].integer.has(temp.unitId) then
set trainList[1].integer[temp.unitId] = UnitGroupList.create()
set trainList[2].integer[temp.unitId] = temp
call IntegerList(trainList[1].integer[0]).push(trainList[1].integer[temp.unitId])
call IntegerList(trainList[2].integer[0]).push(temp.unitId)
endif
call UnitGroupList(trainList[1].integer[temp.unitId]).push(grp)
if IntegerList(trainList[1].integer[-2]).find(handler.abilHolder) == 0 then
call IntegerList(trainList[1].integer[-2]).push(handler.abilHolder)
endif
set iter2 = IntegerList(trainList[1].integer[-2]).first
loop
exitwhen iter2 == 0
set iter = thistype(thistype.holderTable.integer[iter2.data]).subList.first
loop
exitwhen iter == 0
call BlzUnitDisableAbility(station, SubBuildList(iter.data).abilId, false, false)
call BlzUnitHideAbility(station, SubBuildList(iter.data).abilId, true)
set iter = iter.next
endloop
set iter2 = iter2.next
endloop
set grp = null
else
call BuildSystemEx.decrement(stationOwner, temp.unitId)
static if DEBUG_MODE then
call BJDebugMsg("Insufficient resources.")
else
call SimError(stationOwner, "Insufficient resources.")
endif
set plug = FirstOfGroup(grp)
loop
exitwhen plug == null
call DockingSystem.dock(plug, GetClosestSocketWithState(station, plug, false))
call GroupRemoveUnit(grp, plug)
set plug = FirstOfGroup(grp)
endloop
call DestroyGroup(grp)
if trainList[1].integer.has(-2) then
set iter2 = IntegerList(trainList[1].integer[-2]).first
loop
exitwhen iter2 == 0
set iter = thistype(thistype.holderTable.integer[iter2.data]).subList.first
loop
exitwhen iter == 0
call BlzUnitDisableAbility(station, SubBuildList(iter.data).abilId, false, false)
call BlzUnitHideAbility(station, SubBuildList(iter.data).abilId, true)
set iter = iter.next
endloop
set iter2 = iter2.next
endloop
endif
if BuildSystemEx.dataBase[13].integer[stationHandle] == 0 then
if BuildSystemEx.dataBase[14].integer.has(stationHandle) then
set trainList = BuildSystemEx.dataBase[14].integer[stationHandle]
if trainList[1].integer.has(0) then
call IntegerList(trainList[1].integer[0]).destroy()
endif
if trainList[2].integer.has(0) then
call IntegerList(trainList[2].integer[0]).destroy()
endif
if trainList[1].integer.has(-2) then
call IntegerList(trainList[1].integer[-2]).destroy()
endif
call trainList.destroy()
endif
call BuildSystemEx.dataBase[12].player.remove(stationHandle)
call BuildSystemEx.dataBase[13].integer.remove(stationHandle)
call BuildSystemEx.dataBase[14].integer.remove(stationHandle)
endif
set grp = null
set station = null
set plug = null
return
endif
endif
set station = null
endmethod
private static method initVar takes nothing returns nothing
set thistype.holderTable = Table.create()
set thistype.subRefTable = Table.create()
endmethod
private static method initListener takes nothing returns nothing
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onSpellCast)
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
call thistype.initListener()
endmethod
implement Initializer
endstruct
struct BuildSystem extends array
implement Alloc
private static constant integer DEFAULT_WORKER_COUNT = 4
private static constant real DEFAULT_WORKER_DIST = 45.
private static constant real DEFAULT_WORKER_HEIGHT = 30.
private static constant real DEFAULT_WORKER_RAD = 0.
private static constant real DEFAULT_DETECT_DIST = 250.
private static constant boolean DEFAULT_CONSUMES_WORKER = true
// These store the unit types which have been passed into the BuildSystem
private static Table unitTypeList = 0
// This stores the owner of the unit whose unit type has been registered
private static Table unitOwner = 0
// This stores the flag of the unit whether it triggered a unit death
// event or not
private static Table unitDeathFlag = 0
// This stores the flag for all stations...
private static Table stationFlag = 0
// Main members. Can be read, but not written.
readonly integer workerId
readonly integer buildingId
private trigger onPredock
private trigger onDock
private trigger onUndock
private IntegerList constructList
private IntegerList upgradeList
private IntegerList trainList
integer workerCount
real workerHeight
real workerDist
real workerStartRad
real workerDetectDist
boolean workerConsumed
static method create takes integer workerId, integer buildingId returns thistype
local thistype result = BuildSystemEx.stationHolder.integer[buildingId]
if result == 0 then
set result = thistype.allocate()
set result.workerId = workerId
set result.buildingId = buildingId
set result.constructList = IntegerList.create()
set result.upgradeList = IntegerList.create()
set result.trainList = IntegerList.create()
set result.workerCount = DEFAULT_WORKER_COUNT
set result.workerHeight = DEFAULT_WORKER_HEIGHT
set result.workerDist = DEFAULT_WORKER_DIST
set result.workerStartRad = DEFAULT_WORKER_RAD
set result.workerDetectDist = DEFAULT_DETECT_DIST
set result.workerConsumed = DEFAULT_CONSUMES_WORKER
set result.onPredock = CreateTrigger()
set result.onDock = CreateTrigger()
set result.onUndock = CreateTrigger()
set BuildSystemEx.stationHolder.integer[buildingId] = result
endif
return result
endmethod
private static method precheckAbil takes integer abilHolder returns boolean
return BuildSystemEx.constructType.integer.has(abilHolder)
endmethod
private static method addUnitType takes integer unitId returns nothing
if unitId == 0 then
debug call printError("thistype.addUnitType: Invalid unit type!")
return
endif
if not thistype.unitTypeList.integer.has(unitId) then
set thistype.unitTypeList.integer[unitId] = IntegerList(thistype.unitTypeList.integer[0]).push(unitId).last
endif
endmethod
private static method isUnitPhysical takes unit u returns boolean
return (not IsUnitType(u, UNIT_TYPE_SUMMONED)) and (not IsUnitIllusion(u))
endmethod
method addConstructAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addConstructAbil: Ability type was already defined.")
return
endif
call this.constructList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.construct
endmethod
method addUpgradeAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addUpgradeAbil: Ability type was already defined.")
return
endif
call this.upgradeList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.upgrade
endmethod
method addTrainAbil takes integer abilHolder returns nothing
if thistype.precheckAbil(abilHolder) then
debug call printError("thistype.addTrainAbil: Ability type was already defined.")
return
endif
call this.trainList.push(abilHolder)
set BuildSystemEx.constructType.integer[abilHolder] = BuildSystemEx.train
endmethod
method addConstructUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.construct then
debug call printError("thistype.addConstructUnit: Ability id is not of type construct.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method addUpgradeUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.upgrade then
debug call printError("thistype.addUpgradeUnit: Ability id is not of type upgrade.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method addTrainUnit takes integer unitId, integer abilId, integer abilHolder, integer count returns nothing
if BuildSystemEx.constructType.integer[abilHolder] != BuildSystemEx.train then
debug call printError("thistype.addTrainUnit: Ability id is not of type train.")
return
endif
call BuildList.create(unitId, abilId, abilHolder, this.workerConsumed, count)
call thistype.addUnitType(unitId)
endmethod
method setOnDockEvent takes integer dockEvent, code whichHandler returns nothing
if dockEvent == EVENT_ON_PRE_DOCK then
call DestroyTrigger(this.onPredock)
set this.onPredock = CreateTrigger()
call TriggerAddCondition(this.onPredock, Condition(whichHandler))
elseif dockEvent == EVENT_ON_DOCK then
call DestroyTrigger(this.onDock)
set this.onDock = CreateTrigger()
call TriggerAddCondition(this.onDock, Condition(whichHandler))
elseif dockEvent == EVENT_ON_UNDOCK then
call DestroyTrigger(this.onUndock)
set this.onUndock = CreateTrigger()
call TriggerAddCondition(this.onUndock, Condition(whichHandler))
debug else
debug call printError("thistype.setOnDockEvent: Unrecognized dock event!")
endif
endmethod
private method initStation takes unit station returns nothing
local integer i = 0
local integer stationHandle = GetHandleId(station)
local real pSlice = 2*bj_PI/(this.workerCount)
local real stationX = GetUnitX(station)
local real stationY = GetUnitY(station)
if not thistype.stationFlag.boolean.has(stationHandle) then
set thistype.stationFlag.boolean[stationHandle] = false
call DockingSystem.createStation(station, this.workerDetectDist)
loop
exitwhen i >= this.workerCount
call DockingSystem.addSocket(station, /*
*/stationX + this.workerDist*Cos(I2R(i)*pSlice + this.workerStartRad),/*
*/stationY + this.workerDist*Sin(I2R(i)*pSlice + this.workerStartRad),/*
*/this.workerHeight, (I2R(i)*pSlice + this.workerStartRad + (bj_PI/2))/*
*/ * bj_RADTODEG)
set i = i + 1
endloop
endif
endmethod
private method removeStation takes unit station returns nothing
local integer stationHandle = GetHandleId(station)
if thistype.stationFlag.boolean.has(stationHandle) then
call thistype.stationFlag.boolean.remove(stationHandle)
call DockingSystem.terminateStation(station)
endif
endmethod
/*
-----------------------------------
| Handler methods |
-----------------------------------
*/
/*
------------------
| |
| Constructs |
| |
------------------
*/
private static method onConstructStart takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local SubBuildList buildList = BuildSystemEx.dataBase[6].integer[buildingId]
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
// If building is a station...
if temp != 0 then
call temp.removeStation(building)
endif
if BuildSystemEx.dataBase[5].unit.has(builderHandle) then
// Move data reference to the building currently being built...
set station = BuildSystemEx.dataBase[5].unit[builderHandle]
set BuildSystemEx.dataBase[5].unit[buildingHandle] = station
set BuildSystemEx.dataBase[6].integer[buildingHandle] = BuildSystemEx.dataBase[6].integer[builderHandle]
call BuildSystemEx.dataBase[5].unit.remove(builderHandle)
call BuildSystemEx.dataBase[6].integer.remove(builderHandle)
// Correct the incremental value...
call BuildSystemEx.decrement(buildingOwner, buildingId)
if buildList.consumesWorker then
call UnitAddAbility(builder, 'Aloc')
endif
endif
set builder = null
set building = null
endmethod
private static method onConstructCancel takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station
local unit plug
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local integer stationHandle
local real stationX
local real stationY
local player stationOwner
local group stationGrp
local trigger trig
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
local SubBuildList buildList = 0
// Triggered by removal
if GetTriggerEventId() == null then
set building = GetIndexedUnit()
set builder = GetBuilder(building)
set buildingId = GetUnitTypeId(building)
set buildingHandle = GetHandleId(building)
set builderHandle = GetHandleId(builder)
endif
if BuildSystemEx.dataBase[5].unit.has(buildingHandle) then
set station = BuildSystemEx.dataBase[5].unit[buildingHandle]
set stationHandle = GetHandleId(station)
set stationOwner = BuildSystemEx.dataBase[1].player[stationHandle]
set stationX = BuildSystemEx.dataBase[2].real[stationHandle]
set stationY = BuildSystemEx.dataBase[3].real[stationHandle]
set stationGrp = BuildSystemEx.dataBase[4].group[stationHandle]
set buildList = BuildSystemEx.dataBase[6].integer[buildingHandle]
call BuildSystemEx.dataBase[5].unit.remove(buildingHandle)
call BuildSystemEx.dataBase[6].integer.remove(buildingHandle)
if buildList.consumesWorker then
call UnitRemoveAbility(builder, 'Aloc')
endif
call SetUnitInvulnerable(station, false)
call SetUnitX(station, stationX)
call SetUnitY(station, stationY)
call ShowUnit(station, true)
set plug = FirstOfGroup(stationGrp)
loop
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, stationX, stationY)
call PauseUnit(plug, false)
if GetLocalPlayer() == stationOwner then
call SelectUnit(plug, true)
endif
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(stationGrp, plug)
set plug = FirstOfGroup(stationGrp)
endloop
call BuildSystemEx.dataBase[1].player.remove(stationHandle)
call BuildSystemEx.dataBase[2].real.remove(stationHandle)
call BuildSystemEx.dataBase[3].real.remove(stationHandle)
call BuildSystemEx.dataBase[4].group.remove(stationHandle)
call DestroyGroup(stationGrp)
set station = null
set stationGrp = null
endif
set builder = null
set building = null
endmethod
private static method onConstructFinish takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit builder = GetBuildingUnit()
local unit station = null
local unit plug
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer builderHandle = GetHandleId(builder)
local integer stationHandle
local real stationX
local real stationY
local player stationOwner
local group stationTempGrp = null
local group stationGrp
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
local SubBuildList buildList = 0
if BuildSystemEx.dataBase[5].unit.has(buildingHandle) then
set station = BuildSystemEx.dataBase[5].unit[buildingHandle]
set stationHandle = GetHandleId(station)
set stationOwner = BuildSystemEx.dataBase[1].player[stationHandle]
set stationX = BuildSystemEx.dataBase[2].real[stationHandle]
set stationY = BuildSystemEx.dataBase[3].real[stationHandle]
set stationGrp = BuildSystemEx.dataBase[4].group[stationHandle]
set buildList = BuildSystemEx.dataBase[6].integer[stationHandle]
set stationTempGrp = CreateGroup()
call CopyGroup(stationTempGrp, stationGrp)
endif
call thistype.onConstructCancel()
if station != null then
set plug = FirstOfGroup(stationTempGrp)
loop
exitwhen plug == null
call GroupRemoveUnit(stationTempGrp, plug)
if buildList.consumesWorker then
call RemoveUnit(plug)
endif
set plug = FirstOfGroup(stationTempGrp)
endloop
call RemoveUnit(station)
endif
if stationTempGrp != null then
call DestroyGroup(stationTempGrp)
endif
if temp != 0 then
call temp.initStation(building)
endif
set stationTempGrp = null
set station = null
set stationGrp = null
set builder = null
set building = null
endmethod
/*
------------------
| |
| Upgrades |
| |
------------------
*/
private static method onUpgradeStart takes nothing returns nothing
local unit building = GetTriggerUnit()
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
if temp != 0 then
call DockingSystem.undockAll(building)
endif
if BuildSystemEx.dataBase[9].integer.has(buildingHandle) then
// Raise a flag telling the system that the unit is upgrading.
set BuildSystemEx.dataBase[11].boolean[buildingHandle] = true
endif
set building = null
endmethod
private static method onUpgradeCancel takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit plug
local real buildingX = GetUnitX(building)
local real buildingY = GetUnitY(building)
local group plugGroup
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer upgradeId
local SubBuildList buildList
local thistype temp = BuildSystemEx.stationHolder.integer[buildingId]
if GetTriggerEventId() == null then
set building = GetIndexedUnit()
set buildingX = GetUnitX(building)
set buildingY = GetUnitY(building)
set buildingOwner = GetOwningPlayer(building)
set buildingId = GetUnitTypeId(building)
set buildingHandle = GetHandleId(building)
endif
if BuildSystemEx.dataBase[9].integer.has(buildingHandle) then
set plugGroup = BuildSystemEx.dataBase[8].group[buildingHandle]
set buildList = SubBuildList(BuildSystemEx.dataBase[9].integer[buildingHandle])
set upgradeId = buildList.unitId
call BuildSystemEx.decrement(buildingOwner, upgradeId)
// Show the units...
set plug = FirstOfGroup(plugGroup)
loop
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, buildingX, buildingY)
call PauseUnit(plug, false)
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(plugGroup, plug)
set plug = FirstOfGroup(plugGroup)
endloop
call DestroyGroup(plugGroup)
set plugGroup = null
call BuildSystemEx.dataBase[7].player.remove(buildingHandle)
call BuildSystemEx.dataBase[8].group.remove(buildingHandle)
call BuildSystemEx.dataBase[9].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[10].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[11].boolean.remove(buildingHandle)
endif
set building = null
endmethod
private static method onUpgradeFinish takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit plug
local real buildingX = GetUnitX(building)
local real buildingY = GetUnitY(building)
local group plugGroup
local group plugGroupCopy = null
local player buildingOwner = GetOwningPlayer(building)
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local integer upgradeId
local integer lastBuildingId
local SubBuildList buildList
local thistype temp
if BuildSystemEx.dataBase[3].integer.has(buildingHandle) then
set plugGroup = BuildSystemEx.dataBase[2].group[buildingHandle]
set buildList = SubBuildList(BuildSystemEx.dataBase[3].integer[buildingHandle])
set upgradeId = buildList.unitId
set lastBuildingId = BuildSystemEx.dataBase[4].integer[buildingHandle]
set temp = BuildSystemEx.stationHolder.integer[lastBuildingId]
set plugGroupCopy = CreateGroup()
call CopyGroup(plugGroupCopy, plugGroup)
if temp != 0 then
/*
call temp.removeStation(building)
// Outsource it to transformation.
if thistype.unitTypeList.has(lastBuildingId) then
call BuildSystemEx.decrement(buildingOwner, lastBuildingId)
endif
*/
endif
// Counter the effects of decrement when calling onUpgradeCancel...
call BuildSystemEx.increment(buildingOwner, buildingId)
endif
call thistype.onUpgradeCancel()
set plug = FirstOfGroup(plugGroupCopy)
loop
exitwhen plug == null
call GroupRemoveUnit(plugGroupCopy, plug)
if buildList.consumesWorker then
call RemoveUnit(plug)
endif
set plug = FirstOfGroup(plugGroupCopy)
endloop
if plugGroupCopy != null then
call DestroyGroup(plugGroupCopy)
endif
set plugGroupCopy = null
set building = null
endmethod
/*
------------------
| |
| Training |
| |
------------------
*/
private static method onTrainCancel takes nothing returns nothing
local unit building
local unit plug
local integer buildingHandle
local integer buildingId
local integer trainedType = GetTrainedUnitType()
local real buildingX
local real buildingY
local group buildGroup
local TableArray buildTable
local SubBuildList buildList
local player buildingOwner
local thistype inst
set building = GetTriggerUnit()
set buildingId = GetUnitTypeId(building)
set buildingHandle = GetHandleId(building)
set buildingOwner = GetOwningPlayer(building)
set buildingX = GetUnitX(building)
set buildingY = GetUnitY(building)
// If there are units to be trained...
if BuildSystemEx.dataBase[14].integer.has(buildingHandle) then
set buildTable = BuildSystemEx.dataBase[14].integer[buildingHandle]
set buildGroup = UnitGroupList(buildTable[1].integer[trainedType]).first.data
set buildList = SubBuildList(buildTable[2].integer[trainedType])
call UnitGroupList(buildTable[1].integer[trainedType]).removeElem(buildGroup)
call BuildSystemEx.decrement(buildingOwner, trainedType)
// Show the units...
set plug = FirstOfGroup(buildGroup)
loop
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, buildingX, buildingY)
call PauseUnit(plug, false)
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(buildGroup, plug)
set plug = FirstOfGroup(buildGroup)
endloop
call DestroyGroup(buildGroup)
if UnitGroupList(buildTable[1].integer[trainedType]).size() == 0 then
call IntegerList(buildTable[1].integer[0]).removeElem(buildTable[1].integer[trainedType])
call IntegerList(buildTable[2].integer[0]).removeElem(trainedType)
call buildTable[2].integer.remove(trainedType)
endif
set BuildSystemEx.dataBase[13].integer[buildingHandle] = BuildSystemEx.dataBase[13].integer[buildingHandle] - 1
set buildGroup = null
endif
endmethod
private static method onTrainFinish takes nothing returns nothing
local unit building = GetTriggerUnit()
local unit plug
local integer buildingHandle
local integer buildingId
local integer trainTypeId = GetTrainedUnitType()
local group buildGroup
local TableArray trainTable
local SubBuildList buildList
local player buildingOwner
local thistype inst
local IntegerListItem iter
if not thistype.unitTypeList.integer.has(trainTypeId) then
set building = null
return
endif
set buildingId = GetUnitTypeId(building)
set buildingHandle = GetHandleId(building)
set buildingOwner = GetOwningPlayer(building)
set buildGroup = CreateGroup()
set trainTable = BuildSystemEx.dataBase[14].integer[buildingHandle]
set buildList = trainTable[2].integer[trainTypeId]
// Copy the group first, since it will get destroyed on thistype.onTrainCancel
call CopyGroup(buildGroup, UnitGroupList(trainTable[1].integer[trainTypeId]).first.data)
// Negation of the decrement call is on onEnter
call thistype.onTrainCancel()
set plug = FirstOfGroup(buildGroup)
loop
exitwhen plug == null
call GroupRemoveUnit(buildGroup, plug)
if buildList.consumesWorker then
call RemoveUnit(plug)
endif
set plug = FirstOfGroup(buildGroup)
endloop
call DestroyGroup(buildGroup)
set buildGroup = null
if BuildSystemEx.dataBase[13].integer[buildingHandle] == 0 then
set iter = IntegerList(trainTable[1].integer[-2]).first
loop
exitwhen iter == 0
call UnitRemoveAbility(building, iter.data)
call UnitAddAbility(building, iter.data)
set iter = iter.next
endloop
call IntegerList(trainTable[1].integer[0]).destroy()
call IntegerList(trainTable[2].integer[0]).destroy()
call IntegerList(trainTable[1].integer[-2]).destroy()
call trainTable.destroy()
call BuildSystemEx.dataBase[12].player.remove(buildingHandle)
call BuildSystemEx.dataBase[13].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[14].integer.remove(buildingHandle)
endif
endmethod
private static method onTrainDeath takes unit building returns nothing
local unit plug
local integer buildingId = GetUnitTypeId(building)
local integer buildingHandle = GetHandleId(building)
local player buildingOwner = GetOwningPlayer(building)
local real buildingX = GetUnitX(building)
local real buildingY = GetUnitY(building)
local group trainGroup
local SubBuildList buildList
local TableArray trainTable
local IntegerListItem iter
local IntegerListItem iter2
local UnitGroupListItem iterGrp
set trainTable = BuildSystemEx.dataBase[14].integer[buildingHandle]
set iter = IntegerList(trainTable[1].integer[0]).first
set iter2 = IntegerList(trainTable[2].integer[0]).first
loop
exitwhen iter == 0
set iterGrp = UnitGroupList(iter.data).first
set buildList = SubBuildList(trainTable[2].integer[iter2.data])
loop
exitwhen iterGrp == 0
set trainGroup = iterGrp.data
call BuildSystemEx.decrement(buildingOwner, buildList.unitId)
loop
set plug = FirstOfGroup(trainGroup)
exitwhen plug == null
call ShowUnit(plug, true)
call SetUnitInvulnerable(plug, false)
call SetUnitPosition(plug, buildingX, buildingY)
call PauseUnit(plug, false)
if buildList.consumesWorker then
call SetUnitUseFood(plug, true)
endif
call GroupRemoveUnit(trainGroup, plug)
endloop
call DestroyGroup(trainGroup)
set BuildSystemEx.dataBase[13].integer[buildingHandle] = BuildSystemEx.dataBase[13].integer[buildingHandle] - 1
set iterGrp = iterGrp.next
endloop
set iter = iter.next
set iter2 = iter2.next
endloop
if GetTriggerEventId() != null then
set iter = IntegerList(trainTable[1].integer[-2]).first
call PauseUnit(building, true)
loop
exitwhen iter == 0
call UnitRemoveAbility(building, iter.data)
call UnitAddAbility(building, iter.data)
set iter = iter.next
endloop
call PauseUnit(building, false)
endif
call IntegerList(trainTable[1].integer[0]).destroy()
call IntegerList(trainTable[2].integer[0]).destroy()
call IntegerList(trainTable[1].integer[-2]).destroy()
call trainTable.destroy()
call BuildSystemEx.dataBase[12].player.remove(buildingHandle)
call BuildSystemEx.dataBase[13].integer.remove(buildingHandle)
call BuildSystemEx.dataBase[14].integer.remove(buildingHandle)
endmethod
private static method onUnitEnter takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
// Unit is a station.
if inst != 0 then
call inst.initStation(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.increment(uOwner, unitId)
set thistype.unitOwner.player[uHandle] = uOwner
set thistype.unitDeathFlag.boolean[uHandle] = false
endif
set u = null
endmethod
private static method onUnitExit takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call inst.removeStation(u)
endif
// Unit must have undergone construction when it was removed...
if BuildSystemEx.dataBase[5].unit.has(uHandle) then
call thistype.onConstructCancel()
endif
// Unit must have undergone upgrade when it was removed...
if BuildSystemEx.dataBase[9].integer.has(uHandle) then
call thistype.onUpgradeCancel()
endif
// Unit must have trained some units...
if BuildSystemEx.dataBase[13].integer.has(uHandle) then
call thistype.onTrainDeath(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
if not thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.decrement(uOwner, unitId)
endif
call thistype.unitOwner.player.remove(uHandle)
call thistype.unitDeathFlag.boolean.remove(uHandle)
endif
set u = null
endmethod
private static method onUnitDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if GetTriggerEventId() == null then
// Called on reincarnation
set u = GetEventUnit()
endif
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
if GetNumberOfOccupiedSockets(u) != 0 then
call DockingSystem.undockAll(u)
endif
endif
// Unit must have undergone construction when it was destroyed...
if BuildSystemEx.dataBase[5].unit.has(uHandle) then
call thistype.onConstructCancel()
endif
// Unit must have trained some units beforehand...
if BuildSystemEx.dataBase[13].integer.has(uHandle) then
call thistype.onTrainDeath(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
if not thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.decrement(uOwner, unitId)
set thistype.unitDeathFlag.boolean[uHandle] = true
endif
endif
set u = null
endmethod
private static method onUnitChangeOwner takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[unitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call DockingSystem.undockAll(u)
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.decrement(thistype.unitOwner.player[uHandle], unitId)
set thistype.unitOwner.player[uHandle] = uOwner
call BuildSystemEx.increment(thistype.unitOwner.player[uHandle], unitId)
endif
set u = null
endmethod
private static method onUnitRevive takes nothing returns nothing
local unit u = GetEventUnit()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if thistype.unitTypeList.integer.has(unitId) then
if thistype.unitDeathFlag.boolean[uHandle] then
call BuildSystemEx.increment(uOwner, unitId)
set thistype.unitDeathFlag.boolean[uHandle] = false
endif
endif
set u = null
endmethod
private static method onUnitTransform takes nothing returns nothing
local unit u = GetEventUnit()
local integer prevUnitId = GetEventTransformType()
local integer unitId = GetUnitTypeId(u)
local integer uHandle = GetHandleId(u)
local player uOwner = GetOwningPlayer(u)
local thistype inst = BuildSystemEx.stationHolder.integer[prevUnitId]
if not thistype.isUnitPhysical(u) then
set u = null
return
endif
if inst != 0 then
call inst.removeStation(u)
endif
set inst = BuildSystemEx.stationHolder.integer[unitId]
if inst != 0 then
call inst.initStation(u)
endif
if thistype.unitTypeList.integer.has(GetEventTransformType()) then
call BuildSystemEx.decrement(uOwner, GetEventTransformType())
endif
if thistype.unitTypeList.integer.has(unitId) then
call BuildSystemEx.increment(uOwner, unitId)
endif
set u = null
endmethod
private static method onPreDockHandler takes nothing returns nothing
local unit station = GetStation()
local unit plug = GetPlug()
local integer stationId = GetUnitTypeId(station)
local integer stationHandle = GetHandleId(station)
local integer plugId = GetUnitTypeId(plug)
local integer plugHandle = GetHandleId(plug)
local player plugOwner = GetOwningPlayer(plug)
local thistype temp = BuildSystemEx.stationHolder.integer[stationId]
// Nothing to do here...
if (temp == 0) then
// Don't interfere with other stations...
set plug = null
set station = null
return
endif
if (temp.workerId != plugId) then
call InterruptDocking()
set plug = null
set station = null
return
endif
if (GetOwningPlayer(plug) != GetOwningPlayer(station)) then
call InterruptDocking()
call SimError(plugOwner, "Cannot dock into a station owned by another player!")
set plug = null
set station = null
endif
// Unit is being upgraded. Don't allow docking!
if BuildSystemEx.dataBase[7].player.has(stationHandle) then
call InterruptDocking()
call SimError(plugOwner, "Upgrade is in progress... you cannot dock at this moment.")
set plug = null
set station = null
return
endif
call ConditionalTriggerExecute(temp.onPredock)
set plug = null
set station = null
endmethod
private static method onDockHandler takes nothing returns nothing
local thistype temp = BuildSystemEx.stationHolder.integer[GetUnitTypeId(GetStation())]
if temp != 0 then
call ConditionalTriggerExecute(temp.onDock)
endif
endmethod
private static method onUndockHandler takes nothing returns nothing
local thistype temp = BuildSystemEx.stationHolder.integer[GetUnitTypeId(GetStation())]
if temp != 0 then
call ConditionalTriggerExecute(temp.onUndock)
endif
endmethod
private static method initVar takes nothing returns nothing
set thistype.unitTypeList = Table.create()
set thistype.unitOwner = Table.create()
set thistype.unitDeathFlag = Table.create()
set thistype.stationFlag = Table.create()
set thistype.unitTypeList.integer[0] = IntegerList.create()
endmethod
private static method initListener takes nothing returns nothing
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function thistype.onConstructStart)
//call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function thistype.onConstructCancel)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.onConstructFinish)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_START, function thistype.onUpgradeStart)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL, function thistype.onUpgradeCancel)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH, function thistype.onUpgradeFinish)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL, function thistype.onTrainCancel)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function thistype.onTrainFinish)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onUnitDeath)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CHANGE_OWNER, function thistype.onUnitChangeOwner)
call RegisterUnitIndexEvent(Condition(function thistype.onUnitEnter), EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onUnitExit), EVENT_UNIT_DEINDEX)
call RegisterNativeEvent(EVENT_ON_REINCARNATION_START, function thistype.onUnitDeath)
call RegisterNativeEvent(EVENT_ON_RESURRECTION, function thistype.onUnitRevive)
call RegisterNativeEvent(EVENT_ON_REINCARNATION_FINISH, function thistype.onUnitRevive)
call RegisterNativeEvent(EVENT_ON_TRANSFORM, function thistype.onUnitTransform)
call RegisterNativeEvent(EVENT_ON_PRE_DOCK, function thistype.onPreDockHandler)
call RegisterNativeEvent(EVENT_ON_DOCK, function thistype.onDockHandler)
call RegisterNativeEvent(EVENT_ON_UNDOCK, function thistype.onUndockHandler)
endmethod
private static method init takes nothing returns nothing
call thistype.initVar()
call thistype.initListener()
endmethod
static method onGameStart takes nothing returns nothing
local integer i = 1
local player p = Player(i - 1)
local IntegerListItem firstIter = IntegerList(thistype.unitTypeList.integer[0]).first
local IntegerListItem iter = firstIter
loop
loop
exitwhen iter == 0
set BuildSystemEx.unitTypeLimit[i].integer[iter.data] = 0
call SetPlayerTechMaxAllowed(p, iter.data, BuildSystemEx.unitTypeLimit[i].integer[iter.data])
set iter = iter.next
endloop
set iter = firstIter
exitwhen i >= bj_MAX_PLAYER_SLOTS
set p = Player(i)
set i = i + 1
endloop
endmethod
implement Initializer
endstruct
// This function is required. Don't edit this. (functionally private)
function InitTrig_CustomBuildSystem takes nothing returns nothing
call ForForce(bj_FORCE_PLAYER[0], function BuildSystem.onGameStart)
endfunction
endlibrary
library BuilderTrace /*
*/ requires /*
*||------------||*
*/ UnitDex /*
-> TriggerHappy
link: https://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
#? WorldBounds
#? GroupUtils
*||------------||*
*||------------||*
*/ Table /*
-> Bribe
link: https://www.hiveworkshop.com/threads/snippet-new-table.188084/#post-1835068
*||------------||*
*||------------||*
*/ OrderMatrix /*
-> MyPad
link: Not yet included, will do so in the future.
# Table
*/ optional TimerUtils /*
-> Preferably by Magtheridon96, Bribe, and Vexorian.
UnitDex -> Uses GetUnitId instead of GetHandleId, which is nicer in performance
overall.
Table -> Makes attaching data to stuff a breeze.
OrderMatrix -> Stores the relevant data of an issued order in an issued order event.
optional TimerUtils -> Only attach data to timers, which will clear out the first
builder of the building.
----------------------------
|Legend: |
| - # -> Requirement |
| - #? -> Optional |
----------------------------
------------------------------------
| BuilderTrace |
| - By MyPad |
------------------------------------
Track the first builder of any building.
-------------------------------------------------
Approach:
-------------------------------------------------
Simply enumerate units with the appropriate order id in order to get the builder.
From there, filter out the closest unit with that order id.
This runs on a CONSTRUCT_START event, so we are assured that buildings created
via CreateUnit or by training don't get included by mistake.
-------------------------------------------------
Functions:
-------------------------------------------------
function GetBuilder(unit whichBuilding) returns unit
- Returns the first builder of the building. Will return null if the unit
hasn't fired the CONSTRUCT_START event or 0 seconds after CONSTRUCT_FINISH,
if the unit has fired said event.
function GetBuildingUnit() returns unit
- A wrapper function for GetBuilder(GetTriggerUnit()) which behaves like a
native of sorts.
*/
private keyword BuilderTraceM
private struct BuilderTrace extends array
private static Table isIdBuilding = 0
private static TableArray builderTable = 0
static if not LIBRARY_TimerUtils then
private static Table newTimerData = 0
endif
private static group enum = null
private static integer buildingId = 0
private static method getUnitDist takes unit u1, unit u2 returns real
return SquareRoot( (GetUnitX(u1) - GetUnitX(u2))*(GetUnitX(u1) - GetUnitX(u2)) + (GetUnitY(u1) - GetUnitY(u2))*(GetUnitY(u1) - GetUnitY(u2)) )
endmethod
private static method isBuildingId takes unit u returns boolean
local integer uId = GetUnitTypeId(u)
if not isIdBuilding.boolean.has(uId) then
set isIdBuilding.boolean[uId] = IsUnitType(u, UNIT_TYPE_STRUCTURE)
endif
return isIdBuilding.boolean[uId]
endmethod
private static method onOrderMatchMisc takes unit u returns boolean
return (852013 >= GetUnitCurrentOrder(u) and GetUnitCurrentOrder(u) >= 852008) or GetUnitCurrentOrder(u) == 852147
endmethod
private static method onOrderMatch takes nothing returns boolean
local unit filterUnit = GetFilterUnit()
local boolean result = (GetUnitCurrentOrder(filterUnit) == buildingId) or onOrderMatchMisc(filterUnit)
set filterUnit = null
return result
endmethod
private static method onEnter takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit iter = null
local unit builder = null
local real dist = 0.
local real minDist = 999999.
local real orderDist = 0.
local real minOrderDist = 999999.
local real cx = GetUnitX(u)
local real cy = GetUnitY(u)
if thistype.isBuildingId(u) then
set buildingId = GetUnitTypeId(u)
call GroupEnumUnitsOfPlayer(thistype.enum, GetOwningPlayer(u), Filter(function thistype.onOrderMatch))
loop
set iter = FirstOfGroup(thistype.enum)
exitwhen iter == null
set dist = thistype.getUnitDist(u, iter)
if dist < minDist then
set orderDist = SquareRoot((cx - OrderMatrix[iter].getTargetX())*(cx - OrderMatrix[iter].getTargetX()) + (cy - OrderMatrix[iter].getTargetY())*(cy - OrderMatrix[iter].getTargetY()))
if orderDist < minOrderDist then
set builder = iter
set minDist = dist
set minOrderDist = orderDist
exitwhen minOrderDist <= 0
endif
endif
call GroupRemoveUnit(thistype.enum, iter)
endloop
endif
set thistype.builderTable[1].unit[GetUnitId(u)] = builder
set builder = null
set u = null
endmethod
private static method onClearData takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer data
static if LIBRARY_TimerUtils then
set data = ReleaseTimer(t)
else
set data = thistype.newTimerData.integer[GetHandleId(t)]
call thistype.newTimerData.integer.remove(GetHandleId(t))
call DestroyTimer(t)
endif
call thistype.builderTable[1].unit.remove(data)
call thistype.builderTable[2].boolean.remove(data)
set t = null
endmethod
private static method onCancel takes nothing returns nothing
local unit u = GetTriggerUnit()
local timer t
if (GetTriggerEventId() != EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL) and (GetTriggerEventId() != EVENT_PLAYER_UNIT_CONSTRUCT_FINISH) then
set u = GetIndexedUnit()
endif
static if LIBRARY_TimerUtils then
if not thistype.builderTable[2].boolean.has(GetUnitId(u)) then
set t = NewTimerEx(GetUnitId(u))
endif
else
set t = CreateTimer()
set thistype.newTimerData.integer[GetHandleId(t)] = GetUnitId(u)
endif
if not thistype.builderTable[2].boolean[GetUnitId(u)] then
call TimerStart(t, 0., false, function thistype.onClearData)
set thistype.builderTable[2].boolean[GetUnitId(u)] = true
endif
set t = null
set u = null
endmethod
private static method onFinish takes nothing returns nothing
call thistype.onCancel()
endmethod
private static method initVars takes nothing returns nothing
set thistype.isIdBuilding = Table.create()
set thistype.builderTable = TableArray[3]
static if not LIBRARY_TimerUtils then
set thistype.newTimerData = Table.create()
endif
set thistype.enum = CreateGroup()
endmethod
private static method initHandlers takes nothing returns nothing
local trigger array t
set t[0] = CreateTrigger()
set t[1] = CreateTrigger()
set t[2] = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t[1], EVENT_PLAYER_UNIT_CONSTRUCT_START)
call TriggerRegisterAnyUnitEventBJ(t[0], EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL)
call TriggerRegisterAnyUnitEventBJ(t[2], EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerRegisterUnitIndexEvent(t[0], EVENT_UNIT_DEINDEX)
call TriggerAddCondition(t[1], function thistype.onEnter)
call TriggerAddCondition(t[0], function thistype.onCancel)
call TriggerAddCondition(t[2], function thistype.onFinish)
set t[2] = null
set t[1] = null
set t[0] = null
endmethod
private static method init takes nothing returns nothing
call initVars()
call initHandlers()
endmethod
static method getBuilder takes unit u returns unit
return thistype.builderTable[1].unit[GetUnitId(u)]
endmethod
implement BuilderTraceM
endstruct
private module BuilderTraceM
private static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
function GetBuilder takes unit building returns unit
return BuilderTrace.getBuilder(building)
endfunction
function GetBuildingUnit takes nothing returns unit
return GetBuilder(GetTriggerUnit())
endfunction
endlibrary