/*
Issues
- Can't detect if a targeted area is reachable by land or water.
- Has no Errror Messages
- Units on route that have been blocked are left standing still even after the block is removed
they should automatically start moving again.
Posible changes:
- Replace the timer check for blocked pathing with an error message only.
Known bug: - if you issue to deliver goods to a city outside of during free-time, it will be added
to the failure group temporarily. (until next PERIOD)
- During supply route and you order it to another destination then its supposed target it will continue afterwards.
if it fails the failure is stuck above the unit until next refresh event
*/
scope SupplyCities initializer Init
globals
constant integer SUPPLY_CARAVAN = 'hrdh'
constant integer SUPPLY_SHIP = 'hbot'
constant integer CANCEL_ROUTE = 'Atau'
constant integer HOME_DEST = 'A004'
constant integer HOME_DEST_UNS = 'A006'
constant integer SUPPLY_DEST = 'A005'
constant integer SUPPLY_DEST_UNS = 'A007'
constant integer DELIVER = 'A003'
constant integer DELIVER_SHIP = 'A00G'
constant integer GATHER = 'A00B'
constant integer GATHER_SHIP = 'A00H'
constant integer WAITING_DELIVER = 'A00F'
constant integer WAITING_GATHER = 'A002'
constant integer PLAY_PAUSE = 'A00D'
constant integer PLAY_PAUSE_SHIP = 'A00I'
constant integer STATUS_FREE = 0 // If only two options exist these can be removed
constant integer STATUS_WORKING = 1
constant string ORDER_GATHER = "shadowstrike"
constant string ORDER_DELIVER = "cripple"
constant string ORDER_STOP_WORK = "bearform"
//constant string ORDER_NEW_DEST = "unholyfrenzy" // Not sure these are used
//constant string ORDER_NEW_HOME = "charm"
private constant real PERIOD = 5.
private constant real GATHER_PERCENT = 50.
private integer array cityDest
private integer array cityHome
private integer array status
private string array order
private real array x
private real array y
private group failures = CreateGroup()
private group active = CreateGroup()
private trigger trgPeriodic
endglobals
private function Cancel takes nothing returns nothing
local unit caster = genLastSpellCaster
local integer uId = GetUnitUserData(caster)
local unit u = GetTriggerUnit()
if cityDest[uId] != 0 then
set cityDest[uId] = 0
call UnitAddAbility(caster, SUPPLY_DEST_UNS)
call UnitRemoveAbility(caster, SUPPLY_DEST)
endif
if cityHome[uId] != 0 then
set cityHome[uId] = 0
call UnitAddAbility(caster, HOME_DEST_UNS)
call UnitRemoveAbility(caster, HOME_DEST)
endif
if status[uId] != STATUS_FREE then
call IssueImmediateOrderDelayed(caster, ORDER_STOP_WORK, 0.05)
endif
set caster = null
endfunction
private function Destination takes nothing returns nothing
local unit caster = genLastSpellCaster
local unit target = genLastSpellTarget
local integer uId = GetUnitUserData(caster)
if cityDest[uId] == 0 then
call UnitAddAbility(caster, SUPPLY_DEST)
call UnitRemoveAbility(caster, SUPPLY_DEST_UNS)
endif
set cityDest[uId] = GetUnitUserData(target)
if cityDest[uId] == cityHome[uId] then
set cityHome[uId] = 0
call UnitAddAbility(caster, HOME_DEST_UNS)
call UnitRemoveAbility(caster, HOME_DEST)
endif
set caster = null
set target = null
endfunction
private function Home takes nothing returns nothing
local unit caster = genLastSpellCaster
local unit target = genLastSpellTarget
local integer uId = GetUnitUserData(caster)
if cityHome[uId] == 0 then
call UnitAddAbility(caster, HOME_DEST)
call UnitRemoveAbility(caster, HOME_DEST_UNS)
endif
set cityHome[uId] = GetUnitUserData(target)
if cityHome[uId] == cityDest[uId] then
set cityDest[uId] = 0
call UnitAddAbility(caster, SUPPLY_DEST_UNS)
call UnitRemoveAbility(caster, SUPPLY_DEST)
endif
set caster = null
set target = null
endfunction
private function ToggleFailure takes unit u, integer id, boolean toggle returns nothing
if IsUnitInGroup(u, failures) == true and toggle == false then
call GroupRemoveUnit(failures, u)
call UnitRemoveAbility(u, WAITING_GATHER)
call UnitRemoveAbility(u, WAITING_DELIVER)
elseif IsUnitInGroup(u, failures) == false and toggle == true then
if order[id] == ORDER_GATHER then
call UnitAddAbility(u, WAITING_GATHER)
else
call UnitAddAbility(u, WAITING_DELIVER)
endif
call GroupAddUnit(failures, u)
endif
endfunction
private function SetFree takes unit u, integer id returns nothing
if GetUnitTypeId(u) == SUPPLY_CARAVAN then
call UnitRemoveAbility(u, PLAY_PAUSE)
call UnitAddAbility(u, PLAY_PAUSE)
else
call UnitRemoveAbility(u, PLAY_PAUSE_SHIP)
call UnitAddAbility(u, PLAY_PAUSE_SHIP)
endif
set status[id] = STATUS_FREE
set order[id] = null
call ToggleFailure(u, id, false)
call GroupRemoveUnit(active, u)
endfunction
private function PlayPauseButton takes nothing returns nothing
local unit caster = genLastSpellCaster
local integer uId = GetUnitUserData(caster)
local real mana
if cityDest[uId] != 0 and cityHome[uId] != 0 and status[uId] == STATUS_FREE then
set status[uId] = 1
set mana = GetUnitState(caster, UNIT_STATE_MANA)
if mana > 0 then
set order[uId] = ORDER_DELIVER
call IssueTargetOrder(caster, ORDER_DELIVER, city[cityDest[uId]].u)
else
set order[uId] = ORDER_GATHER
call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
endif
call GroupAddUnit(active, caster)
else
call SetFree(caster, uId)
endif
set caster = null
endfunction
private function InterruptionCheck takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer uId = GetUnitUserData(u)
local integer typeId = GetUnitTypeId(u)
if typeId == SUPPLY_CARAVAN or typeId == SUPPLY_SHIP then
if status[uId] == STATUS_WORKING and order[uId] != OrderId2String(GetIssuedOrderId()) then
call SetFree(u, uId)
call IssueImmediateOrder(u, "stop")
endif
endif
set u = null
return false
endfunction
private function GatherSupplies takes nothing returns nothing
local unit caster = genLastSpellCaster
local unit target = genLastSpellTarget
local integer uId = GetUnitUserData(caster)
local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
local integer statusIn = status[uId]
if cityMana/GetUnitState(caster, UNIT_STATE_MAX_MANA)*100 >= GATHER_PERCENT then
set status[uId] = STATUS_FREE
call IssueTargetOrder(caster, "smart", target)
if statusIn == STATUS_WORKING then
set order[uId] = ORDER_DELIVER
call ToggleFailure(caster, uId, false)
call IssueTargetOrderDelayed(caster, ORDER_DELIVER, city[cityDest[uId]].u, 0.1)
set status[uId] = STATUS_WORKING
endif
elseif status[uId] == STATUS_WORKING then
call ToggleFailure(caster, uId, true)
endif
set target = null
set caster = null
endfunction
private function DeliverSupplies takes nothing returns nothing
local unit caster = genLastSpellCaster
local unit target = genLastSpellTarget
local integer uId = GetUnitUserData(caster)
local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
local real cityManaMax = GetUnitState(target, UNIT_STATE_MAX_MANA)
local real unitMana = GetUnitState(caster, UNIT_STATE_MANA)
local integer statusIn = status[uId]
if cityManaMax >= unitMana + cityMana then
call SetUnitState(target, UNIT_STATE_MANA, unitMana + cityMana)
call SetUnitState(caster, UNIT_STATE_MANA, 0)
if status[uId] == STATUS_WORKING then
call ToggleFailure(caster, uId, false)
set order[uId] = ORDER_GATHER
call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
endif
else
// Delivers what mana posible and toggles failure on
call SetUnitState(target, UNIT_STATE_MANA, cityManaMax)
set unitMana = unitMana - cityManaMax + cityMana
call SetUnitState(caster, UNIT_STATE_MANA, unitMana)
if status[uId] == STATUS_WORKING then
call ToggleFailure(caster, uId, true)
endif
endif
set target = null
set caster = null
endfunction
private function RedoTask takes nothing returns nothing
local unit u = GetEnumUnit()
local integer uId = GetUnitUserData(u)
if status[uId] == 0 then
set order[uId] = null
call ToggleFailure(u, uId, false)
else
if order[uId] == ORDER_DELIVER then
call IssueTargetOrder(u, order[uId], city[cityDest[uId]].u)
elseif order[uId] == ORDER_GATHER then
call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[uId]].u)
endif
endif
set u = null
endfunction
private function Refresh takes nothing returns nothing
local unit u = GetEnumUnit()
local integer id = GetUnitUserData(u)
local real old_x = x[id]
local real old_y = y[id]
set x[id] = GetUnitX(u)
set y[id] = GetUnitY(u)
if (not IsUnitInGroup(u, failures) and old_x == x[id] and old_y == y[id]) or IsUnitInGroup(u, failures) == true then
if order[id] == ORDER_DELIVER then
call IssueTargetOrder(u, ORDER_DELIVER, city[cityDest[id]].u)
else
call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[id]].u)
endif
endif
endfunction
private function Periodic takes nothing returns nothing
call ForGroup(active, function Refresh)
endfunction
private function Init takes nothing returns nothing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
local trigger t4 = CreateTrigger()
local trigger t5 = CreateTrigger()
local trigger t6 = CreateTrigger()
local trigger t7 = CreateTrigger()
local integer i = 0
local player p
set trgPeriodic = CreateTrigger()
loop
set p = Player(i)
call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerRegisterTimerEvent(trgPeriodic, PERIOD, true)
call TrgRegisterGenericSpellFinish(t1, CANCEL_ROUTE)
call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST_UNS)
call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST)
call TrgRegisterGenericSpellFinish(t3, HOME_DEST_UNS)
call TrgRegisterGenericSpellFinish(t3, HOME_DEST)
call TrgRegisterGenericSpellFinish(t4, DELIVER)
call TrgRegisterGenericSpellFinish(t4, DELIVER_SHIP)
call TrgRegisterGenericSpellFinish(t5, GATHER)
call TrgRegisterGenericSpellFinish(t5, GATHER_SHIP)
call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE)
call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE_SHIP)
call TriggerAddAction(t1, function Cancel)
call TriggerAddAction(t2, function Destination)
call TriggerAddAction(t3, function Home)
call TriggerAddAction(t4, function DeliverSupplies)
call TriggerAddAction(t5, function GatherSupplies)
call TriggerAddAction(t6, function PlayPauseButton)
call TriggerAddCondition(t7, Condition(function InterruptionCheck))
call TriggerAddAction(trgPeriodic, function Periodic)
endfunction
endscope