First, start with the "Bare Bones" Mission skeleton.
MissionType = {
UID = 0, --- TODO: Use this for Mission Dependencies.
Difficulty = "EASY", --- TODO: Use this to warn Users about difficult Missions.
Create = function() --- Call this when the Mission is created.
--- Return a mission table.
--- This is persistent and will be passed back to the action functions below.
return defaultMissionTable( "Name", "Description" )
end,
Accept = function( missionTable ) end, --- Call this when the Mission is accepted.
Reject = function( missionTable ) end, --- Call this when the Mission is rejected after being accepted.
Update = function( missionTable ) --- Call this each time that the Mission should be checked.
return nil --- Return nil when the mission isn't over yet.
return true --- Return true when the mission has succeded.
return false --- Return false when the mission has failed.
end,
Success = function( missionTable ) end, --- Call this if the Mission is a Success.
Failure = function( missionTable ) end, --- Call this if the Mission is a failure.
}
Second, create a unique MissionType? name and UID. The "Difficulty" field doesn't do anything yet, so leaving it at "EASY" is fine.
CollectArtifacts = {
UID = 3,
Difficulty = "EASY",
...
}
Third, the Create function is how each instance of this mission type gets it's uniqueness. The player will see the same mission type several times, so try to make enough aspects of the Mission different. Any mission data should be stored in a table and returned from this function. At the bare minimum, this table needs to contain a "Name" and a "Description".
In Lua, there are several ways of accessing a table key.
sometable = {}
sometable["Name"] = "Foobar"
sometable = {}
sometable.Name = "Foobar"
sometable = {Name="Foobar", ...}
sometable = {["Name"]="Foobar", ...}
In this case, the player needs to travel to several planets collecting Artifacts, then return them to a planet. Since we're creating a Mission that may be used a lot, we want to give it a plenty of blank spaces and fill them in madlibs style.
The missionTable that gets returned from the Create function will be passed to all future mission functions for this Mission instance. Those functions can modify the table at will. The Create function should not actually do anything itself, but should define everything that later functions will need.
Create = function()
local missionTable = defaultMissionTable(
"Collect %d Artifacts from %s for The %s",
"Several important items of %s have been found by %s %s. The %s will pay you %d credits to return them safely to %s."
)
-- The vocabulary of our mission madlibs
local allianceNames = Epiar.alliances()
local planetNames = Epiar.planetNames()
local objects = {"Sword", "Blaster", "Helm", "Amulet", "Tome", "Flag", "Statue", "History", "MacGuffin", "Crystal", "Book", "Document"}
local adjectives = {"Red", "Black", "Bloodless", "Steel", "Iron", "Circular", "Mistaken", "Forgotten", "Wild", "Nuclear"}
local events = {"Revolution", "Revolt", "Insurgency", "Tournament", "Race", "Decade", "Legend", "Treaty", "Project", "Council"}
local actors = {"revolutionaries", "spies", "rebels", "agitators", "freedom fighters", "terrorists", "hooligans", "mobsters", "pirates", "officials", "assassins"}
-- The rest of the Mission Table entries.
missionTable.EventName = "The %s %s"
missionTable.Actors = choose( actors )
missionTable.FriendAlliance = choose( allianceNames )
missionTable.EnemyAlliance = choose( allianceNames )
missionTable.NumArtifacts = math.random( 2, 6 )
missionTable.FinalPlanet = choose( planetNames )
missionTable.Adjective = choose( adjectives )
missionTable.Event = choose( events )
missionTable.Reward = 5000 + (missionTable.NumArtifacts * 2000)
missionTable.Objects = {}
missionTable.Collected = {}
missionTable.PlanetsWithArtifacts = {}
-- Fill in the blanks madlib style
missionTable.EventName = missionTable.EventName:format( missionTable.Adjective, missionTable.Event )
missionTable.Name = missionTable.Name:format( missionTable.NumArtifacts, missionTable.EventName, missionTable.FriendAlliance)
missionTable.Description = missionTable.Description:format( missionTable.EventName, missionTable.EnemyAlliance, missionTable.Actors, missionTable.FriendAlliance, missionTable.Reward, missionTable.FinalPlanet)
-- Get a random subset of the Objects and Planets
table.shuffle( planetNames )
table.shuffle( objects )
for i=1, missionTable.NumArtifacts do
table.insert( missionTable.PlanetsWithArtifacts, planetNames[i] )
table.insert( missionTable.Objects, objects[i] )
table.insert( missionTable.Collected, false )
local sentence = " The %s can be found on %s."
sentence = sentence:format( objects[i], planetNames[i] )
missionTable.Description = missionTable.Description .. sentence
end
return missionTable
end,
Fourth, the Accept function will get called when the player chooses to accept this mission. At this point, the Mission can modify the universe appropriately. The DestroyPirate? MissionType? will create a nearby Pirate Ship for example. This example does not change the universe, so we'll just send the Player a quick message.
Accept = function( missionTable ) local acceptMessage = "The artifacts from %s can be found at %s" local places = missionTable.PlanetsWithArtifacts[1] .. " and " .. missionTable.PlanetsWithArtifacts[2] for i=3, missionTable.NumArtifacts do places = missionTable.PlanetsWithArtifacts[1] .. ", " .. places end acceptMessage = acceptMessage:format( missionTable.EventName, places ) HUD.newAlert( acceptMessage ) end,
Fifth, the Reject function is called when the player rejects the mission. This function is intended to clean up anything that the Accept or Update has created. Again, the example here doesn't do much more than Alert the player.
Reject = function( missionTable ) local rejectMessage = "The %s %s will get away with the artifacts." rejectMessage = rejectMessage:format( missionTable.EnemyAlliance, missionTable.Actors ) HUD.newAlert( acceptMessage ) end,
Sixth, the Update function is the most important function in the Mission. This is where the exit conditions are checked for success and failure. This function is called on every update Tick, so don't make it too complicated. Normally the Update function shouldn't return anything (or return nil). When this function returns true then the Player has Succeeded in their Mission. When this function returns false, then they have failed.
For this example, we're simply going to check if the player has picked up any of the artifacts. Once all of the Artifacts have been retrieved the player must return to the Final Planet.
Update = function( missionTable ) local totalFound = 0 local x,y = PLAYER:GetPosition() for i=1, missionTable.NumArtifacts do if missionTable.Collected[i] == false then local p = Planet.Get( missionTable.PlanetsWithArtifacts[i] ) local px,py = p:GetPosition() if distfrom(px,py,x,y) < 50 then -- This artifact has been recovered -- Record this in the Description local desc = "** You have recovered the %s **" desc = desc:format( missionTable.Objects[i] ) missionTable.Description = missionTable.Description .. desc -- Alert the Player local message = "You have recovered the %s of %s from %s." message = message:format( missionTable.Objects[i], missionTable.EventName, missionTable.PlanetsWithArtifacts[i] ) HUD.newAlert( message ) -- Mark this Object as Collected missionTable.Collected[i] = true end else totalFound = totalFound + 1 end end if totalFound == missionTable.NumArtifacts then local p = Planet.Get( missionTable.FinalPlanet ) local px,py = p:GetPosition() if distfrom(px,py,x,y) < 50 then local message = "All of the Artifacts from %s have been delivered to the %s on ." message = message:format( missionTable.EventName, missionTable.FriendAlliance, missionTable.FinalPlanet ) HUD.newAlert( message ) return true end end end,
Seventh, the Success and Failure functions will be called when the Mission has ended. Usually the Success function will give the player something of value like credits.
Success = function( missionTable ) addcredits( missionTable.Reward ) end,
Failure = function( missionTable ) end,