Tutorial: Making a campaign mission
Posted: Fri Feb 03, 2012 10:02 am
I'm currently working on the campaign for Aleona's Tales so I figure I might as well write a short tutorial on how to ready a map for a campaign.
Step 1 - Make a map.
Step 2 - Copy the map (sms.gz and smp.gz) into a suitable location in the campaign directory.
For this tutorial I'm working on level 3 of the introduction campaign. So I'm going to put the map files into Tales/campaigns/orc/level03/.
Step 3 - Make a copy of level02o_c.sms and level03o_c2.sms (located in Tales/campaigns/orc/), renaming them to level30_c.sms and level03o_c2.sms respectively.
Step 4 - Open up level03o_c2.sms and adjust the title of the mission and the objectives.
In my case I've ended up with:
You may wonder what the point of level03o_c2.sms is at all since you could just embed those variables directly inside level03o_c.sms and remove level03o_c2.sms all together. Don't do that however as level03o_c2.sms is used for the campaign level selector.
Step 5 - Open up level03o.smp.gz (using something like 7-Zip) and open level03o.smp (with WordPad or similar).
Add the following line at the end:
It would now be a good idea now to test out the level to make sure the game doesn't crash.
Step 6 - Open up level03o_c.sms and make sure all the correct files get loaded.
First, you should make sure level03o_c2.sms is loading at the start of the file.
At the bottom of the file you need to make sure that your map itself will load when the mission starts.
Step 7 - Set up the triggers in level03o_c.sms
A mission with no triggers should have a section just under Briefing() of:
The first thing I'm going to add are the diplomacy settings.
0 is red, 1 is blue, and 6 is white. In the situation above both red and yellow will be allied, while blue will be against them both.
Next I'm going to add winning conditions.
The player will win when four destroyers and a shipyard are built.
Now I'm going to add some loosing conditions.
If all the player's units or Arthor Literios are lost, the game ends. Kind of redundant though since Arthor Literios has to be lost in order for the player to have no more units left.
Step 8 - Add some fancy scripting.
Right now the map is playable, but not winnable. What I'm going to do is have the town hall at the AI's base tranfer to the player. First however I'll deal with those four AI rangers at the start of the map.
Lazy rangers. What I'd love to have happen is for those rangers to lead the way to the allied base. However, currently we don't have the functions needed to make that happen. What I'm going to do is to make my own AI which will make those rangers attack the enemy instead. First, I'll make the AI.
Create a new LUA file in Tales/campaigns/orc/level03/ and call it level03o_ai.lua
Inside insert:
Now to make the AI load I add the following line to level03o_c.sms:
And finally change Players 6's AI to ai_level03 in level03o.sms.gz
Success, the friendly player is now using a custom AI script.
OK, now that we've got that little annoyance out of the way, let's make this mission winnable. I'll open level03o_c.sms back up and have the townhall change to the player when the hero unit stands next to it.
Yes, I know it isn't working for some reason.
Seems one small side effect has come up. When the player takes control of the townhall the AI will build another one. That goes against the lore so I'll remove some functionality from the AI script.
Step 9 - Adjust building permissions.
For this mission, the player needs to be able to build a shipyard and destroyers. Open up level03o_c.sms for the final time and fine:
And replace with:
Done, all thats left to do is the write a mission intro and record some lines.
Step 1 - Make a map.
Step 2 - Copy the map (sms.gz and smp.gz) into a suitable location in the campaign directory.
For this tutorial I'm working on level 3 of the introduction campaign. So I'm going to put the map files into Tales/campaigns/orc/level03/.
Step 3 - Make a copy of level02o_c.sms and level03o_c2.sms (located in Tales/campaigns/orc/), renaming them to level30_c.sms and level03o_c2.sms respectively.
Step 4 - Open up level03o_c2.sms and adjust the title of the mission and the objectives.
In my case I've ended up with:
Code: Select all
title = "III. Sea Preparations"
objectives = {"- Find your ally's base", "- Build a Shipyard", "- Build 5 Destroyers", "- Arthor Literios must not die"}
Step 5 - Open up level03o.smp.gz (using something like 7-Zip) and open level03o.smp (with WordPad or similar).
Add the following line at the end:
Code: Select all
DefineMapSetup("./campaigns/orc/level03o_c.sms")
Step 6 - Open up level03o_c.sms and make sure all the correct files get loaded.
First, you should make sure level03o_c2.sms is loading at the start of the file.
Code: Select all
-- Stratagus Map - Single player campaign
Load("campaigns/orc/level03o_c2.sms")
Briefing(
title,
objectives,
"../campaigns/orc/interface/introscreen1.png",
"campaigns/orc/level03/level03o.txt",
{"campaigns/orc/level02/level03o-intro1.wav"}
)
Code: Select all
Load("campaigns/orc/level03/level03o.sms")
A mission with no triggers should have a section just under Briefing() of:
Code: Select all
Triggers = [[]]
Code: Select all
Triggers = [[
SetDiplomacy(0, "allied", 6)
SetDiplomacy(6, "allied", 0)
SetSharedVision(6, true, 0)
SetSharedVision(0, true, 6)
SetDiplomacy(1, "enemy", 6)
SetDiplomacy(6, "enemy", 1)
]]
Next I'm going to add winning conditions.
Code: Select all
Triggers = [[
SetDiplomacy(0, "allied", 6)
SetDiplomacy(6, "allied", 0)
SetSharedVision(6, true, 0)
SetSharedVision(0, true, 6)
SetDiplomacy(1, "enemy", 6)
SetDiplomacy(6, "enemy", 1)
AddTrigger(
function() return GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-destroyer") > 4 and
GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-shipyard") >= 1 end,
function() return ActionVictory() end)
]]
Now I'm going to add some loosing conditions.
Code: Select all
Triggers = [[
SetDiplomacy(0, "allied", 6)
SetDiplomacy(6, "allied", 0)
SetSharedVision(6, true, 0)
SetSharedVision(0, true, 6)
SetDiplomacy(1, "enemy", 6)
SetDiplomacy(6, "enemy", 1)
AddTrigger(
function() return GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-destroyer") > 4 and
GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-shipyard") >= 1 end,
function() return ActionVictory() end)
AddTrigger(
function() return GetNumUnitsAt(ThisPlayer.Index, "unit-arthor-literios",
{0, 0}, {128, 128}) < 1 end,
function() return ActionDefeat() end)
AddTrigger(
function() return GetPlayerData(GetThisPlayer(), "TotalNumUnits") == 0 end,
function() return ActionDefeat() end)]]
Step 8 - Add some fancy scripting.
Right now the map is playable, but not winnable. What I'm going to do is have the town hall at the AI's base tranfer to the player. First however I'll deal with those four AI rangers at the start of the map.
Lazy rangers. What I'd love to have happen is for those rangers to lead the way to the allied base. However, currently we don't have the functions needed to make that happen. What I'm going to do is to make my own AI which will make those rangers attack the enemy instead. First, I'll make the AI.
Create a new LUA file in Tales/campaigns/orc/level03/ and call it level03o_ai.lua
Inside insert:
Code: Select all
-- _________ __ __
-- / _____// |_____________ _/ |______ ____ __ __ ______
-- \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
-- / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ \
-- /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
-- \/ \/ \//_____/ \/
-- ______________________ ______________________
-- T H E W A R B E G I N S
-- Stratagus - A free fantasy real time strategy game engine
--
-- level03o_ai.lua - Define the AI.
--
-- (c) Copyright 2012 by Kyran Jackson
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
function AiLevel03()
AiForce(2, {AiShooter(), 4})
AiAttackWithForce(2)
AiSet(AiWorker(), 8)
if ((GetNumUnitsAt(AiPlayer(), "unit-town-hall", {0, 0}, {256, 256}) >= 1) or (GetNumUnitsAt(AiPlayer(), "unit-castle", {0, 0}, {256, 256}) >= 1) or (GetNumUnitsAt(AiPlayer(), "unit-keep", {0, 0}, {256, 256}) >= 1)) then
if (GetNumUnitsAt(AiPlayer(), "unit-human-barracks", {0, 0}, {256, 256}) >= 1) then
if (GetNumUnitsAt(AiPlayer(), "unit-footman", {0, 0}, {256, 256}) >= 4) then
AiForce(3, {AiSoldier(), 12})
if (GetNumUnitsAt(AiPlayer(), "unit-footman", {0, 0}, {256, 256}) >= 8) then
print("attack")
AiAttackWithForce(3)
end
else
AiSet(AiSoldier(), 4)
end
else
AiSet(AiBarracks(), 1)
end
else
AiSet(AiCityCenter(), 1)
end
end
DefineAi("ai_level03", "*", "ai_level03", AiLevel03)
Code: Select all
Load("campaigns/orc/level03/level03o_ai.lua")
Success, the friendly player is now using a custom AI script.
OK, now that we've got that little annoyance out of the way, let's make this mission winnable. I'll open level03o_c.sms back up and have the townhall change to the player when the hero unit stands next to it.
Code: Select all
Triggers = [[
SetDiplomacy(0, "allied", 6)
SetDiplomacy(6, "allied", 0)
SetDiplomacy(1, "enemy", 6)
SetDiplomacy(6, "enemy", 1)
AddTrigger(
function() return GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-destroyer") > 4 and
GetPlayerData(GetThisPlayer(), "UnitTypesCount", "unit-human-shipyard") >= 1 end,
function() return ActionVictory() end)
AddTrigger(
function() return GetNumUnitsAt(ThisPlayer.Index, "unit-arthor-literios",
{0, 0}, {128, 128}) < 1 end,
function() return ActionDefeat() end)
AddTrigger(
function() return GetPlayerData(GetThisPlayer(), "TotalNumUnits") == 0 end,
function() return ActionDefeat() end)
AddTrigger(
function() return GetNumUnitsAt(ThisPlayer.Index, "unit-arthor-literios",
{17, 29}, {25, 37}) > 0 end,
function() return ChangeUnitsOwner({15, 29}, {25, 37}, 6, 0) end)
]]
Seems one small side effect has come up. When the player takes control of the townhall the AI will build another one. That goes against the lore so I'll remove some functionality from the AI script.
Code: Select all
-- _________ __ __
-- / _____// |_____________ _/ |______ ____ __ __ ______
-- \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
-- / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ \
-- /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
-- \/ \/ \//_____/ \/
-- ______________________ ______________________
-- T H E W A R B E G I N S
-- Stratagus - A free fantasy real time strategy game engine
--
-- level03o_ai.lua - Define the AI.
--
-- (c) Copyright 2012 by Kyran Jackson
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
function AiLevel03()
if (GetNumUnitsAt(AiPlayer(), "unit-ranger", {0, 0}, {256, 256}) >= 4) then
AiForce(2, {AiShooter(), 4})
AiAttackWithForce(2)
end
AiSet(AiWorker(), 8)
if (GetNumUnitsAt(AiPlayer(), "unit-human-barracks", {0, 0}, {256, 256}) >= 1) then
if (GetNumUnitsAt(AiPlayer(), "unit-footman", {0, 0}, {256, 256}) >= 4) then
AiForce(3, {AiSoldier(), 12})
if (GetNumUnitsAt(AiPlayer(), "unit-footman", {0, 0}, {256, 256}) >= 8) then
AiAttackWithForce(3)
end
else
AiSet(AiSoldier(), 4)
end
else
AiSet(AiBarracks(), 1)
end
end
DefineAi("ai_level03", "*", "ai_level03", AiLevel03)
For this mission, the player needs to be able to build a shipyard and destroyers. Open up level03o_c.sms for the final time and fine:
Code: Select all
DefineAllow("unit-human-oil-tanker", "FFFFFFFFFFFFFFFF")
DefineAllow("unit-human-destroyer", "FFFFFFFFFFFFFFFF")
DefineAllow("unit-human-transport", "FFFFFFFFFFFFFFFF")
DefineAllow("unit-human-oil-platform", "FFFFFFFFFFFFFFFF")
DefineAllow("unit-human-shipyard", "FFFFFFFFFFFFFFFF")
Code: Select all
DefineAllow("unit-human-oil-tanker", "AAAAAAAAAAAAAAAA")
DefineAllow("unit-human-destroyer", "AAAAAAAAAAAAAAAA")
DefineAllow("unit-human-transport", "AAAAAAAAAAAAAAAA")
DefineAllow("unit-human-oil-platform", "AAAAAAAAAAAAAAAA")
DefineAllow("unit-human-shipyard", "AAAAAAAAAAAAAAAA")