Reverse MvM Beginners Guide: Difference between revisions

From SigMod
Jump to navigation Jump to search
No edit summary
(basic split of page to technical implementation and theory sections)
 
(39 intermediate revisions by 8 users not shown)
Line 1: Line 1:
Reverse MvM refers to a combination of [https://sigwiki.potatomvm.tf/index.php/WaveSchedule custom keyvalues] that flips the teams and win conditions.  Instead of defending against hordes of robots, players are spawned on the blue team and must fight their way to the hatch and deliver the bomb.  Designing missions around this concept can be very complex and requires heavy usage of [https://sigwiki.potatomvm.tf/index.php/Design_PointTemplate_with_hammer_map_editor Point Templates].  It is highly recommended that you have a basic understanding of hammer and map logic beforehand, as well as a deep understanding of our [https://testing.potatomvm.tf/mvm_bigrock_sigdemo.pop custom popfile keyvalues].
Reverse MvM is a combination of [https://sigwiki.potato.tf/index.php/WaveSchedule custom popfile keyvalues] that flips the teams and win conditions.  Instead of defending against hordes of robots, players are spawned on the blue team and must fight their way to the hatch and deliver the bomb.  Designing missions around this concept can be very complex and requires heavy usage of [https://steamcommunity.com/sharedfiles/filedetails/?id=2289315026 Point Templates].  It is highly recommended that you have a basic understanding of hammer and map logic beforehand, as well as a deep understanding of our [https://testing.potatomvm.tf/mvm_bigrock_sigdemo.pop popfile mods].


An example popfile for Rottenburg can be found [https://www.dropbox.com/s/iu84axj1r0vhg0y/mvm rottenburg reverse core logic.pop?dl=1rial mission here]
An example popfile for Rottenburg can be found [https://testing.potato.tf/tf/scripts/population/mvm_rottenburg_reverse_core_logic.pop here].


== Pacing and Structure ==
== Technical Implementation ==
[[File:Rotten.png|thumb|Custom spawn and sub-wave layout example for Rottenburg.]]
=== Lose Condition ===
While the majority of existing mvm maps are suitable, longer and more complex maps are best suited for reverse.  Bigrock, Mannhattan, and Rottenburg are examples of valve maps where it is relatively easy to stop players from getting to the hatch quickly, due to their layouts and/or overall length.  Shorter and more open-ended maps such as Decoy, Mannworks, and Coaltown are still completely valid options, however they will require ample counter-measures to avoid players bypassing every threat and camping at the hatch, usually by blocking the hatch until the last subwave is ended, or blocking off large regions of the map from access. 
In order to fail the wave when players lose, you will need to add your own [https://developer.valvesoftware.com/wiki/Game_round_win game_round_win] entity like so:
 
 
Once you've identified a map you feel is best for your mission, the next step is to create bot spawns that move progressively closer to the hatch, combined with sub-waves that give players adequate time to move forward and engage in the next sub-wave after it.  If each sub-wave and spawn location is balanced correctly, players will not spend the majority of their time in one part of the map.  If spawns are too fast and too close together, the mission will be a slog and players will struggle to progress.  If new sub-waves are too slow to begin and spawns are spread too far apart, the threat will be too spread out and players can simply ignore the next sub-wave, head straight to the hatch, and let everything come to them.  Do your best to strike a balance between these two extremes.
<syntaxhighlight lang="cpp">
PointTemplates [$SIGSEGV]
{
LoseRelay
{
NoFixup 1
game_round_win // RED win entity
{
"TeamNum" "2"
"targetname" "bots_win_red"
"switch_teams" "0"
"force_map_reset" "1"
"classname" "game_round_win"
}
logic_relay // Trigger this for player loss
{
"targetname" "redwin_relay"
"OnTrigger" "bots_win_red,RoundWin,,0,-1"
}
}
}
</syntaxhighlight>


Maps with gates are very useful for structuring your waves at the cost of simplicityYou can enable/disable bot spawns and connect your own custom logic to the outputs of the maps [https://developer.valvesoftware.com/wiki/Trigger_timer_door trigger_timer_door] entity using AddOutput, giving you the option to add rewards or enable new mission mechanics when capturing a gate.
It's up to you to decide how you want players to loseTimers, VIP Escort, and Tanks are popular ways to do so.


==Getting Started==
=== Preparing A Non-Reverse Map ===
Because many maps were not designed for this mode, it is recommended that you go through your map of choice and remove unwanted map entities, cover up holes in bot spawn with [https://developer.valvesoftware.com/wiki/Prop_dynamic prop_dynamic], and generally prepare your map beforehand.  For the bulk of custom logic, a [https://developer.valvesoftware.com/wiki/Logic_auto logic_auto] in combination with [https://developer.valvesoftware.com/wiki/AddOutput AddOutputs] is recommended, as it will instantly trigger when a new wave loads.  For example, if your mission gives the blue team infinite ammo, it wouldn't hurt to remove redundant ammo packs from the map like so  <syntaxhighlight lang="cpp">
Because many maps were not designed for this mode, it is recommended that you go through your map of choice and remove unwanted map entities, cover up holes in bot spawn with [https://developer.valvesoftware.com/wiki/Prop_dynamic prop_dynamic], and generally prepare your map beforehand.  For the bulk of custom logic, a simple [https://developer.valvesoftware.com/wiki/Logic_auto logic_auto] in combination with [https://developer.valvesoftware.com/wiki/AddOutput AddOutputs] will suffice, as it will instantly trigger when a new wave loads, however this can also be achieved with [[lua]] or [https://github.com/rafradek/VScript-Popfile-Extensions VScript].  For example, if your mission gives the blue team infinite ammo, it wouldn't hurt to remove redundant ammo packs from the map like so  <syntaxhighlight lang="cpp">
logic_auto  
logic_auto  
{
{
    "origin" "0 0 0"  
"origin" "0 0 0"  
    "targetname" "mainrelay"
"targetname" "mainrelay"
    "OnMapSpawn" "item_ammopack*,Kill,,0,-1"
"OnMapSpawn" "item_ammopack*,Kill,,0,-1"
}
}
</syntaxhighlight>  
</syntaxhighlight>


Many maps do not have gates or doors blocking the blue spawn area and will require you to add your own blockades.  This can be as simple as placing a prop in front of the spawn and killing it when the wave starts, or as complex as creating a moving gate using [https://developer.valvesoftware.com/wiki/Func_tracktrain func_tracktrain].  For our example, we'll be using a [https://developer.valvesoftware.com/wiki/Func_forcefield func_forcefield], an invisible wall which can be disabled and enabled when wave start/end relays trigger using some basic AddOutputs
==== Spawn Room ====
Many maps do not have gates or doors blocking the blue spawn area and will require you to add your own blockades.  This can be as simple as placing a forcefield in front of the spawn and killing it when the wave starts, or as complex as creating a moving gate using [https://developer.valvesoftware.com/wiki/Func_tracktrain func_tracktrain].  For our example, we'll be using a [https://developer.valvesoftware.com/wiki/Func_forcefield func_forcefield], an invisible wall which can be disabled and enabled when wave start/end relays trigger using some basic AddOutputs
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
PointTemplates [$SIGSEGV]
PointTemplates [$SIGSEGV]
Line 30: Line 52:
logic_auto  
logic_auto  
{
{
"origin" "0 0 0"
"targetname" "mainrelay"
"targetname" "mainrelay"
"OnMapSpawn" "item_ammopack*,Kill,,0,-1"
"OnMapSpawn" "item_ammopack*,Kill,,0,-1"
"OnMapSpawn" "wave_start_relay*,AddOutput,OnTrigger spawnbarrier:Disable:0:-1,0,-1"
"OnMapSpawn" "wave_start_relay*,AddOutput,OnTrigger spawnbarrier:Disable:0:-1,0,-1"
"OnMapSpawn" "wave_finished_relay*,AddOutput,OnTrigger spawnbarrier:Enable:0:-1,0,-1"
"OnMapSpawn" "wave_finished_relay*,AddOutput,OnTrigger spawnbarrier:Enable:0:-1,0,-1"
Line 43: Line 64:
func_forcefield
func_forcefield
{
{
"disablereceiveshadows" "0"
"targetname" "spawnbarrier"
"origin" "2724.365479 -2303.941650 -143.139458" //rottenburg spawn
"origin" "2724.365479 -2303.941650 -143.139458" // Rottenburg main spawn
"angles" "0 90 0"
"angles" "0 90 0"
"renderamt" "255"
"rendermode" "10" // 10 = Don't render
"rendercolor" "255 255 255"
"TeamNum" "2" // 2 for RED, 3 for BLU
"renderfx" "0"
"rendermode" "10" //10 = don't render
"TeamNum" "2" //2 for red, 3 for blu
"targetname" "spawnbarrier"
"mins" "-300 -300 -300"
"mins" "-300 -300 -300"
"maxs" "300 300 300" //300x300 hu cube
"maxs" "300 300 300" // 300x300HU cube
"StartDisabled" "0"
}
}
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>
''* is a [https://developer.valvesoftware.com/wiki/Wildcard wildcard] that can be used to reference multiple entities with the same prefix.  It is only limited to suffixes (*_start_relay* would not work)''  
''<sup>* is a [https://developer.valvesoftware.com/wiki/Wildcard wildcard] that can be used to reference multiple entities with the same prefix.  It is limited to suffixes only (i.e. "*_start_relay*" would not work).</sup>''  


''For more complex maps with a lot of entities, it may be beneficial to strip away unnecessary decorative elements of the map to avoid hitting the edict limitmove_rope and keyframe_rope for example.''
For more complex maps with a lot of entities, it may be beneficial to strip away certain decorative elements of the map to avoid hitting the [https://developer.valvesoftware.com/wiki/Edict_t#Limitations edict limit] of 2048 while the wave is active (such as move_rope and keyframe_rope).
 
==Lose Condition==
In order to fail the wave when players lose, you will need to add your own game_round_win entity like so:
 
<syntaxhighlight lang="cpp">
PointTemplates [$SIGSEGV]
{
LoseRelay
{
NoFixup 1
game_round_win //ignore this
{
"origin" "0 0 0"
"TeamNum" "2"
"targetname" "bots_win_red"
"switch_teams" "0"
"force_map_reset" "1"
"classname" "game_round_win"
}
logic_relay //trigger this
{
"origin" "0 0 0"
"targetname" "redwin_relay"
"OnTrigger" "bots_win_red,RoundWin,,0,-1"
}
}
}
</syntaxhighlight>


It's up to you to decide how you want players to lose.  Timers, VIP Escort, and Tanks are popular ways to do so.
==== Upgrade Station ====


== Upgrade Station ==
Upgrade stations will need to be placed in blue spawns.  Do your best to strategically place these in areas that don't interfere with spawn points and cover up holes in the map if there are any.  If your map has particularly cramped spawns, it might be wise to use a smaller model than the traditional one to signify an upgrade station, such as a resupply locker or a small weapons case. Do note the "mins" and "maxs" values for the func_upgradestation entity will need to be adjusted accordingly<syntaxhighlight lang="c++">
Upgrade stations will need to be placed in blue spawns.  Do your best to strategically place these in areas that don't interfere with spawn points and use them to cover up holes in the map.<syntaxhighlight lang="c++">


station
station
{
{
NoFixup 1
NoFixup 1
func_upgradestation //upgrade station entity
func_upgradestation // Upgrade station entity
{
{
"mins" "-105 -100 0"  
"mins" "-105 -100 0"  
Line 105: Line 92:
"solid" "0"
"solid" "0"
}
}
prop_dynamic //blu upgrade station model, can be found on potato servers
prop_dynamic // BLU upgrade station model, available on Potato servers
{
{
"targetname" "upgradestation"
"targetname" "upgradestation"
"angles" "0 0 0"
"model" "models/props_mvm/mvm_upgrade_blu.mdl"
"DisableBoneFollowers" "0"
"disablereceiveshadows" "0"
"disableshadows" "1"
"ExplodeDamage" "0"
"ExplodeRadius" "0"
"fademaxdist" "0"
"fademindist" "-1"
"fadescale" "1"
"MaxAnimTime" "10"
"maxdxlevel" "0"
"MinAnimTime" "5"
"mindxlevel" "0"
"model" "models\props_mvm\mvm_upgrade_blu.mdl"
"modelscale" "1"
"PerformanceMode" "0"
"pressuredelay" "0"
"RandomAnimation" "0"
"renderamt" "255"
"renderfx" "0"
"rendermode" "0"
"SetBodyGroup" "0"
"skin" "0"
"solid" "0"
"spawnflags" "0"
"origin" "0 0 0"
}
}
prop_dynamic //invisible collision prop  
prop_dynamic // Invisible collision prop
{
{
"targetname" "shopcollision"
"targetname" "shopcollision"
"angles" "0 -90 0"
"angles" "0 -90 0"
"DisableBoneFollowers" "1"
"disablereceiveshadows" "1"
"model" "models/props_vehicles/train_flatcar_container.mdl"
"model" "models/props_vehicles/train_flatcar_container.mdl"
"disableshadows" "1"
"rendermode" "10" // Don't render
"ExplodeDamage" "0"
"solid" "6" // Enable collisions
"ExplodeRadius" "0"
"fademaxdist" "0"
"fademindist" "-1"
"fadescale" "1"
"MaxAnimTime" "10"
"maxdxlevel" "0"
"MinAnimTime" "5"
"mindxlevel" "0"
"modelscale" "1"
"PerformanceMode" "0"
"pressuredelay" "0"
"RandomAnimation" "0"
"renderamt" "0"
"renderfx" "0"
"rendermode" "10"
"SetBodyGroup" "0"
"skin" "0"
"CollisionGroup" "5"
"solid" "6"
"spawnflags" "0"
"StartDisabled" "0"
"origin" "0 0 0"
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>
== Reverse Design Theory ==
=== Maps ===
While the majority of existing mvm maps are suitable, longer and more complex maps are best for reverse.  Bigrock, Mannhattan, and Rottenburg are examples of valve maps where it is relatively easy to stop players from getting to the hatch quickly, due to their layouts and/or overall length.  Shorter and more open-ended maps such as Decoy, Mannworks, and Coaltown, are still completely valid options, however they will require ample counter-measures to avoid players bypassing every threat and camping at the hatch.
==== Gate Maps ====
Maps with gates are very useful for structuring your waves at the cost of simplicity.  You can enable/disable bot spawns and connect your own custom logic to the outputs of the maps [https://developer.valvesoftware.com/wiki/Trigger_timer_door trigger_timer_door] entity using AddOutput, giving you the option to add rewards or enable new mission mechanics when capturing a gate.
==== Engineer Teleporter Types ====
There are 2 separate types of engineer teleporters: regular teleporters, and bot-style teleporters. Engineer bot teleporters act as a new spawn point, and will instantly teleport players to an exit on respawn with no entrance required.  It is recommended to only use bot-style teleporters in long maps that do not use gates, combining gates with this feature can confuse newer players.
=== Placing Spawns ===
[[File:Rotten.png|thumb|Custom spawn and sub-wave layout example for Rottenburg.]]
The best red spawn locations are not immediately noticeable and let bots navigate the map to hunt down players as efficiently as possible, regardless of the bomb path.
Spawning bots in easy to notice areas can break the illusion of RED having control over the map, and should be avoided.  Spawning bots very far away from the player however is equally problematic, and can ruin wave pacing.  It’s important to strike a balance between these two extremes.
=== Friendly Robots ===
When adding friendly bots to your mission, you should balance them to be considerably weaker than the upcoming red robots.  If your friendly bots are strong enough to beat the mission without player interference in a reasonable amount of time, players won't feel very engaged.  A good system for picking good friendly robots is to pick the less dangerous variant of bots you are using in your waves.  If a certain sub-wave uses crit rapid fire giant soldiers on red, send out normal giant soldiers on blu.  This way, blu robots are at an inherent disadvantage and need players to assist them to progress.     
It is recommended that VIP escorting objectives be very forgiving unless you specifically force the bot to only follow players.  Do note that players are able to interact with bots in several ways.  Heavies can heal them with lunchbox items, medics can uber them, soldiers can whip them, and bots will take nearby active teleporters.  All of these features can be modified or disabled.   


__FORCETOC__
__FORCETOC__
[[Category: Tutorials]]
[[Category: Tutorials]]

Latest revision as of 15:08, 14 November 2023

Reverse MvM is a combination of custom popfile keyvalues that flips the teams and win conditions. Instead of defending against hordes of robots, players are spawned on the blue team and must fight their way to the hatch and deliver the bomb. Designing missions around this concept can be very complex and requires heavy usage of Point Templates. It is highly recommended that you have a basic understanding of hammer and map logic beforehand, as well as a deep understanding of our popfile mods.

An example popfile for Rottenburg can be found here.

Technical Implementation[edit | edit source]

Lose Condition[edit | edit source]

In order to fail the wave when players lose, you will need to add your own game_round_win entity like so:

PointTemplates [$SIGSEGV]
{
	LoseRelay 
	{
		NoFixup 1
		game_round_win		// RED win entity
		{
			"TeamNum" "2"
			"targetname" "bots_win_red"
			"switch_teams" "0"
			"force_map_reset" "1"
			"classname" "game_round_win"
		}
		logic_relay		// Trigger this for player loss
		{
			"targetname" "redwin_relay"
			"OnTrigger" "bots_win_red,RoundWin,,0,-1"
		}	
	}
}

It's up to you to decide how you want players to lose. Timers, VIP Escort, and Tanks are popular ways to do so.

Preparing A Non-Reverse Map[edit | edit source]

Because many maps were not designed for this mode, it is recommended that you go through your map of choice and remove unwanted map entities, cover up holes in bot spawn with prop_dynamic, and generally prepare your map beforehand. For the bulk of custom logic, a simple logic_auto in combination with AddOutputs will suffice, as it will instantly trigger when a new wave loads, however this can also be achieved with lua or VScript. For example, if your mission gives the blue team infinite ammo, it wouldn't hurt to remove redundant ammo packs from the map like so

logic_auto 
{
	"origin" "0 0 0" 
	"targetname" "mainrelay"
	"OnMapSpawn" "item_ammopack*,Kill,,0,-1"
}

Spawn Room[edit | edit source]

Many maps do not have gates or doors blocking the blue spawn area and will require you to add your own blockades. This can be as simple as placing a forcefield in front of the spawn and killing it when the wave starts, or as complex as creating a moving gate using func_tracktrain. For our example, we'll be using a func_forcefield, an invisible wall which can be disabled and enabled when wave start/end relays trigger using some basic AddOutputs

PointTemplates [$SIGSEGV]
{
	corelogic
	{
		NoFixup 1
		logic_auto 
		{
			"targetname" "mainrelay"
			"OnMapSpawn" "item_ammopack*,Kill,,0,-1"
			
			"OnMapSpawn" "wave_start_relay*,AddOutput,OnTrigger spawnbarrier:Disable:0:-1,0,-1"
			"OnMapSpawn" "wave_finished_relay*,AddOutput,OnTrigger spawnbarrier:Enable:0:-1,0,-1"
		}
	}
	forcefield
	{  
		NoFixup 1
		func_forcefield
		{
			"targetname" "spawnbarrier"
			"origin" "2724.365479 -2303.941650 -143.139458"	// Rottenburg main spawn
			"angles" "0 90 0"
			"rendermode" "10"		// 10 = Don't render
			"TeamNum" "2"		// 2 for RED, 3 for BLU
			"mins" "-300 -300 -300"
			"maxs" "300 300 300"		// 300x300HU cube
		}
	}
}

* is a wildcard that can be used to reference multiple entities with the same prefix. It is limited to suffixes only (i.e. "*_start_relay*" would not work).

For more complex maps with a lot of entities, it may be beneficial to strip away certain decorative elements of the map to avoid hitting the edict limit of 2048 while the wave is active (such as move_rope and keyframe_rope).

Upgrade Station[edit | edit source]

Upgrade stations will need to be placed in blue spawns. Do your best to strategically place these in areas that don't interfere with spawn points and cover up holes in the map if there are any. If your map has particularly cramped spawns, it might be wise to use a smaller model than the traditional one to signify an upgrade station, such as a resupply locker or a small weapons case. Do note the "mins" and "maxs" values for the func_upgradestation entity will need to be adjusted accordingly

		station
		{
			NoFixup 1
			func_upgradestation		// Upgrade station entity
			{
				"mins" "-105 -100 0" 
				"maxs" "105 100 242"
				"solid" "0"
			}
			prop_dynamic	// BLU upgrade station model, available on Potato servers
			{
				"targetname" "upgradestation"
				"model" "models/props_mvm/mvm_upgrade_blu.mdl"
			}
			prop_dynamic	// Invisible collision prop
			{
				
				"targetname" "shopcollision"
				"angles" "0 -90 0"
				"model" "models/props_vehicles/train_flatcar_container.mdl"
				"rendermode" "10"		// Don't render
				"solid" "6"		// Enable collisions
			}		
		}

Reverse Design Theory[edit | edit source]

Maps[edit | edit source]

While the majority of existing mvm maps are suitable, longer and more complex maps are best for reverse. Bigrock, Mannhattan, and Rottenburg are examples of valve maps where it is relatively easy to stop players from getting to the hatch quickly, due to their layouts and/or overall length. Shorter and more open-ended maps such as Decoy, Mannworks, and Coaltown, are still completely valid options, however they will require ample counter-measures to avoid players bypassing every threat and camping at the hatch.

Gate Maps[edit | edit source]

Maps with gates are very useful for structuring your waves at the cost of simplicity. You can enable/disable bot spawns and connect your own custom logic to the outputs of the maps trigger_timer_door entity using AddOutput, giving you the option to add rewards or enable new mission mechanics when capturing a gate.

Engineer Teleporter Types[edit | edit source]

There are 2 separate types of engineer teleporters: regular teleporters, and bot-style teleporters. Engineer bot teleporters act as a new spawn point, and will instantly teleport players to an exit on respawn with no entrance required. It is recommended to only use bot-style teleporters in long maps that do not use gates, combining gates with this feature can confuse newer players.

Placing Spawns[edit | edit source]

Custom spawn and sub-wave layout example for Rottenburg.

The best red spawn locations are not immediately noticeable and let bots navigate the map to hunt down players as efficiently as possible, regardless of the bomb path.

Spawning bots in easy to notice areas can break the illusion of RED having control over the map, and should be avoided. Spawning bots very far away from the player however is equally problematic, and can ruin wave pacing.  It’s important to strike a balance between these two extremes.

Friendly Robots[edit | edit source]

When adding friendly bots to your mission, you should balance them to be considerably weaker than the upcoming red robots. If your friendly bots are strong enough to beat the mission without player interference in a reasonable amount of time, players won't feel very engaged. A good system for picking good friendly robots is to pick the less dangerous variant of bots you are using in your waves. If a certain sub-wave uses crit rapid fire giant soldiers on red, send out normal giant soldiers on blu. This way, blu robots are at an inherent disadvantage and need players to assist them to progress.

It is recommended that VIP escorting objectives be very forgiving unless you specifically force the bot to only follow players. Do note that players are able to interact with bots in several ways. Heavies can heal them with lunchbox items, medics can uber them, soldiers can whip them, and bots will take nearby active teleporters. All of these features can be modified or disabled.