Quake II Rerelease Game Source This repository contains the game code for the 2023 rerelease of Quake II, for users who wish to mod the gam…
Quake II Rerelease Game Source This repository contains the game code for the 2023 rerelease of Quake II, for users who wish to mod the gam…
This repository contains the game code for the 2023 rerelease of Quake II, for users who wish to mod the game, along with the original game code that was use for reference. Mods can be loaded into the rerelease the same way as the original game: launch the game with +set game mymod or type game mymod into the console while the game is running. We recommend installing mods into your %USERPROFILE%\Saved Games\Nightdive Studios\Quake II directory to ensure the original game files do not get modified.
id Software is unable to provide support for this release, however we urge you to take advantage of the depth of community-driven resources already available.
The rerelease of Quake II uses a new version of the API to communicate between the server & the game module. It also introduces a very thin "client game" module, akin to Quake III Arena's cgame module, to allow for extended modding opportunities that change previously hardcoded client behavior. It also has a new network protocol, version 2023.
This codebase is a combination of the separate game modules that were part of the original game: baseq2, ctf, rogue, and xatrix. It requires a C++17 compiler. In cases of conflicting spawnflags, maps were modified in order to resolve issues, so original expansion pack maps may not load correctly with this DLL. The combined FGD as used for development is also available for users wishing to make new maps. A modified TrenchBroom Quake II gameconfig.cfg is included as there are modified textureflags.
Because the game export interface has changed, existing mods may be able to be moved over to support the API changes. However, in order to support all expansion packs under one codebase and new features in the rerelease, there have been some major changes to structure and layout, so old mods wishing to use the new codebase may need to be rewritten.
The API changes discussed here are written from the perspective of the game DLL.
The game DLL has only been tested with Clang, VS2019 and VS2022.
The code can compile under both C++17 and C++20. Using C++20 allows you to skip fmtlib as a dependency.
GAME_INCLUDE must be defined, tells game.h that this is the game DLL compiling it.KEX_Q2GAME_EXPORTS must be defined, tells game.h that we are exporting the GetGameAPI function.KEX_Q2GAME_DYNAMIC must be defined. The game DLL supports static linking on console platforms, but is always dynamic on PC.NO_FMT_SOURCE: this is only here because of a limitation in the internal build system. It must be defined.KEX_Q2_GAME: must be defined if compiling for Kex. This changes the behavior of the say command to go through the lobby.KEX_Q2GAME_IMPORTS: only used by engine, tells game.h that we are importing GetGameAPI.USE_CPP20_FORMAT: if explicitly defined, C++20's <format> library will be used instead of fmtlib; otherwise fmtlib usage will be autodetected.USE_CPP20_FORMAT is not set, the library needs to be available in the fmt subdirectory.json subdirectory.Both of these can also be installed via vcpkg: vcpkg install jsoncpp:x64-windows fmt:x64-windows
baseq2, make a folder called mymod, enter that folder, make a folder called src, and copying the contents of the rerelease directory into the newly-created src subfolder.game.slnDebugging the DLL is possible when attaching to the engine EXE. Note that if you are using VS2022 Hot Reload, due to an internal Hot Reload issue, current edits will be lost when disconnecting from the server, or changing levels using the map command.
As part of this release, all internal logic in the game DLL has been adjusted to run at 40hz compared to the original 10hz of the original engine. This provides a better gameplay experience, and allows maps and game logic to run at more precise steps than the original 100ms. 40hz was chosen as it is a multiple of the original 10hz, operates at an integral 25ms step, and was the best balance between bandwidth and CPU concerns around the original tech.
As part of the API cleanup, the game DLL no longer uses varargs in any of its functions. Varargs are compiler-specific and not very portable, so instead, the onus is on the caller to handle formatting. As a bonus, this allows the game DLL to more easily hook in modern formatting providers; the game DLL uses fmt almost exclusively. Several built-in types, like edict_t and vec3_t, can be formatted directly.
Since C++ is now used in the game DLL, math functions were made constexpr where appropriate, and operator overloads are used to make math easier to work with and closer to QuakeC. For instance, VectorMA(a, s, b, c) can now be written as c = a + (b * s), which expresses the operation better.
qboolean, which was aliased to int32_t, is now instead aliased to bool. This type should be equivalent to C's _Bool.
In the original Quake II, all infokey values are purely ASCII with upper bits stripped. Kex and the Quake II rerelease engine supports UTF-8 for things like player names, which necessated a change to the way info keys work. Instead of implementing a whole UTF-8 system in the game DLL, these functions are now imports, so the engine is in control of the parsing and string management.
Userinfo variables are now suffixed with a number for split screen support. For instance, name and skin have become name_0 and skin_0 for the first player, name_1 and skin_1 for the second player, and so on.
In an attempt to remain compatible with future community engines, all engine interfaces contain stubbed functions for GetExtension. This is currently unused and will only return nullptr, however other engines may wish to support returning named structs containing extra function pointers based on string parameters. This is similar to getextension that has become standard in many QuakeC environments.
Conforming engines should return nullptr if an extension is not supported, otherwise they should return a non null pointer value that is relevant to the requested feature. Supporting engines should use namespaces for features to prevent name collisions around common and possibly incompatible implementations.
Player movement ("pmove") is now handled as an export in both game_export_t and cgame_export_t. This allows a game module to modify physics while still working with client prediction. Pmove also received several upgrades, such as more bits for flags and full float positioning.
Because a lot of movement quirks in Quake II were indirectly caused by the compression, these behaviors were retained. Trick jumping is now an explicit movement type, to allow for things like the Mega Health box jumps to still work. Some fixes were made, like jumping higher below the 0 z point of the map.
As part of network improvements, some changes were made to the "entity is visible to client in frame" methods:
To fix a legacy bug where lasers only relied on one position for culling, RF_BEAM entities now set their absmin & absmax properly. This can cause them to be a bit inflated if they are angled, but should not cause any issues otherwise.
In a similar vein, gi.linkentity no longer automatically sets old_origin for beams. This is to make it a bit easier to work with beams, as otherwise you'd be forced to link twice to get it linked into the world correctly. This might break old mods that depends on this behavior.
Entity spatialization underwent an overhaul (CL_GetEntitySoundOrigin mainly).
s.sound, and plays their sound on the nearest point between the two beam origins.As a secondary fix to the above, S_StartSound has slightly different logic now surrounding what origin to pick when playing a sound:
if (entnum < MAX_EDICTS && (origin || fixed_origin))
{
// [Paril-KEX] if we can currently see the entity in question
// and it's a bmodel or beam, don't use a fixed origin so it sounds correct
if (!fixed_origin && entnum > 1 && (cl_entities[entnum].serverframe == cl.frame.serverframe ||
(cl_entities[entnum].current.solid == PACKED_SOLID_BSP || (cl_entities[entnum].current.renderfx & RF_BEAM))))
{
ps->fixed_origin = false;
}
else
{
VectorCopy (origin, ps->origin);
ps->fixed_origin = true;
}
}
else
ps->fixed_origin = false;fixed_origin is set to flags & SND_EXPLICIT_POS for svc_sound packets, and is false otherwise. If the playsounds' fixed_origin field is set, then the ps->origin value will always be used over automatically trying to determine its position.
TE_ELECTRIC_SPARKS and TE_SCREEN_SPARKS/TE_SHIELD_SPARKS will only play sounds once on any given frame.delta_angles are interpolated now, although this is never used at all in the game.screen_blend and damage_blend are interpolated now, but only if the frame prior didn't have a clear color.Configstrings have been overhauled. There is now a theoretical maximum of 32767 entries, although you are still bound by the game APIs value of MAX_CONFIGSTRINGS.
The maximum length of a configstring has increased from 64 to 96.
The API now canonizes that certain spans (CS_STATUSBAR and CS_GENERAL) can span multiple lines. A CS_SIZE function is provided to calculate the total size (in bytes) that can be written to for a given configstring ID.
A convenience function, CS_REMAP, is provided to help remap old configstring IDs to new ones. This is used in our engine to provide old demo support.
MAX_MODELS, MAX_SOUNDS and MAX_IMAGES have been increased from 256 to 8192, 2048, and 512, respectively.
This entry now spans entries 5 to 58 instead of 5 to 28, giving you an effective size of 5184 bytes (minus one for the null terminator) for the statusbar strings, up from 1536 bytes.
This new span each consists of a shadow light entry. Its format is semicolon-separated numerical values, in the following type & order:
This new span consists of entries for the weapon wheel. It consists of pipe-separated integral values, in the following order:
No open issues yet, or sync has not completed.