Custom gametypes
This is a work-in-progress framework I wrote for custom gametypes. In a gross simplification, every piece of gamelogic belonging to certain gametypes were split off into their own flags that can be combined together to form a gametype. Those are called "gametype rules".
Rule list
These are the current gametype rules available:
Keyword | Explanation or default availability |
---|---|
GTR_CAMPAIGN |
Linear Co-op map progression, don't allow random maps |
GTR_RINGSLINGER |
Outside of Co-op, Competition, and Race (overriden by cv_ringslinger) |
GTR_SPECTATORS |
Outside of Co-op, Competition, and Race |
GTR_FRIENDLYFIRE |
Always allow friendly fire |
GTR_LIVES |
Co-op and Competition |
GTR_TEAMS |
Team Match, CTF |
GTR_RACE |
Race and Competition |
GTR_TAG |
Tag and Hide and Seek |
GTR_POINTLIMIT |
Ringslinger point limit |
GTR_TIMELIMIT |
Ringslinger time limit |
GTR_HIDETIME |
Hide time (Tag and Hide and Seek) |
GTR_HIDEFROZEN |
Frozen after hide time (Hide and Seek, but not Tag) |
GTR_BLINDFOLDED |
Blindfolded view (Tag and Hide and Seek) |
GTR_FIRSTPERSON |
First person camera |
GTR_MATCHEMERALDS |
Ringslinger emeralds (Match and CTF) |
GTR_TEAMFLAGS |
Gametype has team flags (CTF) |
GTR_PITYSHIELD |
Award pity shield |
GTR_DEATHPENALTY |
Death score penalty |
GTR_NOSPECTATORSPAWN |
Use with GTR_SPECTATORS , spawn in the map instead of with the spectators |
GTR_DEATHMATCHSTARTS |
Use deathmatch starts |
GTR_SPECIALSTAGES |
Allow special stages |
GTR_EMERALDTOKENS |
Spawn emerald tokens |
GTR_EMERALDHUNT |
Emerald Hunt |
GTR_SPAWNENEMIES |
Spawn enemies |
GTR_ALLOWEXIT |
Allow exit sectors |
GTR_NOTITLECARD |
Don't show the title card |
GTR_OVERTIME |
Allow overtime |
GTR_HURTMESSAGES |
Hit and death messages |
GTR_SPAWNINVUL |
Babysitting deterrent |
Default used ruleset, for reference:
// Gametype rules
UINT32 gametypedefaultrules[NUMGAMETYPES] =
{
// Co-op
GTR_CAMPAIGN|GTR_LIVES|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES,
// Competition
GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
// Race
GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
// Match
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD|GTR_DEATHPENALTY,
// Team Match
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_SPAWNINVUL|GTR_PITYSHIELD,
// Tag
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL,
// Hide and Seek
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL,
// CTF
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_SPAWNINVUL|GTR_PITYSHIELD,
};
Creating new gametypes
Gametypes can be defined with either SOC or Lua. Here's an example of a gametype definition in SOC:
FreeSlot
TOL_HANGOUT
GameType Hangout
TypeOfLevel = Coop,Hangout
Spectators = True
NoSpectatorSpawn = True
NoTitleCard = True
AllowExit = False
SpawnEnemies = False
Lives = False
EmeraldHunt = False
EmeraldTokens = True
IntermissionType = int_coop
HeaderLeftColor = 103
HeaderRightColor = 109
Description = "Bruh" is a popular variant of the slang term "bro" that is often used as an interjection to convey frustration or disappointment at something. Online, the term is
#
Here, this gametype defines its own TypeOfLevel
to be used in map headers, and toggles gametype rules using keywords. The level platter is also configured here. The description mush be terminated with a #
character (number sign.)
SOC keywords
Keyword | Explanation | Example |
---|---|---|
RULES | Game type rules | Rules = GTR_RINGSLINGER |
IDENTIFIER | Game type constant (GT_)
|
Identifier = CHILLAX (turns into GT_CHILLAX ) |
DEFAULTTIMELIMIT | Time limit in minutes | DefaultTimeLimit = 10 |
DEFAULTPOINTLIMIT | Point limit | DefaultPointLimit = 1050 |
HEADERCOLOR | Level platter header color | HeaderColor = 15 |
HEADERLEFTCOLOR | Level platter header color (left side) | HeaderLeftColor = 103 |
HEADERRIGHTCOLOR | Level platter header color (right side) | HeaderRightColor = 109 |
DESCRIPTION | Level platter description | |
RANKINGTYPE | Score rankings type | RankingType = GT_RACE |
INTERMISSIONTYPE | Intermission type | IntermissionType = int_coop |
TYPEOFLEVEL | Type of level | TypeOfLevel = Match,Tag |
Intermission types
Constant | Type |
---|---|
int_none |
Nothing |
int_coop |
Single Player/Cooperative |
int_match |
Match |
int_teammatch |
Team Match |
int_ctf |
CTF |
int_spec |
Special Stage |
int_race |
Race |
int_comp |
Competition |
In Lua, this would be the same definition:
freeslot("TOL_HANGOUT")
G_AddGametype({
name = "Hangout",
identifier = "chillax",
typeoflevel = TOL_COOP|TOL_HANGOUT,
rules = GTR_SPECTATORS|GTR_NOSPECTATORSPAWN|GTR_NOTITLECARD|GTR_EMERALDTOKENS,
intermissiontype = int_coop,
headerleftcolor = 103,
headerrightcolor = 109,
description = '"Bruh" is a popular variant of the slang term "bro" that is often used as an interjection to convey frustration or disappointment at something. Online, the term is'
})
Lua keywords
Keyword | Explanation |
---|---|
name | Game type name |
identifier | Game type constant (GT_)
|
rules | Game type rules |
typeoflevel | Type of level |
rankingtype | Score rankings type |
intermissiontype | Intermission type |
defaultpointlimit | Point limit |
defaulttimelimit | Time limit in minutes |
description | Level platter description |
headerleftcolor | Level platter header color (left side) |
headerrightcolor | Level platter header color (right side) |
headercolor | Level platter header color |
Lua hooks
Two new Lua hooks are available - TeamSwitch
and ViewpointSwitch
.
TeamSwitch
Hook format: addHook("TeamSwitch", functionname)
Function format: function(player_t player, int team, boolean fromspectators, boolean autobalance, boolean scramble)
Function return value: boolean
(true
to allow team switch, false
to disallow team switch), nil
(does nothing)
This hook runs when the player switches teams. Returning true
allows team switch, and returning false
disallows team switch.
ViewpointSwitch
Hook format: addHook("ViewpointSwitch", functionname)
Function format: function(player_t player, int newdisplayplayer, boolean forcedviewpointswitch)
Function return value: boolean
(true
to force viewpoint switch, false
to skip player about to be viewed), nil
(does nothing)
This hook runs when the player uses spy mode. Returning true
forces a viewpoint switch, and returning false
avoid viewing the other player. forcedviewpointswitch
will be true
if the viewpoint switch was not caused by F12 (example, the player currently being viewed leaves the netgame.)