There is no need to buy MOH:BT to make your map support the Liberation mode gameplay. It can be produced inMOH:AA by a little scripting and some creative mapping. See also LegalAndMoralIssues.
The Liberation gameplay mode is based on two teams batteling each other and trying to put all of the opposing team in prison. It is a respawning game mode, but not as you are used to. Because there is a bigger punishment for getting killed than respawning a bit away. Instead you will spawn inside a locked area that only one of your teammates can open(one that is still not in prison that is). A Liberation game may be as quick as 2 teams killing each others off, or it may be a very long battle that flows back and forth as both teams open the opposing prison and lets their teammembers out, getting well needed reinforcements in the process.
This is just what you would think it is: a space you cant get out of if you are locked in. Here is an example of what I consider a good prison.
In MOH:AA:
( pic 1 )
And in MOHRadiant
( pic 2 )
The simplest way to make the prison door would be to make it a solid brush, but that would make the prisoned players unable to follow the events outside. And if thay can't see what is going on outside, it will be very boring to be in prison ( yes it is a punishment for sucking, but depriving players of enjoying the game is just stupid. Remember: they will not play it if it is not fun. )
So I make the gate like this:
( pic 3 )
The clip brush inside the gate is "common/clip". Be sure to check the "playerclip", "monsterclip", and "weaponclip" in the SurfacePropertiesDialog? box. This way the 2 teams can see each other, but cant hurt each other through the bars.
Also make sure the clip is thick enough to prevent bashing through. About 20 units thick should be enough.
Select all the brushes making up the gate and turn it into a script_object, because we need to be able to open it ( moving it out of the way in some way to let prisoners out ).
Then wee need to set some key / values on it. Select the script_object and press 'n' to bring up the EntityDialog box and set these key / values on it:
| Key | Value | Explanation |
|---|---|---|
| targetname | axis_prison_gate | To be able to refer to the script_object in the script, it must have a unique targetname ( the Allied prison vould have targetname / allies_prison_gate ) |
| dmg | 10 | Because a player may stand in the way to prevent the movement of an entity, we make it do damage if blocked. 10 is a good number because it is small enough to let players try heroic deeds, but big enough to kill him within about 8 seconds. |
We need some way to break out our mates, right? So we need some trigger_use triggers. And its good practice to put these triggers around some obvoius thig to use, like a button or a lever. So place a nice model ( like the pulsating lever in pic 1, 2 and 3, named "animate_equipment_trainswitch-pulsating" ) and place a trigger_use brush around it ( make the brush and select "trigger->use" from the pop up menu ).
Give it these names in the EntityDialog :
| Key | Value | Explanation |
|---|---|---|
| targetname | axis_jailbreak_trigger | To be able to refer to the trigger_use in the script, it must have a unique targetname ( the Allied prison trigger would have targetname / allies_jailbreak_trigger ) |
That should be all you need to get working triggers. Another idea is to just put the triggers outside the prison gate and make it work like a regular door ( but only from the outside ).
We need two different sets of spawns for each team. One set that is placed where spawns regularely are placed to offer a good starting spawn for the team. And one set inside the enemy prison ( see pic 1 )
As we need to manipulate the spawns during play, we must set some key / values on them:
| Key | Value | What spawns to give the Key / Values |
|---|---|---|
| targetname | allied_start_spawn | All spawns that are intended for the Allied players to spawn at when the map starts |
| targetname | axis_start_spawn | All spawns that are intended for the Axis players to spawn at when the map starts |
| targetname | allies_prison_spawn | These are set on the Allied spawns inside the Axis prison on the other side of the map from the Allied start spawns |
| targetname | axis_prison_spawn | These are set on the Axis spawns inside the Allied prison on the other side of the map from the Axis start spawns |
OK, now whe should have the components that wee need in the map, so lets tie it together with some nice scripting.
The complete script is listed further down. Here follows a description and explanation of the major parts ot the script.
This is the default method called by MOH:AA after loading a map, this is where it all starts. There is really nothing special to this method, and it will look a lot like other objective main methods. Three things are worth mentioning here:
This starts the jailbreak sensors ( see below ) and the player scanner ( see below ). then it waits for 10 seconds before it activates the prison spawns and de-activates all other spawns ( see below ).
Disables all the spawns in the prisons.
Disables all the "normal" spawns and enables all the spawns in the prisons.
Waits for the triggers to be activated. When activated it animates the switch and opens the prison, or if the triggerer is from the wrong team: tells the player to "Stop that!".
Opens the prison gate while palying some fitting sounds. Waits a short while, and then closes it again.
This is an important method. Once called it will continually scan all players, and based on the results of that scan: decide if a team has won yet.
A helper method used by the "player_scanner" method. It will fing out if the player given to it is: 1) - in the game ( not just spectating ). 2) - Inside the enemy prison.
This will be called by the trigger spawned in "detect_player_status" if the player is in the game ( not just spectating ).
Use all the gathered data from the methods above to determine if the match is won. Called by "player_scanner".
The method "detect_player_status" spawns a trigger_multiple with the target / value of setthread / player_exists_setthread at the origin of the player. This means that a player will trigger this if he is in the game ( not just spectating ). And if he triggers it, the trigger will call the player_exists_setthread method that will in turn mark the triggering player as "activated" ( really playing the game ).
If you find this a bit strange, you are correct. It is used because you can not rely on checking the isAlive command because it will say the player is alive as soon as he selects a team ( if he selects no weapon: he is seen as alive until he does without actually entering the game ).
// -Liberation tutorial-
// - Liberation objective -
//
// ARCHITECTURE: M.S
// SCRIPTING: Bjarne Grönnevik
// TEXTURES: W.S
// OPTIMIZING: Bjarne Grönnevik
main:
// set scoreboard messages
setcvar "g_obj_alliedtext1" "-Kill all Axis. "
setcvar "g_obj_alliedtext2" "-Free your friends. "
setcvar "g_obj_alliedtext3" "0 of 0 Allies jailed"
setcvar "g_obj_axistext1" "-Kill all Allies. "
setcvar "g_obj_axistext2" "-Free your friends. "
setcvar "g_obj_axistext3" "0 of 0 Axis jailed "
setcvar "g_scoreboardpic" "lib_canal_scoreboard"
level waitTill prespawn
// set the parameters for this round
level.dmrespawning = 1 // 1 or 0
level.dmroundlimit = 10 // round time limit in minutes
level.clockside = kills // set to axis, allies, kills, or draw
exec global/DMprecache.scr
level.script = maps/obj/lib_canal.scr
exec global/door_locked.scr::lock
exec global/ambient.scr lib_canal
waitthread initial_spawn_setup
level waittill spawn
// level waittill roundstart
thread start_liberation_system
end
start_liberation_system:
thread player_scanner
thread allied_jailbreak_sensor
thread axis_jailbreak_sensor
wait 10
thread activate_prison_spawn_setup
end
allied_jailbreak_sensor:
while(true)
{
$allied_jailbreak_trigger waittill trigger
if(parm.other.dmteam == axis)
{
parm.other iprint "You have released your friends!" 0
$allied_jailbreak_switch playsound track_switch1
$allied_jailbreak_switch anim move
waitthread allied_prison_open
$allied_jailbreak_switch anim idle
}
else
{
if(parm.other.dmteam == allies)
{
parm.other iprint "Stop that!" 0
}
}
}
end
allied_prison_open:
if(!$allies_prison_gate.busy)
{
$allies_prison_gate.busy = 1
$allies_prison_gate time 4
wait 1
$allies_prison_gate moveUp 120
$allies_prison_gate playsound elevator_run
$allies_prison_gate waitmove
iprintlnbold_noloc "The Allied prison is open!"
wait 10
$allies_prison_gate damage 100
$allies_prison_gate moveDown 120
$allies_prison_gate playsound elevator_run
$allies_prison_gate waitmove
$allies_prison_gate.busy = 0
}
end
axis_jailbreak_sensor:
while(true)
{
$axis_jailbreak_trigger waittill trigger
if(parm.other.dmteam == allies)
{
parm.other iprint "You have released your friends!" 0
$axis_jailbreak_switch playsound track_switch1
$axis_jailbreak_switch anim move
waitthread axis_prison_open
$axis_jailbreak_switch anim idle
}
else
{
if(parm.other.dmteam == axis)
{
parm.other iprint "Stop that!" 0
}
}
}
end
axis_prison_open:
if(!$axis_prison_gate.busy)
{
$axis_prison_gate.busy = 1
$axis_prison_gate time 4
wait 1
$axis_prison_gate moveUp 120
$axis_prison_gate playsound elevator_run
$axis_prison_gate waitmove
iprintlnbold_noloc "The Axis prison is open!"
wait 10
$axis_prison_gate moveDown 120
$axis_prison_gate playsound elevator_run
$axis_prison_gate waitmove
$axis_prison_gate.busy = 0
}
end
player_scanner:
while (true)
{
level.allies_in_game = 0
level.axis_in_game = 0
level.allies_in_prison = 0
level.axis_in_prison = 0
for(local.i = 1; local.i <= $player.size; local.i++)
{
waitthread detect_player_status $player[local.i]
waitframe
}
waitthread test_winning_conditions
wait 1
}
end
detect_player_status local.player:
// Test if the player has spawned into the map, or are still choosing weapon
local.trigger = spawn trigger_multiple "targetname" "player_position_trigger" setthread player_exists_setthread
local.trigger.origin = local.player.origin
waitframe
waitframe
waitframe
$player_position_trigger delete
if(local.player.activated && isAlive local.player)
{
if(local.player.dmteam == allies)
{
level.allies_in_game++
if(local.player istouching $axis_prison_volume)
{
level.allies_in_prison++
}
}
else
{
if(local.player.dmteam == axis)
{
level.axis_in_game++
if(local.player istouching $allied_prison_volume)
{
level.axis_in_prison++
}
}
else
{
if(local.player.dmteam == spectator)
{
iprintln "Spectating player detected " local.player.dmteam
local.player.activated = false
}
else
{
iprintln "Undefined player detected " local.player.dmteam
local.player.activated = false
}
}
}
}
end
player_exists_setthread:
parm.other.activated = true
end
test_winning_conditions:
local.temp_string = string(level.axis_in_prison) + " of " + string(level.axis_in_game) + " Axis jailed "
setcvar "g_obj_axistext3" local.temp_string
local.temp_string = string(level.allies_in_prison) + " of " + string(level.allies_in_game) + " Allies jailed"
setcvar "g_obj_alliedtext3" local.temp_string
if(level.allies_in_game > 0)
{
if(level.allies_in_game == level.allies_in_prison)
{
// iprintln "Axis win!"
teamwin axis
}
}
if (level.axis_in_game > 0)
{
if( level.axis_in_game == level.axis_in_prison)
{
// iprintln "Allies win!"
teamwin allies
}
}
end
initial_spawn_setup:
$allies_prison_spawn disablespawn
$axis_prison_spawn disablespawn
end
activate_prison_spawn_setup:
$allies_prison_spawn enablespawn
$axis_prison_spawn enablespawn
$allied_start_spawn disablespawn
$axis_start_spawn disablespawn
end
Attach:user-lib_tutorial.zip (47.15 Kb)