Creeper, aw man
Using State as template for this page. :earless:
Felt like writing down what could a custom gamemode framework of sorts be like.
A gamemode, or a gametype (not exactly the same thing?), is a distinct configuration that varies gameplay and affects how other game mechanics behave. just writing this here, it's handy
What if...
Gamemodes are referenced by a constant. 0 for Singleplayer/Co-op, 1 for competition, and so on. States, objects, sprites(?) and sound effects are also referenced (internally) by a constant!
The game has free space to allow modders to allocate their own objects/states/what have you, and then reference them by a constant with a "random" number assigned to it (more like the first available slot).
Therefore, we could do the same with custom gamemodes!
Freeslot
could be used to "create" a new gamemode by using the GT_
prefix, allowing us to reference it later on.
Attributes
Gamemodes would have "attributes" that would define if the game would carry out some vanilla actions on specific circumstances or not.
Name
: The name that would show up in the hosting screen when scrolling through gametypes.Flag
: A flag for theLevel
header to use.CanUse
: A list of gametype flags, separated by commas, signaling the game that this gametype can alternatively use levels that contain any of these TypeOfLevel flags.Spectators
: Whether this gametype allows spectating. An 1 would allow players to enter spectator mode, while a 0 would force everyone into the game, like Co-op.
To add to this, if the gametype changes from a non-spectators one to another with spectators, everyone will be immediately sent to spectator.
Teams
: A comma separated list of stylized team names. If this value exists,Enter game...
is replaced bySwitch team...
with a list of available teams using the names set here, along with the spectator team if applicable. Each team is assigned a number, just like red is 1 and blue is 2 in CTF, and so on. The modder is then tasked on handling colors and the HUD.
Same as above, if the gametype changes from one without teams to one with teams, everyone is sent to spectator. However, everyone will remain in their playing state if changing from a teamed gametype to a non-teamed one.
UseRespawnDelay
: If 1, whether the game delays respawning, using the respawndelay CVar.WeaponRings
: If 1, ringslinger is forced on. This allows the default weapon rings to spawn in the map, and shows the weapon selector.Emeralds
: If 1, spawn vanilla match emeralds in their respective spawn points.TimeLimit
: Default time limit value for this gametype.PointLimit
: Default point limit value for this gametype. For this value and the above, a host switching gametypes will make the game read these two values and apply them once, as to "initialize" the default limits.:
:
Level header?
Levels have a TypeOfLevel
value which tells the game, well, what type of level is it. Is it for Co-op? For race? For match?
If you freeslot a gametype, you are forced to enter a flag name, the which you can now use as a TypeOfLevel flag of sorts. Even if the flag wasn't defined, you should be able to use it regardless - It wouldn't work, of course, but once a gamemode adds such flag, it will be used.
Level/Gamemode attribute interaction
When generating a list of maps a gametype can use (does the game even do this? Imagine it does), the game could look for levels containing either the gamemode specific flag, or flags specified by the gamemode in CanUse
.
For example, Chaos works on both chaos specific maps and in match maps. The gamemode was defined with CanUse
having the value of Match
.
When the game makes the list, it will look for maps with TypeOfLevel
containing either Chaos
or Match
, and adds it to the list if there was a match.
Lua interaction
As this is aimed to Lua scripting, modders could be given more tools to handle their gametype.
The game should expose both time limit and point limit to Lua as a read and write variable - That way, the modder doesn't have to create a separate CVar for their gametype's scoring methods, and also set some restraints.
On top of that, vanilla behaviour of ending the map when reaching the time/point limit should be disabled, allowing the modder to decide when to actually end the map, for example because of there being some sort of tie-breaker period, or just creating an animation on round end.
inttime
should be an exposed read only variable, specifically for the intermission hooks.
An intermission HUD hook would allow modders to customize the rankings screen with information relevant to their gametype, with a default level screenshot as the default backdrop and the inttime counter at the bottom. That way they can display team score, winners, something resembling the Co-op level end screen, and so.
Also, hooks!
Non-HUD hooks
ViewpointSwitch
Hook format: addHook("ViewpointSwitch", functionname)
Function format: function(player_t player, player_t targetplayer)
Function return value: Boolean (allow switch?)
When a player presses the Change Viewpoint button, this hook is called to decide whether the next player is suitable as a viewpoint.
This calls the function given with the player next in the list starting from the current player. Should this return false, the hook will then be called with the next player in the list, looping around if we reached the end. If this returns true, the loop ends and the viewpoint is changed to targetplayer.
For example, if there is a team gametype with red and blue teams, you wouldn't want the living to be able to spectate their opponents, while spectators can spectate any player.
If a red team member changes viewpoints, ViewpointSwitch could be called with the targetplayer being in the blue team. Returning false will then call this function again with the next person in line until reaching either another red team member or themselves, then which the hook would return true and change viewpoints accordingly.
TeamSwitch
Hook format: addHook("TeamSwitch", functionname)
Function format: function(player_t player, number team)
Function return value: Boolean (allow switch?)
Whether player
can switch to team team
. Returning false would slow the player a "Can't switch to this team" message.
There may be events in the which the modder would want to prevent team switching, as to prevent cheating or otherwise.
Other interactions
How would the master server identify these gametypes if they are sent as a number?
Maybe the master server could report a "custom" or "unknown" gametype if it doesn't match any of the vanilla values.
Or the game could additionally send the gametype string and other gametype related data to the master server, the which can't use anyways lol
SOC definition
An example of a gamemode definition written with SOC. I'm not exactly experienced with SOC, but this is a general idea.
Freeslot GT_CHAOS Gametype GT_CHAOS Name = Chaos Flag = Chaos CanUse = Match,CTF Level MC Name = Probably a valid map TypeOfLevel = Match,Chaos
Freeslot GT_BATTLERACE # lol cool name Gametype GT_BATTLERACE Name = Battle Race Flag = BattleRace CanUse = Race,SP,Co-op,Competition Level 1 Name = Yellowdandelion Area TypeOfLevel = SP,Race,All of these flags up there Level 99 Name = A battle race specific map TypeOfLevel = Race,BattleRace
Lua definition?
This page was more or less aimed for gamemode implementation using SOC for Lua to access later, but I didn't get to this part yet :^)