Tutorial: Making a campaign mission

Post Reply
User avatar
Kyran
Posts: 499
Joined: Sat Dec 31, 2011 5:19 pm
Location: Australia
Contact:

Tutorial: Making a campaign mission

Post by Kyran »

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:

Code: Select all

title = "III. Sea Preparations"
objectives = {"- Find your ally's base", "- Build a Shipyard", "- Build 5 Destroyers", "- Arthor Literios must not die"}
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:

Code: Select all

DefineMapSetup("./campaigns/orc/level03o_c.sms")
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.

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"}
)
At the bottom of the file you need to make sure that your map itself will load when the mission starts.

Code: Select all

Load("campaigns/orc/level03/level03o.sms")
Step 7 - Set up the triggers in level03o_c.sms

A mission with no triggers should have a section just under Briefing() of:

Code: Select all

Triggers = [[]]
The first thing I'm going to add are the diplomacy settings.

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)
]] 
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.

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)
]]
The player will win when four destroyers and a shipyard are built.

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)]]
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.
Unactive Ranger.png
Unactive Ranger.png (145.93 KiB) Viewed 9777 times
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)
Now to make the AI load I add the following line to level03o_c.sms:

Code: Select all

Load("campaigns/orc/level03/level03o_ai.lua")
And finally change Players 6's AI to ai_level03 in level03o.sms.gz
Active Ranger.png
Active Ranger.png (129.1 KiB) Viewed 9777 times
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)
]]
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.

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)
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:

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")
And replace with:

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")
Done, all thats left to do is the write a mission intro and record some lines.

Image
Attachments
level03.zip
(11.11 KiB) Downloaded 708 times
04:27 jim4 why haven't you added wc1 support? this project sucks. i'm only going to use freecraft
05:06 jim4 finished wc1 support yet? i've been waiting for 6 years
05:10 jim4 new things scare me
User avatar
Big Daddy
Posts: 118
Joined: Sun Jan 08, 2012 11:23 pm

Re: Tutorial: Making a campaign mission

Post by Big Daddy »

Good work mate, your tutorial will help anyone who intends to work with the Stratagus engine. Recommended read.

-Big Daddy
Post Reply