whoward69
DLL Minion
NOTE: Custom missions require a modded DLL
Missions are either instantaneous (eg, culture bomb, build an academy, create a great work, etc) or durational (eg build an improvement).
How to create an instantaneous custom mission using the event hooks provided by my DLL or the CP DLL are covered in post #1104 here, and this post assume you have read that one and have successfully created an instantaneous custom mission.
This post describes how to use the same set of events to create a custom mission that takes a number or turns to complete, eg a druid sanctifying a grove, or a prospector fossicking.
We're going to add a custom mission to the Scout unit that permits them to fossick for a set number of turns on Gems, Gold, Silver or Copper and add to the player's treasury.
Firstly, we need to create the custom mission database entry, which is the same as a new instantaneous custom mission, so see the description of each field/column in post #1104
And we need to enable the events within the DLL
Finally we need to hook three of the new custom mission events - CustomMissionPossible, CustomMissionStart and CustomMissionDoStep.
The solution presented below is slightly more complex than it needs to be as it was written to be a flexible template for others to use as the basis of their own custom missions.
Using the template, we only need to worry about four "needs to know" functions and three "do this" functions.
The template needs to know
1) What is the custom mission
2) How long is the custom mission
3) Can a unit ever perform the custom mission
4) Can a unit perform the custom mission at this plot
and the template calls "do this" functions
1) When the mission starts
2) Every turn the mission is active
3) When the mission ends
So some setup statements that will be used by the "needs to know" functions
and the four "needs to know" functions themselves
While there are three "do this" functions, typically only DoMissionComplete() will do any work. However, it is possible that some scenarios will have a use for the other two "do this" functions, so the template provides them
The bulk of the remaining code is the framework that handles the three custom mission events
The framework needs to store some data about in progress custom missions.
This is to overcome a short-coming in the existing event parameters (I didn't want to change the C++ code in the DLL as that would impact the CP DLL)
and also to handle the special case when the unit is already on the plot and doesn't need to move onto it
The following code does this in a non-persistent way.
There is one situation, see comment above in the CustomMissionDoStep() handler, where this may not be acceptable. In which case
you'll need to rewrite the Get/SetMissionValue() functions to persist the data into the modding database.
Complete Lua code
Missions are either instantaneous (eg, culture bomb, build an academy, create a great work, etc) or durational (eg build an improvement).
How to create an instantaneous custom mission using the event hooks provided by my DLL or the CP DLL are covered in post #1104 here, and this post assume you have read that one and have successfully created an instantaneous custom mission.
This post describes how to use the same set of events to create a custom mission that takes a number or turns to complete, eg a druid sanctifying a grove, or a prospector fossicking.
We're going to add a custom mission to the Scout unit that permits them to fossick for a set number of turns on Gems, Gold, Silver or Copper and add to the player's treasury.
Firstly, we need to create the custom mission database entry, which is the same as a new instantaneous custom mission, so see the description of each field/column in post #1104
Code:
<GameData>
<Missions>
<Row>
<Type>MISSION_FOSSICK</Type>
<Description>TXT_KEY_MISSION_FOSSICK</Description>
<Help>TXT_KEY_MISSION_FOSSICK_HELP</Help>
<DisabledHelp>TXT_KEY_MISSION_FOSSICK_HELP_DISABLED</DisabledHelp>
<IconAtlas>UNIT_ACTION_ATLAS</IconAtlas>
<IconIndex>22</IconIndex>
<OrderPriority>201</OrderPriority>
<Visible>1</Visible>
<EntityEventType>ENTITY_EVENT_GREAT_EVENT</EntityEventType>
<Time>25</Time>
</Row>
</Missions>
<Language_en_US>
<Row Tag="TXT_KEY_MISSION_FOSSICK">
<Text>Fossick</Text>
</Row>
<Row Tag="TXT_KEY_MISSION_FOSSICK_HELP">
<Text>Search for easily collectable resources</Text>
</Row>
<Row Tag="TXT_KEY_MISSION_FOSSICK_HELP_DISABLED">
<Text>The Scout must be on a resource to fossick</Text>
</Row>
</Language_en_US>
</GameData>
And we need to enable the events within the DLL
Code:
UPDATE CustomModOptions SET Value=1 WHERE Name='EVENTS_CUSTOM_MISSIONS';
Finally we need to hook three of the new custom mission events - CustomMissionPossible, CustomMissionStart and CustomMissionDoStep.
The solution presented below is slightly more complex than it needs to be as it was written to be a flexible template for others to use as the basis of their own custom missions.
Using the template, we only need to worry about four "needs to know" functions and three "do this" functions.
The template needs to know
1) What is the custom mission
2) How long is the custom mission
3) Can a unit ever perform the custom mission
4) Can a unit perform the custom mission at this plot
and the template calls "do this" functions
1) When the mission starts
2) Every turn the mission is active
3) When the mission ends
So some setup statements that will be used by the "needs to know" functions
Code:
--
-- Data that defines the parameters of the custom mission
--
local iMissionType = GameInfoTypes.MISSION_FOSSICK
local iMissionUnit = GameInfoTypes.UNIT_SCOUT
local iMissionDuration = 3
local fossickResources = {
[GameInfoTypes.RESOURCE_GEMS] = 5,
[GameInfoTypes.RESOURCE_GOLD] = 3,
[GameInfoTypes.RESOURCE_SILVER] = 2,
[GameInfoTypes.RESOURCE_COPPER] = 1
}
and the four "needs to know" functions themselves
Code:
--
-- What is the custom mission we are interested in?
--
function GetMissionType()
-- While it would be possible for one framework instance to support many (related) missions, that's advanced stuff
-- so we "keep it simple, stupid", and just support a single custom mission per framework instance
return iMissionType
end
--
-- How long is the mission for this unit?
--
function GetMissionDuration(pUnit, iCurrentTurn, iStartTurn)
-- Duration could be a function of the units type (eg a neutral wizard may take longer to summon undead than an evil one)
-- or their xp/level (eg a high wizard may be able to summon undead faster than a novice wizard)
-- but we'll keep it simple and just go for a fixed duration
return iMissionDuration
end
--
-- Can pUnit EVER perform the mission?
--
function IsMissionUnit(pUnit)
-- This should be a very general check, typically for the correct unit type/class
-- More complex checks (health, hostile units, etc) should be handled in IsMissionPlot()
return (pUnit:GetUnitType() == iMissionUnit)
end
--
-- Can pUnit perform the mission right NOW on this plot?
--
function IsMissionPlot(pUnit, iPlotX, iPlotY)
-- Simply check the resource on the plot,
-- but this could also be dependant on the unit's health, xp, level, promotions, proximity of cities, hostile units, etc
return fossickResources[Map.GetPlot(iPlotX, iPlotY):GetResourceType()]
end
While there are three "do this" functions, typically only DoMissionComplete() will do any work. However, it is possible that some scenarios will have a use for the other two "do this" functions, so the template provides them
Code:
--
-- DoMissionStart()
--
-- Called once as the mission starts
--
-- Typically does nothing. After this method is called, the unit will not be able to move
-- Do not perform "work" in this method, as if the mission is aborted (unit is moved, killed, whatever),
-- there is no way to undo the work.
-- Could be used to alert locals to an undesirable action (eg summoning undead) and summon "pitch fork wielding yokels" towards the unit's plot
--
function DoMissionStart(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionStart(%i)", iCurrentTurn))
end
--
-- DoMissionStep()
--
-- Called once per turn as the mission progresses
--
-- Typically does nothing
-- Could be used to keep directing the yokels towards the actioning unit's plot
--
function DoMissionStep(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionStep(%i)", iCurrentTurn))
end
--
-- DoMissionComplete()
--
-- Called once when the mission is completed
--
-- Typically does all the "work", will be called at the start of the turn after the mission completes,
-- so the unit will still be able to move after completing the work
--
function DoMissionComplete(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionComplete(%i)", iCurrentTurn))
-- Give the player some gold
local iGold = (Map.Rand(3, "Gold from fossicking") + 2) * fossickResources[pUnit:GetPlot():GetResourceType()]
print(string.format("Gold: %i", iGold))
Players[pUnit:GetOwner()]:ChangeGold(iGold)
end
The bulk of the remaining code is the framework that handles the three custom mission events
Code:
--
-- Nothing below here should need changing
-- (with the possible exception of the Get/SetMissionValue() functions, if persistent data is required)
--
local iCustomMission = GetMissionType()
-- Constants for the event handlers to return
local CUSTOM_MISSION_NO_ACTION = 0
local CUSTOM_MISSION_ACTION = 1
local CUSTOM_MISSION_DONE = 2
--
-- Handler for the CustomMissionPossible event
-- Can the specified unit perform the custom mission?
--
function OnCustomMissionPossible(iPlayer, iUnit, iMission, iData1, iData2, _, _, iPlotX, iPlotY, bTestVisible)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit) and pUnit:CanMove()) then
local iCurrentTurn = Game.GetGameTurn()
-- If the mission has been aborted, reset the temp data
if (pUnit:GetActivityType() ~= ActivityTypes.ACTIVITY_MISSION) then
SetMissionValue(iPlayer, iUnit, 'startTurn', iCurrentTurn)
end
-- If the mission could start this turn ...
if (GetMissionValue(iPlayer, iUnit, 'startTurn') == iCurrentTurn) then
-- ... can the unit perform the mission right here, right now
if (not IsMissionPlot(pUnit, iPlotX, iPlotY)) then
return bTestVisible
end
return true
end
end
end
return false
end
GameEvents.CustomMissionPossible.Add(OnCustomMissionPossible)
--
-- Handler for the CustomMissionStart event
-- Start the custom mission for the specified unit
--
function OnCustomMissionStart(iPlayer, iUnit, iMission, iData1, iData2, iFlags, iTurn)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit)) then
-- Initialise the mission temp data
SetMissionValue(iPlayer, iUnit, 'startTurn', iTurn)
SetMissionValue(iPlayer, iUnit, 'stepTurn', iTurn)
-- Call the mission start function
DoMissionStart(pUnit, iTurn, iTurn, iData1, iData2, iFlags)
local iDuration = GetMissionDuration(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
if (pUnit:HasMoved()) then
-- Unit has used part of the turn to get here, so mission is next N turns
SetMissionValue(iPlayer, iUnit, 'duration', iDuration)
else
-- Unit did not move to get here, so we count this turn as the first turn of the mission
SetMissionValue(iPlayer, iUnit, 'duration', iDuration-1)
DoMissionStep(pUnit, iTurn, iTurn, iData1, iData2, iFlags)
end
-- Just stand around doing nothing (as animating units is a real PITA)
pUnit:FinishMoves()
return CUSTOM_MISSION_ACTION
end
end
return CUSTOM_MISSION_NO_ACTION
end
GameEvents.CustomMissionStart.Add(OnCustomMissionStart)
--
-- Handler for the CustomMissionDoStep event
-- Update the custom mission for the specified unit
--
function OnCustomMissionDoStep(iPlayer, iUnit, iMission, iData1, iData2, iFlags, iTurn)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit)) then
local iCurrentTurn = Game.GetGameTurn()
-- Is this the first time this turn for this event?
if (not (GetMissionValue(iPlayer, iUnit, 'stepTurn') == iCurrentTurn)) then
-- Update the mission temp data
SetMissionValue(iPlayer, iUnit, 'stepTurn', iCurrentTurn)
-- Get the remaining turns for this mission
local iTurnsLeft = GetMissionValue(iPlayer, iUnit, 'duration')
if (iTurnsLeft == nil) then
-- This happens if the game was saved while a mission was in progress.
-- We only store the remaining turns to benefit a unit that didn't move before starting the mission
-- So we can recalculate the missing value, which will "short-change" a unit that didn't move,
-- but it's preferable to the complexity of persisting (in a generic manner) the data
-- If this is a problem, rewrite Get/SetMissionValue() to use a persistent data store
iTurnsLeft = GetMissionDuration(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags) - ((iCurrentTurn-1) - iTurn)
end
-- Did the mission complete this turn ...
if (iTurnsLeft > 0) then
-- ... no, so call the mission step function
DoMissionStep(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
SetMissionValue(iPlayer, iUnit, 'duration', iTurnsLeft-1)
return CUSTOM_MISSION_ACTION
else
-- ... yes, so call the mission complete function
DoMissionComplete(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
return CUSTOM_MISSION_DONE
end
end
end
end
return CUSTOM_MISSION_NO_ACTION
end
GameEvents.CustomMissionDoStep.Add(OnCustomMissionDoStep)
The framework needs to store some data about in progress custom missions.
This is to overcome a short-coming in the existing event parameters (I didn't want to change the C++ code in the DLL as that would impact the CP DLL)
and also to handle the special case when the unit is already on the plot and doesn't need to move onto it
Code:
--
-- For a mission that takes 3 turns to complete, you will see (for example)
-- Turn 2 - player moves unit onto plot and clicks the mission button - DoMissionStart(2)
-- Turn 3 - (1st full turn of mission) unit is not cycled to, after End Turn is clicked - DoMissionStep(3)
-- Turn 4 - (2nd turn of mission) unit is not cycled to, after End Turn is clicked - DoMissionStep(4)
-- Turn 5 - (3rd turn of mission) unit is not cycled to, after End Turn is clicked - DoMissionStep(5)
-- Turn 6 - DoMissionComplete(6) - unit is cycled to and may move this turn
-- OR
-- Turn 2 - unit starts turn on plot and player clicks the mission button - DoMissionStart(2) and DoMissionStep(2)
-- Turn 3 - (2nd turn of mission) unit is not cycled to, after End Turn is clicked - DoMissionStep(3)
-- Turn 4 - (3rd turn of mission) unit is not cycled to, after End Turn is clicked - DoMissionStep(4)
-- Turn 5 - DoMissionComplete(5) - unit is cycled to and may move this turn
--
The following code does this in a non-persistent way.
There is one situation, see comment above in the CustomMissionDoStep() handler, where this may not be acceptable. In which case
you'll need to rewrite the Get/SetMissionValue() functions to persist the data into the modding database.
Code:
--
-- Temporary store for mission data
--
-- See comment in OnCustomMissionDoStep, you may want to make this persistent
--
local missionData = {}
function GetMissionData(iPlayer, iUnit)
if (iPlayer) then
if (missionData[iPlayer] == nil) then
missionData[iPlayer] = {}
end
if (iUnit) then
if (missionData[iPlayer][iUnit] == nil) then
missionData[iPlayer][iUnit] = {}
end
return missionData[iPlayer][iUnit]
else
return missionData[iPlayer]
end
else
return missionData
end
end
function GetMissionValue(iPlayer, iUnit, sKey)
return GetMissionData(iPlayer, iUnit)[sKey]
end
function SetMissionValue(iPlayer, iUnit, sKey, value)
GetMissionData(iPlayer, iUnit)[sKey] = value
end
Complete Lua code
Spoiler :
Code:
--
-- For a mission that takes 3 turns to complete, you will see (for example)
-- Turn 2 - player moves unit onto plot and clicks the mission button - DoMissionStart(2)
-- Turn 3 - (1st full turn of mission) unit is not cycled, after End Turn is clicked - DoMissionStep(3)
-- Turn 4 - (2nd turn of mission) unit is not cycled, after End Turn is clicked - DoMissionStep(4)
-- Turn 5 - (3rd turn of mission) unit is not cycled, after End Turn is clicked - DoMissionStep(5)
-- Turn 6 - DoMissionComplete(6) - unit is cycled to and may move this turn
-- OR
-- Turn 2 - unit starts turn on plot and player clicks the mission button - DoMissionStart(2) and DoMissionStep(2)
-- Turn 3 - (2nd turn of mission) unit is not cycled, after End Turn is clicked - DoMissionStep(3)
-- Turn 4 - (3rd turn of mission) unit is not cycled, after End Turn is clicked - DoMissionStep(4)
-- Turn 5 - DoMissionComplete(5) - unit is cycled to and may move this turn
--
--
-- Data that defines the parameters of the custom mission
--
local iMissionType = GameInfoTypes.MISSION_FOSSICK
local iMissionUnit = GameInfoTypes.UNIT_SCOUT
local iMissionDuration = 3
local fossickResources = {
[GameInfoTypes.RESOURCE_GEMS] = 5,
[GameInfoTypes.RESOURCE_GOLD] = 3,
[GameInfoTypes.RESOURCE_SILVER] = 2,
[GameInfoTypes.RESOURCE_COPPER] = 1
}
--
-- What is the custom mission we are interested in?
--
function GetMissionType()
return iMissionType
end
--
-- How long is the mission for this unit?
--
function GetMissionDuration(pUnit, iCurrentTurn, iStartTurn)
return iMissionDuration
end
--
-- Can pUnit EVER perform the mission?
--
function IsMissionUnit(pUnit)
-- This should be a very general check, typically for the correct unit type/class
-- More complex checks (health, hostile units, etc) should be handled in IsMissionPlot()
return (pUnit:GetUnitType() == iMissionUnit)
end
--
-- Can pUnit perform the mission right NOW on this plot?
--
function IsMissionPlot(pUnit, iPlotX, iPlotY)
-- Simply check the resource on the plot,
-- but this could also be dependant on the unit's health, xp, level, promotions, proximity of cities, hostile units, etc
return fossickResources[Map.GetPlot(iPlotX, iPlotY):GetResourceType()]
end
--
-- DoMissionStart()
--
-- Called once as the mission starts
--
-- Typically does nothing. After this method is called, the unit will not be able to move
-- Do not perform "work" in this method, as if the mission is aborted (unit is moved, killed, whatever),
-- there is no way to undo the work
-- Could be used to alert locals to an undesirable action (eg summoning undead) and summon "pitch fork wielding yokels" towards the unit's plot
--
function DoMissionStart(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionStart(%i)", iCurrentTurn))
end
--
-- DoMissionStep()
--
-- Called once per turn as the mission progresses
--
-- Typically does nothing
-- Could be used to keep directing the yokels towards the actioning unit's plot
--
function DoMissionStep(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionStep(%i)", iCurrentTurn))
end
--
-- DoMissionComplete()
--
-- Called once when the mission is completed
--
-- Typically does all the "work", will be called at the start of the turn the mission completes in,
-- so the unit will still be able to move after completing the work
--
function DoMissionComplete(pUnit, iCurrentTurn, iStartTurn)
print(string.format("DoMissionComplete(%i)", iCurrentTurn))
-- Give the player some gold
local iGold = (Map.Rand(3, "Gold from fossicking") + 2) * fossickResources[pUnit:GetPlot():GetResourceType()]
print(string.format("Gold: %i", iGold))
Players[pUnit:GetOwner()]:ChangeGold(iGold)
end
--
-- Nothing below here should need changing
-- (with the possible exception of the Get/SetMissionValue() functions, if persistent data is required)
--
local iCustomMission = GetMissionType()
-- Constants for the event handlers to return
local CUSTOM_MISSION_NO_ACTION = 0
local CUSTOM_MISSION_ACTION = 1
local CUSTOM_MISSION_DONE = 2
--
-- Handler for the CustomMissionPossible event
--
function OnCustomMissionPossible(iPlayer, iUnit, iMission, iData1, iData2, _, _, iPlotX, iPlotY, bTestVisible)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit) and pUnit:CanMove()) then
local iCurrentTurn = Game.GetGameTurn()
-- If the mission has been aborted, reset the temp data
if (pUnit:GetActivityType() ~= ActivityTypes.ACTIVITY_MISSION) then
SetMissionValue(iPlayer, iUnit, 'startTurn', iCurrentTurn)
end
-- If the mission could start this turn ...
if (GetMissionValue(iPlayer, iUnit, 'startTurn') == iCurrentTurn) then
-- ... can the unit perform the mission right here, right now
if (not IsMissionPlot(pUnit, iPlotX, iPlotY)) then
return bTestVisible
end
return true
end
end
end
return false
end
GameEvents.CustomMissionPossible.Add(OnCustomMissionPossible)
--
-- Handler for the CustomMissionStart event
--
function OnCustomMissionStart(iPlayer, iUnit, iMission, iData1, iData2, iFlags, iTurn)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit)) then
-- Initialise the mission temp data
SetMissionValue(iPlayer, iUnit, 'startTurn', iTurn)
SetMissionValue(iPlayer, iUnit, 'stepTurn', iTurn)
-- Call the mission start function
DoMissionStart(pUnit, iTurn, iTurn, iData1, iData2, iFlags)
local iDuration = GetMissionDuration(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
if (pUnit:HasMoved()) then
-- Unit has used part of the turn to get here, so mission is next N turns
SetMissionValue(iPlayer, iUnit, 'duration', iDuration)
else
-- Unit did not move to get here, so we count this turn as the first turn of the mission
SetMissionValue(iPlayer, iUnit, 'duration', iDuration-1)
DoMissionStep(pUnit, iTurn, iTurn, iData1, iData2, iFlags)
end
-- Just stand around doing nothing (as animating units is a real PITA)
pUnit:FinishMoves()
return CUSTOM_MISSION_ACTION
end
end
return CUSTOM_MISSION_NO_ACTION
end
GameEvents.CustomMissionStart.Add(OnCustomMissionStart)
--
-- Handler for the CustomMissionDoStep event
--
function OnCustomMissionDoStep(iPlayer, iUnit, iMission, iData1, iData2, iFlags, iTurn)
-- Is this the custom mission we are supervising
if (iMission == iCustomMission) then
local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
-- Can the specified unit ever perform this mission
if (IsMissionUnit(pUnit)) then
local iCurrentTurn = Game.GetGameTurn()
-- Is this the first time this turn for this event?
if (not (GetMissionValue(iPlayer, iUnit, 'stepTurn') == iCurrentTurn)) then
-- Update the mission temp data
SetMissionValue(iPlayer, iUnit, 'stepTurn', iCurrentTurn)
-- Get the remaining turns for this mission
local iTurnsLeft = GetMissionValue(iPlayer, iUnit, 'duration')
if (iTurnsLeft == nil) then
-- This happens if the game was saved while a mission was in progress.
-- We only store the remaining turns to benefit a unit that didn't move before starting the mission
-- So we can recalculate the missing value, which will "short-change" a unit that didn't move,
-- but it's preferable to the complexity of persisting (in a generic manner) the data
-- If this is a problem, rewrite Get/SetMissionValue() to use a persistent data store
iTurnsLeft = GetMissionDuration(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags) - ((iCurrentTurn-1) - iTurn)
end
-- Did the mission complete this turn ...
if (iTurnsLeft > 0) then
-- ... no, so call the mission step function
DoMissionStep(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
SetMissionValue(iPlayer, iUnit, 'duration', iTurnsLeft-1)
return CUSTOM_MISSION_ACTION
else
-- ... yes, so call the mission complete function
DoMissionComplete(pUnit, iCurrentTurn, iTurn, iData1, iData2, iFlags)
return CUSTOM_MISSION_DONE
end
end
end
end
return CUSTOM_MISSION_NO_ACTION
end
GameEvents.CustomMissionDoStep.Add(OnCustomMissionDoStep)
--
-- Temporary store for mission data
--
-- See comment in OnCustomMissionDoStep, you may want to make this persistent
--
local missionData = {}
function GetMissionData(iPlayer, iUnit)
if (iPlayer) then
if (missionData[iPlayer] == nil) then
missionData[iPlayer] = {}
end
if (iUnit) then
if (missionData[iPlayer][iUnit] == nil) then
missionData[iPlayer][iUnit] = {}
end
return missionData[iPlayer][iUnit]
else
return missionData[iPlayer]
end
else
return missionData
end
end
function GetMissionValue(iPlayer, iUnit, sKey)
return GetMissionData(iPlayer, iUnit)[sKey]
end
function SetMissionValue(iPlayer, iUnit, sKey, value)
GetMissionData(iPlayer, iUnit)[sKey] = value
end