.map
file having NaN
values.sv_allowbunnyhopping
to control whether the bunny hopping limiter is enableddelta.lst
when building client or server to ensure mods have correct delta.lst
file (defines networking properties for data types)func_tank_of
and other OF tank entities firing many attacks at the same time at players if they hide behind obstacles for a few secondsSchedule_t
, CBaseMonster
& CCineMonster
to make it easier to debug NPCs and scripts using the Visual Studio debuggerfunc_tank
entities not respecting persistence and not being able to switch targets properly if target is behind coverfunc_tank
and other tank entities firing many attacks at the same time at players if they hide behind obstacles for a few seconds (same fix as in Opposing Force, applies to regular tank entities here)sv_infinite_ammo
& sv_bottomless_magazines
to override skill variablesofboot1
after loading a save gamefunc_tank
entities using persistence keyvalue (func_tank_of
entities do not use this keyvalue and act as though it is set to 0)ba_power2
of5a2
not playing eat scripts (Xen area reached via Displacer)ba_outro
having wrong body groupsfidgetnip
animation leaving the left hand in an awkward position at the end of the animationportal
animation cutting off dialogue due to sounds played on voice channel (affects c3a2d
, final Lambda Core level)deadhaz.mdl
helmet submodel including Gordon's head causing his glasses and ponytail to clip through the helmetTE_PLAYERATTACHMENT
message instead. It creates a temporary entity attached to the player that sticks around for a specific amount of time.clientIndex
variable in TEMPENTITY
along with the flags FTENT_PLYRATTACHMENT
and FTENT_PERSIST
, so if this message doesn't do the trick you can make your own. The rest of TEMPENTITY
's variables you should be able to set up like you would a server side entity.null.mdl
failing to load)External texture file "<filename>" does not exist or is currently opened by another program
messageAhhh I see. That's a darn shame, I loved that sound lol. And you're once again an absolute legend for adding that bunnyhop cvar. I made a video about your unified SDK btw, just released it today. https://www.youtube.com/watch?v=EzvoI6nFvf8That's nice. Thanks for making a presentation of what the project does.
So even with all these changes to the code, there's still no way to bring back gunshot impact sounds for the player's bullets? And a cvar to enable / disable bhop cap would be very welcome for someone like myselfI've added a cvar
sv_allowbunnyhopping
to control the bunny hopping limiter. That can be used to allow unconstrained movement speed.MAX_MAP_PLANES
limithalflife_updated_addon/map/graphs
)O
to match Opposing Forcemonster_generic
CBaseMonster
from being +USEable)json_debug
cvar (redundant, server commands require rcon access)allow_follow
being set on script entitiesenv_spritetrain
sounds when upgrading maps (same as func_train
)config.cfg
file with correct key bindingsMapUpgraderDocGenerator
: converts XML documentation generated by C# compiler for the MapUpgrader.Upgrades
library to Markdown for use in documentationnonfunctional-prototype-scripting
.multiplayer_only
option.cheat_jetpack
: When enabled, players can fly by holding down the jump button and accelerate forward when holding the forward movement buttonimpulse 101
(MP5 gets full magazine)CBaseMonster::DropItem
to drop any entity (fixes Shock Troopers not dropping roaches)c2a5
to stop them from disappearing when entering through level changebs_sentences.json
)ba_tram2
that references Freeman and HEV suit in errorturretrot1.wav
sound played by loader modelcl_custom_message_text
cvar to display a custom message on-screen, along with cl_custom_message_x
and cl_custom_message_y
to control the position on-screen (works like game_text
)sv_snd_openal
and cl_snd_openal
cvars (sound is played through the OpenAL sound system only now)(ai)scripted_sequence
to prevent players from activating them with +USE (scripts share code with NPCs, including follower code)HUD_Init
and HUD_VidInit
sentences.txt
to sentences.json
sentences.txt
with sentences.json
{
"Sentences": [
// Grenade Warning
"HG_GREN0 hgrunt/clik(p120) grenade! clik",
"HG_GREN1 hgrunt/(t30) clik take!(e75) cover!(s5) clik",
"HG_GREN2 hgrunt/clik clik oh! shit! clik",
"HG_GREN3 hgrunt/(p110 t40) clik(p120) get!(e78) down!(t30) clik",
"HG_GREN4 hgrunt/clik(p110) (t40) of!(e75) god! clik(p110)",
"HG_GREN5 hgrunt/clik no! clik",
"HG_GREN6 hgrunt/clik move! clik(p120)"
],
"Groups": {
"HG_GREN": [
"HG_GREN0",
"HG_GREN1",
"HG_GREN2",
"HG_GREN3",
"HG_GREN4",
"HG_GREN5",
"HG_GREN6"
]
}
}
Sentences
is a list of strings containing the sentences, just like before.Groups
is an object of group names to lists of sentences that are in that group.Sentences2Json
has been added that can convert the old format to the new. It also prints warnings if invalid or duplicate sentences are encountered. The default file has a few of those.BA_POK
group being replaced, which is played when you +USE a pre-disaster Barney, as well as the scripted sentence BA_SEC2_NOPASS
which plays when trying to continue in the Insecurity
chapter before you've got your armor:
{
"Sentences": [
"BA_POK0 hgrunt/clik(p110) (t40) freeman you are lay!(e90) team!(e20) clik(p120) clik",
"BA_SEC2_NOPASS barney/c2a4_ba_longnite"
],
"Groups": {
"BA_POK": [
"BA_POK0"
]
}
}
This becomes:
Note that you can reload the map to test changes as opposed to the original game which requires a full restart.
ent_list
client command to avoid network buffer overflowspev->body
instead of a separate body
parameterchainsaw_melee
skill variable: enables buggy melee attack behavior causing corpses to be damaged much fastergame_end
is used to end multiplayer game (allows Co-op maps to clear state that may affect other maps)..
(parent directory)child_classification
keyvalue to allow NPCs that spawn NPCs (e.g. Big Momma, Osprey) to pass on classificationsunkillable
keyvalue & cheat_unkillable
: Makes NPCs and players unkillable, respectively. Not all NPCs support this settingmonster_*_dead
NPCs that should use human gibs as such so they spawn gibssv_load_all_maps
command to load all maps and generate node graph for them (allows leaving the game running on its own, can also be used to generate a log containing any errors logged by the game)buddha
cheat.
func_tank
entitiesallow_weapon_dropping
skill var to allow_player_weapon_dropping
, added allow_npc_item_dropping
to globally control whether NPCs can drop items on deathfunc_train
move sound when triggered off (fixes sound looping issue in c1a0c
(first Unforeseen Consequences map))scripted_sequence
by +using friendly NPCs to make them follow playerscripted_sequence
ent.io
trace logging for multi_manager
startmonstermaker
entities using provided keyvaluestrigger_changekeyvalue
logicmulti_manager
targets from 16 to 64env_blowercannon
crashing if target does not exist, simplified spore creationlogic_random
: triggers a randomly selected target out of up to 16 targetshud.json
entry for name mapping to enable an Opposing Force-specific version to be usedOverflow 2048 temporary ents!
message to only print once per frame (excessive logging caused framerate drops to < 30 FPS)ED_Alloc: out of edicts
errors, crashes, entity rendering issues (see below)c3a2b
(Lambda Core map 3) valves soft) locking if turned too quickly in succession. The second valve now locks until it is safe to use itc3a2
(killing retinal scanner scientist in Lambda Core map 1)c4a2
(Gonarch's Lair map 1) not playing ("Win, you cannot win")HalfLife.UnifiedSdk
prefix (the Map Decompiler executables have also been renamed)c2a5
(Surface Tension map 1) barrel not flying up if destroyed using radius damage attackEntity
class to store keyvalues as lists instead of dictionaries (matches map compile tools behavior)multi_manager
keyvalues (affects retinal scanner scripts that had too many keys)Too many changes at once in directory
errorszoo_npcs
to improve map performance, stability and behaviorContents
choices to func_train
(allows trains to be made out of water, slime or lava)target_source
keyvalue typemaster
keyvalue to game_zone_player
ReplacementFiles
base class to entities that use sounds or sentenceslogic_random
hud.json
entries used by entities whose names have changedhud.json
entries for the Blue Shift helmet & armor vest pickup itemshud.json
entries for unused train icons, added train_controls
& pain_directions
entries to allow the HUD to locate the right files at runtimeChange Game
button when launching the game directly (as opposed to launching through Steam)OpenAL
library name in the package manifest so the right file is packagedOverflow 2048 temporary ents!
has also been addressed.
cl_gibcount
, cl_giblife
and cl_gibvelscale
control how many are spawned, how long they exist once they stop moving and how much their velocity is affected (the settings in the video are 100
, 1
and -10000
respectively).gibshooter
entity still uses server-side gibs but this can be changed if necessary.
zoo_npcs
test map has been added and includes functionality to test most of the non-scripted NPCs as well as weapons, items, ammo and other new features.
As you can see there is still work needed for the classification changes to work properly. Additional features are needed to help reduce the number of entities created since it exceeds the server-side maximum visible entities limit at times (255).trigger_push
(fuel to force entities to move and touch trigger_hurt)
to all entities in the arena. Since the turrets aren't meant to move they aren't set up to handle this properly.trigger_changekeyvalue
: used to configure NPCs after spawning to set the classification
and is_player_ally
keyvaluespoint_teleport
: Used to teleport the player at the push of a buttonammo_all
: Resupply point outside Displacement field labenv_warpball
: Teleport target for Displacement field lab teleporters, creates teleport effecttrigger_teleport
: fire_on_teleport
triggers warpball entity on teleportfunc_button
in a room under the map is used for this, since trigger_relay
doesn't preserve the activator)monstermaker
: Pass initial path_corner
target name to Apache and Osprey NPCsfunc_tank
: target laserspak0.pak
file). The demo works fine aside from a couple scripted events that glitch out, but that also seems to happen in the original so i don't consider those to be worth fixing.monster_rosenberg
model to correct default (was still using scientist.mdl
)is_player_ally
keyvaluemonstermaker
target after NPC spawning is done instead of after NPC creation and before spawningUTIL_FindEntityBy*
functions to avoid calling engine function (see below)point_teleport
initial_capacity
keyvalue to Osprey NPCs to allow specifying how many grunts/assassins to deploy instead of relying on existing NPCs in the map to influence calculations (max 24)func_tank
entitiesfunc_tank
entities not returning player weapon control when killtargetedenv_fog
point_teleport
and env_fog
entities to fgdclass_signs.wad
(contains textures stating NPC names)zoo_npcs
mapc4a3
(Nihilanth boss battle death script) using wrong render modeof1a1
(Opposing Force "Welcome To Black Mesa" map)model
keyvalue for monster_rosenberg
(defaults to correct model in code now)valve_uplink
directoryhuman_passive
classification (Black Mesa scientists) fears human_military
(Human Grunts) and will run away from them. human_military
dislikes human_passive
and will attack them.{
// Class none is always added and should only have relationship "none" (default) to all classes.
"none": {},
"machine": {
"Relationships": {
"player": "dislike",
"human_passive": "dislike",
"human_military": "none",
"alien_military": "dislike",
"alien_passive": "dislike",
"alien_monster": "dislike",
"alien_prey": "dislike",
"alien_predator": "dislike",
"player_ally": "dislike",
"player_bioweapon": "dislike",
"alien_bioweapon": "dislike",
"human_military_ally": "dislike",
"race_x": "dislike"
}
},
"player": {
"Relationships": {
"machine": "dislike",
"human_military": "dislike",
"alien_military": "dislike",
"alien_passive": "dislike",
"alien_monster": "dislike",
"alien_prey": "dislike",
"alien_predator": "dislike",
"player_bioweapon": "dislike",
"alien_bioweapon": "dislike",
"race_x": "dislike"
}
},
"human_passive": {
"Relationships": {
"player": "ally",
"human_passive": "ally",
"human_military": "hate",
"alien_military": "hate",
"alien_monster": "hate",
"alien_prey": "dislike",
"alien_predator": "dislike",
"player_ally": "ally",
"human_military_ally": "dislike",
"race_x": "hate"
}
},
// More classifications here
}
As usual it can be overridden on a per-map basis, though it only supports a single file per map.alien_flora
classification for Xen trees and large spores (replaces CLASS_BARNACLE
which wasn't used by barnacles and was never used because it would cause the class table to be accessed out of bounds)IsMachine
method to determine whether an entity is a machine of some kind (e.g. Osprey, turrets)IsBioWeapon
method to determine whether an entity is a bioweapon of some kind (e.g. Snarks, Penguins, Hornets)RadiusDamage
and FlameDamage
methods to take ignore class as last parameter to allow it to be defaulted to "none"CanRecruit
function to determine whether a candidate entity can be recruited into the current squad monster's squadclassification
: If defined, changes the NPC's classification to the specified class (must be one named in the map's classification config file). The new entity templates feature can be used to apply this to every instance of a specific type of NPC in a map. The new target selector feature (see below) can be used to change the player's classification.is_player_ally
: Has three possible values: Default, No and Yes. Default uses the relationship from the NPC's class to the player's class defined in the map's classification config file. No equals dislike
(will attack), Yes equals ally
."target" "class_sprite_*"
"killtarget" "!activator"
trigger_relay
which passes itself instead.!activator
: The entity that started the current trigger execution!caller
: The last entity in the trigger execution chaintrigger_teleport
now has a fire_on_teleport
target fired whenever it teleports an entity. Useful for triggering effects and whatnot.point_teleport
entity can be used to teleport a targeted entity to the point_teleport
entity's position. To teleport the entity that activated it (like a player pressing a button that triggers the teleport entity) the !activator
target selector can be used.fire_on_teleport
keyvalue.
enable_target_laser
keyvalue and can use a designer-configured sprite, width and color.
env_fog
entity has been implemented here as well. This entity allows the addition of fog with configurable density, start and stop distances, color and the option to also affect the skybox.And did you learn about modern delegate unmanagable pointers and you would like to port whole Half-Life into C# if Valve Software would like to be happy if many coders write in C# and develop own game better then Xash.No, i stopped working on SharpLife because that project is way too big to be completed in a reasonable amount of time and recreating game behavior is too difficult to do with available resources.
OnCreate
and OnDestroy
function callsweapon_rpg
and ammo_rpgclip
to use entity templates for multiplayer-only ammo doublingCBasePlayer
to use ToBasePlayer
(extra safety checks and runtime type validation in debug builds)CBasePlayer*
(avoids passing non-player entities to these functions and simplifies function calls)entvars_t::enemy
if it can be avoided (the engine uses this variable in NPC movement code but it doesn't seem to actually be used, needs more investigation)UTIL_FindEntityByTargetname
when searching by targetname instead of UTIL_FindEntityByString
trigger_teleport
when target is an empty string (prevents teleportation to seemingly random locations)CListBox
class setting scrollbar range to incorrect maximum (off by one issue, last line was always empty as a result)MyCTFItemPointer()
function now)weapon_rpg
and ammo_rpgclip
ammo amounts to 2 for multiplayer (was previously hard-coded)GameMenu.res
and gameui_english.txt
New Game
menu button, added new Start Campaign...
menu button that opens the campaign selection menucfg/entitytemplates/op4/weapon_9mmar.json
:
{
"default_ammo": "50" // Full magazine
}
cfg/OpposingForceConfig.json
:
// Rest of file omitted
{
"SectionGroups": [
{
"Sections": {
"EntityTemplates": {
"weapon_9mmar": "cfg/entitytemplates/op4/weapon_9mmar.json"
}
}
}
]
}
The map config specifies which template to use; the template itself is a collection of keyvalues to apply.OnCreate
has finished) but before level designer-set keyvalues are applied. All entities with the specified classname are affected, even if created by a monstermaker or when transitioned from another map.// Rest of file omitted
{
"SectionGroups": [
{
"Sections": {
"HudReplacement": {
"HudReplacementFile": "sprites/op4/hud.json",
"Weapons": {
"weapon_9mmar": "sprites/op4/weapon_9mmar.json"
}
}
}
}
]
}
This overrides the default files used (sprites/hud.json
and sprites/weapon_9mmar.json
respectively) and causes the client to use the sprites specified therein instead.campaigns
directory for JSON files.{
"Label": "Half-Life",
"Description": "The Half-Life campaign.\n\nRelease date: 1998.",
"CampaignMap": "c0a0",
"TrainingMap": "t0a0"
}
Either the campaign or training map name can be omitted, in which case the option is disabled. If both are omitted or the file doesn't contain the expected data the file is ignored.<moddir>/campaigns
, <moddir_addon>/campaigns
, <moddir_downloads>/campaigns
or other directories usually checked by the filesystem.DefaultGameData.json
(now defined in game code)mapcycle.txt
and default mapcycle.json
cfg/DefaultMapConfig.json
instead.
{
"Includes": [
"cfg/OpposingForceConfig.json"
],
"GameMode": "ctf",
"LockGameMode": true
}
The server can choose a game mode using the mp_gamemode
cvar which contains the name of the game mode to use (deathmatch, teamplay, ctf, coop).mp_createserver_gamemode
. That cvar overrides the value of mp_gamemode
so the method used is slightly different when starting a server that way.// Example/Default mapcycle for Deathmatch Maps
// Copy to mapcycle.txt to use :)
//
op4_bootcamp "\minplayers\0\maxplayers\32\mp_weaponstay\1\"
op4_datacore "\minplayers\0\maxplayers\32\mp_weaponstay\1\"
op4_demise "\minplayers\0\maxplayers\32\mp_weaponstay\1\"
op4_disposal "\minplayers\0\maxplayers\32\mp_weaponstay\1\"
(from WON Opposing Force)[
"undertow",
{
"Name": "snark_pit",
"MinPlayers": 0,
"MaxPlayers": 32
},
"boot_camp",
"lambda_bunker",
"datacore",
"stalkyard"
]
It works the same way but it's a lot easier to understand.trigger_changelevel
. You wouldn't include all maps in the map cycle file so you'd have to keep track of the last map that was in the file so you can skip to the next one.map
command, so when playing through a campaign you'll only get it in the first map, never in subsequent maps.cfg/BaseGameConfig.json
has been added that defines the defaults:
{
"SectionGroups": [
{
"Condition": "Multiplayer",
"Sections": {
"SpawnInventory": {
"HasSuit": true,
"Weapons": {
"weapon_crowbar": {},
"weapon_9mmhandgun": {}
},
"Ammo": {
"9mm": 68
},
"WeaponToSelect": "weapon_9mmhandgun"
}
}
},
{
// Override default multiplayer inventory for CTF.
"Condition": "Multiplayer && GameMode == \"ctf\"",
"Sections": {
"SpawnInventory": {
"Reset": true,
"HasSuit": true,
"Weapons": {
"weapon_pipewrench": {},
"weapon_eagle": {},
"weapon_grapple": {}
},
"Ammo": {
"357": 21
},
"WeaponToSelect": "weapon_grapple"
}
}
}
]
}
You can control whether the player is given the following:
"Weapons": {
"weapon_crowbar": {},
"weapon_9mmhandgun": {
"DefaultAmmo": 34 // Two magazines by default
}
}
So you can give players empty weapons, make them injured by default, or give them a full loadout.coop_persistent_inventory_grace_period
controls how long this persistent inventory is given when respawning. A trigger_changelevel
keyvalue controls whether the inventory is persisted or not.game_text
messages not resetting time value correctly causing messages that reuse channels to use the wrong start timescripted_sentence
) still setting an origin and having directional audio (a previous change intended to fix this bug as it occurred in the original engine, this accounts for an edge case that was missed)func_breakable
and func_pushable
to require level designers to specify the classname of the entity to spawn on break. This allows both entities to spawn any item in the game aside from CTF items without needing code changes to support newly added itemsEntityHandle
to make it easier to see which entity a handle points toedict_t*
, entvars_t*
and CBaseEntity*
to make code more consistent (ongoing effort)UTIL_GetLocalPlayer
to work in multiplayer (ongoing effort)player_hasweapon
logic_isskill
: fires a target matching the current skill levellogic_setskill
: Changes the skill level setting. Due to how the skill system works some changes will only take effect after a map change. This entity is the equivalent of Quake 1's trigger_setskill
but is a point entity that needs to be triggered. Its intended purpose is to be used in a campaign selection maplogic_setskillvar
: Sets a specific skill variable to a value. Intended for multiplayer only because skill variables are not saved and restored, and are reset on map load based on specified skill config filesmp_coopweprespawn 1
cycler_weapon
(not very useful, tends to cause problems when weapons code is changed)impulse 101
give all weapons using the weapons dictionary, give the suit without playing the login sound and give max ammo without creating ammo entitiesEcho
and Command
sections, moved default config file names to hardcoded list (see below)Echo
config section log as info instead of debug/tracegame_playeractivate
target being triggered multiple times in some game modescl_debuginfo_show 1
cl_debuginfo_show 1
sv_oldgrapple
cvar (leftover from an old Opposing Force update)trigger_relay
ent_create
and npc_create
now only inherit the yaw angle from the player that is executing the commandallow_use_while_busy
: Allows players to +USE entities while their character is busy with a weapon (e.g. reloading)allow_flashlight
: Whether to allow the flashlight (replaces mp_flashlight
cvar)allow_monsters
: Whether to allow monsters to spawn (replaces mp_allowmonsters
cvar)falldamagemode
: Controls the fall damage mode (0: fixed at 10 damage, 1: progressive: longer falls deal more damage) (replaces mp_falldamage
cvar)healthcharger_recharge_time
and hevcharger_recharge_time
: Controls how long it takes to recharge both charger types (-1 == never recharge) (Replace hard-coded values)weapon_respawn_time
, ammo_respawn_time
and pickupitem_respawn_time
: Controls how long it takes to respawn the three item types (-1 == never respawn) (Replaces hard-coded values)weapon_instant_respawn
: If set to 1, weapons not flagged to be limited in world (i.e. hand grenades, satchels, etc) will respawn immediately (Replaces mp_weaponstay
cvar)allow_weapon_dropping
: Controls whether players can drop weapons. Does not affect singleplayer (Also replaces mp_weaponstay
cvar)infinite_ammo
: All players have infinite ammo. The game acts as though players have maximum reserve ammobottomless_magazines
: Player reserve ammo is used before the weapon's magazine is used. When used in combination with infinite_ammo
the player can fire forevercoop_persistent_inventory_grace_period
: Amount of time in seconds after joining the server that players are able to spawn with their persisted inventorycrowbar_full_damage
and pipewrench_full_damage
: Whether the crowbar/pipe wrench should deal full damage on each swing. In singleplayer only the first swing deals full damagerevolver_laser_sight
: Whether to enable the revolver's laser sight (zoom)smg_wide_spread
: Whether to use a wider spreadshotgun_single_tight_spread
: Whether to tighten the single shot spreadshotgun_double_wide_spread
: Whether to widen the double shot spreadcrossbow_sniper_bolt
: Whether zoomed in shots use sniper bolts (hitscan instead of physical projectile)crossbow_explosive_bolt
: Whether bolts explode if they don't hit an object that can be damaged (sniper bolts will never explode)gauss_charge_time
: Controls the Gauss gun's charge time. Clamped to the range [0.1, 10]. The Gauss gun overcharges at 10 secondsgauss_fast_ammo_use
: Whether to consume ammo quicklygauss_vertical_force
: Whether to apply vertical knockback when using secondary attack (Gauss jumping)gauss_damage_radius
: Damage radius multiplayer for secondary attack pierced shots. Due to how radius damage is applied this does not turn such attacks into nuclear blasts when the radius is increasedegon_narrow_ammo_per_second
: Ammo usage per second for narrow mode (minimum 0) (note: narrow mode is never used)egon_wide_ammo_per_second
: Ammo usage per second for wide mode (minimum 0)knife_allow_backstab
: Whether to treat attacks from behind as a backstab (backstabs deal 100 times normal damage but will never gib its target)grapple_fast
: Whether to allow the Barnacle grapple to launch again quicklym249_wide_spread
: Whether to use wide spread for M249 shotsshockrifle_fast
: Whether to allow the Shock Rifle to fire and regenerate ammo fasterba_outro
player freeze breaking if the game is saved and loaded while frozengame_player_equip
as wellgame_player_equip
to not give default spawn inventoryba_tram1
to give players the HEV suit instead of relying on buggy game behavior to make players pick it upcl_debuginfo_show
cvar.
ammo_generic
: Can change the ammo type given using trigger_changekeyvalue
ammo_all
: Give specified amount of all ammo types#
:
#TriggerCondition 4
#TriggerTarget death
Killtargeting entities now also correctly cleans up entities spawned by them (if the entity is intended to be killtargeted, not all entities do this). This fixes monstermaker breaking if the spawned entities are killtargeted and certain NPCs and entities leaving effects behind.
cycler_weapon
trying to reloadV_min
and V_max
with std::min
, std::max
& std::clamp
SV_SaveGameComment
function: used by the engine to fill in the text shown in the save game description in the Load Game dialog (game uses localized text for this)sv_spamdelay
is now ignored in singleplayer (it controls the time before players are allowed to chat again, to limit the amount of chat text allowed at any given time)multi_manager
targetsTakeHealth
to GiveHealth
because positive amounts give healthCBaseEntity
wherever possible to make it more consistent and eliminate some older helper functionalitymonstermaker
with infinite children not spawning an infinite number (will spawn 4,294,967,293 entities and then stops. Ridiculous, i know)monstermaker
children (see below)cycler_wreckage
storing time value in int instead of floatHOOK_COMMAND
with console command systemtrigger_changelevel
work in multiplayer (non-persistent level changes only)monster_vortigaunt
classname (never used, breaks Alien Slave code since it searches by classname)game.cfg
execution, added safety checks to prevent server state corruption if multiple map change commands occur in the same framefunc_tank
CBaseEntity
to their respective classesWEAPON_CHAINGUN
constant (effectively frees up 2 weapon slots for use)weapon_9mmAR
, ammo_9mmAR
, ammo_ARgrenades
)sv_schedule_debug
cvardesert
to ensure sky name is consistent even after loading other maps that have other sky names (e.g. crossfire
does not specify a sky name and uses the last used sky)EHANDLE
to use new handle featuresfunc_train
and env_spritetrain
to use EHANDLE
instead of entvars_t*
to track the next stop targetEHANDLE
instead of edict_t*
to store tripmine ownergive
and impulse 101
commands now use the item dictionaryfunc_healthcharger
and func_recharge
(HEV charger) to use shared base classplayer_weaponstrip
item_generic
to avoid the possibility of the wrong sequence being used if the game saves right between the entity spawning and finishing its initializationitem_helmet
& item_armorvest
world_items
(obsolete, replaced by individual entities)item_security
and unused item types not used by game codetrip_beam
(debug only, never used)player_sethealth
player_setsuitlighttype
player_hassuit
logic_setcvar
ammo_generic
: Gives ammo of a specified ammo type (combine with trigger_changekeyvalue
to dynamically change ammo type)ammo_all
: Gives all ammo types. Configurable amountent_remove
: Remove the first entity matching the given targetname or classnameent_remove_all
: Remove all entities matching the given targetname or classnameent_setname
: Sets the name of the entity you're looking at or the entity with the given targetname or classname to the given targetnameent_show_origin
: Shows the origin of the first entity matching the given targetname or classname by creating a temporary laser dot sprite at its location (note: brush entity origins may be 0 0 0
if they do not have an origin brush)ent_show_center
: Shows the center as defined by the first entity matching the given targetname or classname by creating a temporary laser dot sprite at its locationent_show_bbox
: Shows the bounding box of the first entity matching the given targetname or classname by drawing blue particle lines (note: the game expands the bounding box by 1 unit in all directions, so the box appears to be larger than the entity)cheat_god
: Toggles god mode (even in multiplayer)cheat_notarget
: Toggles notarget (even in multiplayer)cheat_noclip
: Toggles noclip (even in multiplayer)cheat_givemagazine
: Gives a single magazine's worth of ammo for the current weapon to the player. An optional parameter indicates the weapon's attack mode index to allow giving secondary ammo (i.e. MP5 grenades are given with cheat_givemagazine 1
)ent_create
: Creates an entity at the position you're looking at, passing along additional keyvalues if providednpc_create
: Creates an entity at the position you're looking for and adjusts its height to place its bounding box on the ground. If the entity is stuck in an object or can't fall to the ground it is removedcheat_
prefix are autocompleted by the console nowm_hActivator
to CBaseEntity
and removed a hack added post-releasemaster
keyvalue definition and made it use the correct data type so editors can auto-complete entity names.wav
extension from a couple Op4 sentenceszoo_items
map to enable easy testing of all itemsmonstermaker
func_train
& env_spritetrain
to use new sound name functionalitydmdelay
keyvalue from charger entities (was always ignored, removed to avoid confusion)trigger_changekeyvalue
, though i wouldn't recommend it because the models and sounds need to be precached to work.
game_shared.cmake
) it'll set it up.materials.txt
, sentences.txt
and skill.json
are now specified through the server config file instead of using hard-coded filenames. Note that this may be changed to solve problems related to servers running custom versions of these files since it messes up custom content when downloaded and loaded locallysk_reload
command (restart the map to see changes)weapons.h
since they should not be accessed directlyWEAPON_*
constants are contained in their individual weapons nowCMakeLists.txt
instead of Platform.h
to ensure they are disabled project-widecl_showprojectinfo
to cl_projectinfo_show
ambient_generic
Play Everywhere
sounds still using spatialization; needs more testing)iItemSlot()
method, removed duplicate constants for max weapon slots and ammo typesmathlib.h/.cpp
EOFFSET
type, updated remaining uses to make use of better alternativesFClassnameIs
with class member functiongamerules.h
so singleplayer & multiplayer gamerules class declarations aren't included (should never be accessed directly)weapon_mp5
=> weapon_9mmAR
)materials.txt
to JSONStart On
spawnflag to func_guntarget
"Sentences": {
"ResetList": false,
"FileNames": ["sound/sentences.txt"]
}
If ResetList
is true then any files specified by config files loaded before this one are ignored.trigger_push
to add velocity in a way that was framerate-dependent. Instead of applying the set velocity in one go it applied it over the course of about a second. The higher the framerate is the lower the applied velocity becomes.{
"number_0": "number_0_hl",
"number_1": "number_1_hl",
"number_2": "number_2_hl",
"number_3": "number_3_hl",
"number_4": "number_4_hl",
"number_5": "number_5_hl",
"number_6": "number_6_hl",
"number_7": "number_7_hl",
"number_8": "number_8_hl",
"number_9": "number_9_hl"
}
The default sprite is substituted for its replacement. In this case the default hud uses Opposing Force sprites so it was substituted with the Half-Life versions.trigger_changekeyvalue
has been implemented.trigger_sequence
's features will be implemented in another manner. This largely involves map-specific sentences.txt
files, the other features are more of a nice-to-have thing and are not as important.
materials.txt
and sentences.txt
are now sent to clients by copying the contents into a JSON file and making the client download and read the file.1
:
networkdata/data.json
. Using the same name simplifies things and takes advantage of the engine's automatic change detection to regenerate the BZip2 compressed version networkdata/data.json.ztmp
which helps to avoid polluting dedicated servers with many old compressed versions. The average compression ratio is about 79% meaning a file with size 100KiB is compressed to a file that's about 21KiB.1.2.3.4_port
. This would make the filename unique for each server. The client has the server's IP address so this should work, but whether this will actually work or not remains to be seen.sv_filetransfermaxsize
cvar. File size shouldn't be a problem but if it does the first thing to do is investigate replacing JSON with a message format like Protobuf.cl_dlmax
cvar.materials.txt
and sentences.txt
changesmaterials.txt
parser now properly handles comments. Previously a line starting with /
was treated as a comment instead of any occurence of //
as expected.materials.txt
and sentences.txt
are now sent to the client. This ensures that the client works with the same data as the client.{
"Sections": [
{
"Name": "GlobalModelReplacement",
"FileName": "cfg/Op4ModelReplacement.json"
},
{
"Name": "GlobalSentenceReplacement",
"FileName": "cfg/Op4SentenceReplacement.json"
},
{
"Name": "GlobalSoundReplacement",
"FileName": "cfg/Op4SoundReplacement.json"
},
{
"Name": "HudColor",
"Color": "0 160 0"
},
{
"Name": "SuitLightType",
"Type": "nightvision"
}
]
}
This has been changed to this:
{
"SectionGroups": [
{
"Sections": {
"GlobalModelReplacement": {
"FileName": "cfg/Op4ModelReplacement.json"
},
"GlobalSentenceReplacement": {
"FileName": "cfg/Op4SentenceReplacement.json"
},
"GlobalSoundReplacement": {
"FileName": "cfg/Op4SoundReplacement.json"
},
"HudColor": "0 160 0",
"SuitLightType": "nightvision"
}
}
]
}
There is now a list of section groups. A section group pairs a set of sections with an optional Condition
key, which previously was available on every section. The section list has been replaced with an object; section names are the key. Section values can now be any JSON object type: object, array, string, etc. This simplifies the trivial sections quite a bit.liblist.gam
, log actual max edicts on map start (max edicts is calculated as max_edicts + ((maxplayers - 1) * 15)
)UTIL_SetSize
with a CBaseEntity::SetSize
member function and overriding the entity's bounds during SetModel
and SetSize
calls. This setting should be used only with entities that use Studio models (files with .mdl
extension).monster_generic
, now relies on mapper-defined hull sizes for these.WRITE_FLOAT
.materials.txt
parsing to make it easier to change the data source, simplified material storage, fixed parser bugs involving comment handling and correctly parsing the last material entry.RecCl*
function calls. These were part of an old anti-cheat system once used by official Valve games but no longer does anything now other than add visual noise to code.sentences.txt
on client (see below).materials.txt
on client (see below).trigger_changekeyvalue
.v_shock.mdl
requires this to fix a visual glitch experienced by some players where polygons meant to be invisible were being rendered due to an OpenGL glitch.qfont.h
back but only for utils use, use header instead of redefining qfont_t
type.nonfunctional-prototype-networking
containing the prototype GameNetworkingSockets-based networking system. As the branch name implies this does not work, it has been added to show people how far its development got and which portions were finished and how. There is some useful information to be gained from it, but there are no plans to continue its development since an alternative has been implemented.c2a5
barrels not flying as high as they are supposed to (see below).monster_generic
models that use a hard-coded hull.ba_power1
.string_view
which made parsing stricter.of2a2
.ba_security2
to use hologram pushcart model.trigger_changekeyvalue
to fgd.v_shock
.// In the global scope somewhere
DECLARE_MESSAGE(m_Health, Health)
// In hud element Init function
HOOK_MESSAGE(Health);
To:
g_ClientUserMessages.RegisterHandler("Health", &CHudHealth::MsgFunc_Health, this);
It's probably easier to show how this change affected the codebase: https://github.com/SamVanheer/halflife-unified-sdk/commit/f32cdda028bef544685c16eecf38a861ba329f42std::vector
and unnecessary null checks have been removed. Enumeration of hud elements is now much simpler:
for (auto hudElement : m_HudList)
{
hudElement->VidInit();
}
Additionally the VidInit
call is now done using the list instead of manually calling each element as is done in the original SDK.std::vector
. Previously all three variables representing hud sprites were in separate dynamically allocated arrays:
// the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded.
// freed in ~CHud()
HSPRITE* m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt
Rect* m_rgrcRects; /*[HUD_SPRITE_COUNT]*/
char* m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/
These three variables as well as the actual sprite model name are now stored in a structure:
struct HudSprite
{
eastl::fixed_string<char, MAX_SPRITE_NAME_LENGTH> Name;
eastl::fixed_string<char, 64> SpriteName;
HSPRITE Handle = 0;
Rect Rectangle{0, 0, 0, 0};
};
The sprite list loaded by the engine (m_pSpriteList
) is now freed once all sprites have been loaded into the hud sprite list. This fixes a memory leak on Linux that occurs when the engine does a soft restart (due to video setting changes or changes to filesystem configuration like toggling HD models).--apply-null
option to command line0 0 0
AAATRIGGER
to brushes lacking any textures (referred to as "trigger entity classname wildcards"){
"SoundList": [
"filename1.wav",
"filename2.wav"
]
}
The resulting JSON formatted in minified form (no whitespace, newlines or comments) is compressed using Bzip2 to about 1/5th the original size.test_effect
entity (not used and only partially implemented, did not function)CBasePlayer*
from UTIL_PlayerByIndex
CBaseEntity
that are only implemented for players and called by code that knows it's CBasePlayer
ToBasePlayer
function to convert a (possibly null) entity pointer to a player pointer, with debug check to verify that it is actually a player to catch incorrect results returned by CBaseEntity::IsPlayer
CBaseEntity
find functions instead of edict_t
versionsclient.so
func_water
and func_train
soundscbase.h
to be split up to ensure correct header include order.CREATE_NAMED_ENTITY
engine function has been rendered obsolete by this change, the game now looks up entities by name locally using this dictionary. string_t
no longer implicitly converts to string_t_value
because it was only needed to support CREATE_NAMED_ENTITY
.GetClassPtr
no longer exists. Creating entities programmatically with specific types is now done in this manner:
CBeam* pBeam = g_EntityDictionary->Create<CBeam>("beam");
If the type doesn't match what you've requested (e.g. g_EntityDictionary->Create<CBasePlayerWeapon>("beam")
) then the game will assert in debug builds to warn you.g_WeaponDictionary
CBasePlayerWeapon
and is currently used by the weapon precache code. In the future this dictionary will be used for more things when HLEnhanced's updated weapon prediction code and the Better Weapons SDK are merged in. It renders the Better Weapons macro used for weapon registration obsolete.template <typename TEntity>
void RegisterEntityDescriptor(EntityDescriptor<TEntity>* descriptor)
{
assert(descriptor);
// This is where each dictionary is initially constructed and built to add all entity classes.
// Ideally some form of reflection would be used to build these dictionaries after the initial dictionary has been created,
// but since we don't have reflection available and existing libraries require loads of refactoring this will have to do for now.
detail::RegisterEntityDescriptorToDictionaries(descriptor,
EntityDictionaryLocator<CBaseEntity>::Get(),
EntityDictionaryLocator<CBasePlayerWeapon>::Get());
}
Simply adding another specialization here creates the dictionary. The global variable used to access it is declared just above this function:
// Used at runtime to look up entities of specific types.
inline EntityDictionary<CBaseEntity>* g_EntityDictionary = EntityDictionaryLocator<CBaseEntity>::Get();
inline EntityDictionary<CBasePlayerWeapon>* g_WeaponDictionary = EntityDictionaryLocator<CBasePlayerWeapon>::Get();
The goal is to eventually merge in Enhanced Half-Life's item class refactoring work, at which point a CBaseItem
dictionary will be used to handle the giving of items to the player (e.g. using the give
console command) to improve the behavior of existing functionality.
CWorld::Instance
to CWorld::World
to avoid conflicting with CBaseEntity::Instance
function name-flifetime-dse=1
flag to Linux Makefile to disable compiler optimization that removed entity memory zero-initialization, resulting in the game crashing when any entity touches the worldbarney.cpp
to h_ai.cpp
to help prevent linker errors when copy pasting source fileimpulse 107
to get the name of a texture the texture type (as used in materials.txt
) will also be printedPM_FindTextureType
const correctWRITE_FLOAT
function corresponding to the client's READ_FLOAT
function2048 + (15 * (maxplayers - 1))
. It is possible to create more than 2048 entities as long as entities with an index exceeding this don't have any physical presence in the world (i.e. no model, non-solid, no movement) but since the entity index cannot be chosen when creating entities this is impractical. The game will crash in the server-side player physics code if solid entities are created, presumably because that system is hard-coded to a maximum of 900 solid/visible entities with no bounds checkingdelta.lst
to the archive again (was accidentally removed in the previous beta)