From 52f292c19774b0a24adbe5e5b94e601f5d2c601f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 15 Jun 2022 17:50:01 +0300 Subject: [PATCH 01/59] Simplify code. --- src/baseq2/p_view.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index cda77b048..03c76f645 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -308,18 +308,9 @@ void SV_CalcViewOffset(edict_t *ent) // absolutely bound offsets // so the view can never be outside the player box - if (v[0] < -14) - v[0] = -14; - else if (v[0] > 14) - v[0] = 14; - if (v[1] < -14) - v[1] = -14; - else if (v[1] > 14) - v[1] = 14; - if (v[2] < -22) - v[2] = -22; - else if (v[2] > 30) - v[2] = 30; + clamp(v[0], -14, 14); + clamp(v[1], -14, 14); + clamp(v[1], -22, 30); VectorCopy(v, ent->client->ps.viewoffset); } @@ -351,10 +342,7 @@ void SV_CalcGunOffset(edict_t *ent) delta -= 360; if (delta < -180) delta += 360; - if (delta > 45) - delta = 45; - if (delta < -45) - delta = -45; + clamp(delta, -45, 45); if (i == YAW) ent->client->ps.gunangles[ROLL] += 0.1f * delta; ent->client->ps.gunangles[i] += 0.2f * delta; From 091489590eff831401371ff344499e9d76d07014 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 16 Jun 2022 19:05:10 +0300 Subject: [PATCH 02/59] Fix invalid sizeof argument. --- src/baseq2/g_target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/baseq2/g_target.c b/src/baseq2/g_target.c index d7c4ecc4a..653c2cff0 100644 --- a/src/baseq2/g_target.c +++ b/src/baseq2/g_target.c @@ -114,9 +114,9 @@ void SP_target_speaker(edict_t *ent) void Use_Target_Help(edict_t *ent, edict_t *other, edict_t *activator) { if (ent->spawnflags & 1) - Q_strlcpy(game.helpmessage1, ent->message, sizeof(game.helpmessage2)); + Q_strlcpy(game.helpmessage1, ent->message, sizeof(game.helpmessage1)); else - Q_strlcpy(game.helpmessage2, ent->message, sizeof(game.helpmessage1)); + Q_strlcpy(game.helpmessage2, ent->message, sizeof(game.helpmessage2)); game.helpchanged++; } From 6a948a30221e8c880a8d9fa78d470be5df3ca754 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 16 Jun 2022 19:06:08 +0300 Subject: [PATCH 03/59] Rewrite how trigger_hurt/target_earthquake timestamps are computed. Rate of these effects should not depend on server framerate. Non-issue currently because variable FPS is not supported. --- src/baseq2/g_target.c | 4 ++-- src/baseq2/g_trigger.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/baseq2/g_target.c b/src/baseq2/g_target.c index 653c2cff0..b665a90ff 100644 --- a/src/baseq2/g_target.c +++ b/src/baseq2/g_target.c @@ -748,13 +748,13 @@ void target_earthquake_think(edict_t *self) } if (level.framenum < self->timestamp) - self->nextthink = level.framenum + 1; + self->nextthink = level.framenum + 0.1f * BASE_FRAMERATE; } void target_earthquake_use(edict_t *self, edict_t *other, edict_t *activator) { self->timestamp = level.framenum + self->count * BASE_FRAMERATE; - self->nextthink = level.framenum + 1; + self->nextthink = level.framenum + 0.1f * BASE_FRAMERATE; self->activator = activator; self->last_move_framenum = 0; } diff --git a/src/baseq2/g_trigger.c b/src/baseq2/g_trigger.c index 8615cca94..37a18ce84 100644 --- a/src/baseq2/g_trigger.c +++ b/src/baseq2/g_trigger.c @@ -444,7 +444,7 @@ void hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf if (self->spawnflags & 16) self->timestamp = level.framenum + 1 * BASE_FRAMERATE; else - self->timestamp = level.framenum + 1; + self->timestamp = level.framenum + 0.1f * BASE_FRAMERATE; if (!(self->spawnflags & 4)) { if ((level.framenum % 10) == 0) From 0ac1eeeb7f51ba432d85bfdfd04ddbaa127de76d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Jun 2022 22:35:55 +0300 Subject: [PATCH 04/59] Fix invalid pointer comparsion in SV_Push(). --- src/baseq2/g_phys.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/baseq2/g_phys.c b/src/baseq2/g_phys.c index 6b597d3a2..07403070a 100644 --- a/src/baseq2/g_phys.c +++ b/src/baseq2/g_phys.c @@ -519,7 +519,8 @@ bool SV_Push(edict_t *pusher, vec3_t move, vec3_t amove) // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position - for (p = pushed_p - 1 ; p >= pushed ; p--) { + for (i = (pushed_p - pushed) - 1; i >= 0; i--) { + p = &pushed[i]; VectorCopy(p->origin, p->ent->s.origin); VectorCopy(p->angles, p->ent->s.angles); #if USE_SMOOTH_DELTA_ANGLES @@ -534,8 +535,8 @@ bool SV_Push(edict_t *pusher, vec3_t move, vec3_t amove) //FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger - for (p = pushed_p - 1 ; p >= pushed ; p--) - G_TouchTriggers(p->ent); + for (i = (pushed_p - pushed) - 1; i >= 0; i--) + G_TouchTriggers(pushed[i].ent); return true; } From fdb67053c1d9d2a48af3fc782f1856d659ae35ff Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 14 Aug 2022 16:10:22 +0300 Subject: [PATCH 05/59] Enable savegames if YQ2 game lib is detected. --- src/baseq2/p_client.c | 4 ++-- src/baseq2/p_weapon.c | 6 +++--- src/server/game.c | 8 ++++++++ src/server/init.c | 3 +++ src/server/save.c | 22 ++++++++++++++++++++++ src/server/server.h | 5 +++++ 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 260396120..5d1f90e0e 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -584,7 +584,7 @@ void InitClientPersistant(gclient_t *client) client->pers.weapon = item; - if (sv_flaregun->integer > 0) + if (sv_flaregun->value > 0) { // Q2RTX: Spawn with a flare gun and some grenades to use with it. // Flare gun is new and not found anywhere in the game as a pickup item. @@ -593,7 +593,7 @@ void InitClientPersistant(gclient_t *client) { client->pers.inventory[ITEM_INDEX(item_flareg)] = 1; - if (sv_flaregun->integer == 2) + if (sv_flaregun->value == 2) { gitem_t* item_grenades = FindItem("Grenades"); client->pers.inventory[ITEM_INDEX(item_grenades)] = 5; diff --git a/src/baseq2/p_weapon.c b/src/baseq2/p_weapon.c index 414fa748c..c031dff9f 100644 --- a/src/baseq2/p_weapon.c +++ b/src/baseq2/p_weapon.c @@ -41,7 +41,7 @@ static void P_ProjectSource(edict_t* ent, vec3_t point, vec3_t distance, vec3_t // Aim fix from Yamagi Quake 2. // Now the projectile hits exactly where the scope is pointing. - if (aimfix->integer) + if (aimfix->value) { vec3_t start, end; VectorSet(start, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + (float)ent->viewheight); @@ -1154,7 +1154,7 @@ void weapon_supershotgun_fire(edict_t *ent) v[ROLL] = ent->client->v_angle[ROLL]; AngleVectors(v, forward, NULL, NULL); - if (aimfix->integer) + if (aimfix->value) { AngleVectors(v, forward, right, NULL); @@ -1169,7 +1169,7 @@ void weapon_supershotgun_fire(edict_t *ent) v[YAW] = ent->client->v_angle[YAW] + 5; AngleVectors(v, forward, NULL, NULL); - if (aimfix->integer) + if (aimfix->value) { AngleVectors(v, forward, right, NULL); diff --git a/src/server/game.c b/src/server/game.c index 9b1ff1786..4cf1c1408 100644 --- a/src/server/game.c +++ b/src/server/game.c @@ -192,6 +192,14 @@ static void PF_dprintf(const char *fmt, ...) char msg[MAXPRINTMSG]; va_list argptr; +#if USE_CLIENT + // detect YQ2 game lib by unique first two messages + if (!sv.gamedetecthack) + sv.gamedetecthack = 1 + !strcmp(fmt, "Game is starting up.\n"); + else if (sv.gamedetecthack == 2) + sv.gamedetecthack = 3 + !strcmp(fmt, "Game is %s built on %s.\n"); +#endif + va_start(argptr, fmt); Q_vsnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); diff --git a/src/server/init.c b/src/server/init.c index e4fe95859..db33fdca5 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -485,7 +485,10 @@ void SV_InitGame(unsigned mvd_spawn) ge->Init(); } else #endif + { SV_InitGameProgs(); + SV_CheckForEnhancedSavegames(); + } // send heartbeat very soon svs.last_heartbeat = -(HEARTBEAT_SECONDS - 5) * 1000; diff --git a/src/server/save.c b/src/server/save.c index 9a12f038f..9f31d2d29 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -556,6 +556,28 @@ void SV_CheckForSavegame(mapcmd_t *cmd) } } +void SV_CheckForEnhancedSavegames(void) +{ + if (dedicated->integer) + return; + + if (Cvar_VariableInteger("deathmatch")) + return; + + if (g_features->integer & GMF_ENHANCED_SAVEGAMES) { + Com_Printf("Game supports Q2PRO enhanced savegames.\n"); + return; + } + + if (sv.gamedetecthack == 4) { + Com_Printf("Game supports YQ2 enhanced savegames.\n"); + Cvar_SetInteger(g_features, g_features->integer | GMF_ENHANCED_SAVEGAMES, FROM_CODE); + return; + } + + Com_WPrintf("Game does not support enhanced savegames. Savegames will not work.\n"); +} + static void SV_Savegame_c(genctx_t *ctx, int argnum) { if (argnum == 1) { diff --git a/src/server/server.h b/src/server/server.h index d7db606ac..1553c0de2 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -146,6 +146,10 @@ typedef struct { server_state_t state; // precache commands are only valid during load int spawncount; // random number generated each server spawn +#if USE_CLIENT || USE_SERVER + int gamedetecthack; +#endif + #if USE_FPS int framerate; int frametime; @@ -766,6 +770,7 @@ void PF_Pmove(pmove_t *pm); void SV_AutoSaveBegin(mapcmd_t *cmd); void SV_AutoSaveEnd(void); void SV_CheckForSavegame(mapcmd_t *cmd); +void SV_CheckForEnhancedSavegames(void); void SV_RegisterSavegames(void); int SV_NoSaveGames(void); From 34808074bbd130c5c935077d55850dfa275d45cc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 14 Aug 2022 16:17:38 +0300 Subject: [PATCH 06/59] =?UTF-8?q?Use=20=E2=80=98menu=5Floadgame=E2=80=99?= =?UTF-8?q?=20inside=20baseq2=20game=20library.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that it can be used with any engine, not just Q2PRO. --- src/baseq2/p_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 5d1f90e0e..568cebc60 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -976,7 +976,7 @@ void respawn(edict_t *self) } // restart the entire server - gi.AddCommandString("pushmenu loadgame\n"); + gi.AddCommandString("menu_loadgame\n"); } /* From 24e2e58eb4e08aff1ee055c9b0f33fff4dc63e3b Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 2 Sep 2022 16:04:30 +0300 Subject: [PATCH 07/59] Fix a typo. --- src/baseq2/p_view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index 03c76f645..0bea526ff 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -310,7 +310,7 @@ void SV_CalcViewOffset(edict_t *ent) clamp(v[0], -14, 14); clamp(v[1], -14, 14); - clamp(v[1], -22, 30); + clamp(v[2], -22, 30); VectorCopy(v, ent->client->ps.viewoffset); } From a050f333776afc0dd1cb4769e49c66b17fdb375f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 18 Sep 2022 21:15:30 +0300 Subject: [PATCH 08/59] Add some game fixes from YQ2. --- src/baseq2/m_boss31.c | 4 ++-- src/baseq2/m_soldier.c | 6 +++--- src/baseq2/p_hud.c | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/baseq2/m_boss31.c b/src/baseq2/m_boss31.c index 678b6fc83..71f23478b 100644 --- a/src/baseq2/m_boss31.c +++ b/src/baseq2/m_boss31.c @@ -672,8 +672,8 @@ void SP_monster_jorg(edict_t *self) self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; - self->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2"); - self->s.modelindex2 = gi.modelindex("models/monsters/boss3/jorg/tris.md2"); + self->s.modelindex = gi.modelindex("models/monsters/boss3/jorg/tris.md2"); + self->s.modelindex2 = gi.modelindex("models/monsters/boss3/rider/tris.md2"); VectorSet(self->mins, -80, -80, 0); VectorSet(self->maxs, 80, 80, 140); diff --git a/src/baseq2/m_soldier.c b/src/baseq2/m_soldier.c index ace2d0520..3879c8a02 100644 --- a/src/baseq2/m_soldier.c +++ b/src/baseq2/m_soldier.c @@ -1202,7 +1202,7 @@ void SP_monster_soldier_light(edict_t *self) gi.soundindex("soldier/solatck2.wav"); self->s.skinnum = 0; - self->health = 20; + self->max_health = self->health = 20; self->gib_health = -30; } @@ -1222,7 +1222,7 @@ void SP_monster_soldier(edict_t *self) gi.soundindex("soldier/solatck1.wav"); self->s.skinnum = 2; - self->health = 30; + self->max_health = self->health = 30; self->gib_health = -30; } @@ -1242,6 +1242,6 @@ void SP_monster_soldier_ss(edict_t *self) gi.soundindex("soldier/solatck3.wav"); self->s.skinnum = 4; - self->health = 40; + self->max_health = self->health = 40; self->gib_health = -30; } diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index d8d0f52e1..d74801144 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -384,14 +384,17 @@ void G_SetStats(edict_t *ent) // ran out of cells for power armor ent->flags &= ~FL_POWER_ARMOR; gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0); - power_armor_type = 0;; + power_armor_type = 0; } } index = ArmorIndex(ent); if (power_armor_type && (!index || (level.framenum & 8))) { // flash between power armor and other armor icon - ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex("i_powershield"); + if (power_armor_type == POWER_ARMOR_SHIELD) + ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex("i_powershield"); + else + ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex("i_powerscreen"); ent->client->ps.stats[STAT_ARMOR] = cells; } else if (index) { item = GetItemByIndex(index); From b78077f71fc61b5d88e48a01df00836a0fe5690f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 20 Sep 2022 03:12:28 +0300 Subject: [PATCH 09/59] Fix odd use of sprintf(), check for overflow. --- src/baseq2/g_cmds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/baseq2/g_cmds.c b/src/baseq2/g_cmds.c index 33e273919..3cae38ecb 100644 --- a/src/baseq2/g_cmds.c +++ b/src/baseq2/g_cmds.c @@ -828,7 +828,8 @@ void Cmd_PlayerList_f(edict_t *ent) e2->client->pers.netname, e2->client->resp.spectator ? " (spectator)" : ""); if (strlen(text) + strlen(st) > sizeof(text) - 50) { - sprintf(text + strlen(text), "And more...\n"); + if (strlen(text) < sizeof(text) - 12) + strcat(text, "And more...\n"); gi.cprintf(ent, PRINT_HIGH, "%s", text); return; } From c4863015c9a2bba5b96ed846509d13418966c61a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 20 Sep 2022 03:12:46 +0300 Subject: [PATCH 10/59] Fix a typo. --- src/baseq2/p_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index d74801144..5f7ec6483 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -53,7 +53,7 @@ void MoveClientToIntermission(edict_t *ent) ent->s.modelindex = 0; ent->s.modelindex2 = 0; ent->s.modelindex3 = 0; - ent->s.modelindex = 0; + ent->s.modelindex4 = 0; ent->s.effects = 0; ent->s.sound = 0; ent->solid = SOLID_NOT; From 6a891ac0ce0a0959911f84a6c0b51a866660f895 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 20 Sep 2022 00:03:00 +0300 Subject: [PATCH 11/59] Fix some -Wlto-type-mismatch warnings. --- src/baseq2/g_turret.c | 4 ++-- src/baseq2/p_client.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/baseq2/g_turret.c b/src/baseq2/g_turret.c index ded5b7ab6..ce5bae19c 100644 --- a/src/baseq2/g_turret.c +++ b/src/baseq2/g_turret.c @@ -262,7 +262,7 @@ Must NOT be on the team with the rest of the turret parts. Instead it must target the turret_breach. */ -void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage); +void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); void infantry_stand(edict_t *self); void monster_use(edict_t *self, edict_t *other, edict_t *activator); @@ -283,7 +283,7 @@ void turret_driver_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int self->target_ent->owner = NULL; self->target_ent->teammaster->owner = NULL; - infantry_die(self, inflictor, attacker, damage); + infantry_die(self, inflictor, attacker, damage, point); } bool FindTarget(edict_t *self); diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 568cebc60..c13f9c333 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -159,7 +159,7 @@ void SP_info_player_coop(edict_t *self) The deathmatch intermission point will be at one of these Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw. 'pitch yaw roll' */ -void SP_info_player_intermission(void) +void SP_info_player_intermission(edict_t *ent) { } From 71fa1b0b358a2a1ba015d41d49cdccaaceb48cb1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 30 Sep 2022 22:53:54 +0300 Subject: [PATCH 12/59] Avoid potentially undefined pointer arithmetic. --- src/baseq2/g_save.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_save.c b/src/baseq2/g_save.c index 95f3a3e8a..d5bd11e8d 100644 --- a/src/baseq2/g_save.c +++ b/src/baseq2/g_save.c @@ -481,19 +481,18 @@ static void write_vector(FILE *f, vec_t *v) static void write_index(FILE *f, void *p, size_t size, void *start, int max_index) { - size_t diff; + uintptr_t diff; if (!p) { write_int(f, -1); return; } - if (p < start || (byte *)p > (byte *)start + max_index * size) { + diff = (uintptr_t)p - (uintptr_t)start; + if (diff > max_index * size) { fclose(f); gi.error("%s: pointer out of range: %p", __func__, p); } - - diff = (byte *)p - (byte *)start; if (diff % size) { fclose(f); gi.error("%s: misaligned pointer: %p", __func__, p); From 00d23a3a23402fb92498a031a6fa47166f0a3331 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 30 Sep 2022 23:00:08 +0300 Subject: [PATCH 13/59] Don't allow saving strings longer than 64 KiB. --- src/baseq2/g_save.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/baseq2/g_save.c b/src/baseq2/g_save.c index d5bd11e8d..df049a541 100644 --- a/src/baseq2/g_save.c +++ b/src/baseq2/g_save.c @@ -468,6 +468,10 @@ static void write_string(FILE *f, char *s) } len = strlen(s); + if (len >= 65536) { + fclose(f); + gi.error("%s: bad length", __func__); + } write_int(f, len); write_data(s, len, f); } @@ -652,7 +656,7 @@ static char *read_string(FILE *f) return NULL; } - if (len < 0 || len > 65536) { + if (len < 0 || len >= 65536) { fclose(f); gi.error("%s: bad length", __func__); } From 3f985caa567d1f81e34a4254921e7ad4d1ff05a3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 30 Sep 2022 23:02:33 +0300 Subject: [PATCH 14/59] Use fixed size integer types for savegames. --- src/baseq2/g_save.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_save.c b/src/baseq2/g_save.c index df049a541..c955ceff7 100644 --- a/src/baseq2/g_save.c +++ b/src/baseq2/g_save.c @@ -440,13 +440,13 @@ static void write_data(void *buf, size_t len, FILE *f) } } -static void write_short(FILE *f, short v) +static void write_short(FILE *f, int16_t v) { v = LittleShort(v); write_data(&v, sizeof(v), f); } -static void write_int(FILE *f, int v) +static void write_int(FILE *f, int32_t v) { v = LittleLong(v); write_data(&v, sizeof(v), f); @@ -617,7 +617,7 @@ static void read_data(void *buf, size_t len, FILE *f) static int read_short(FILE *f) { - short v; + int16_t v; read_data(&v, sizeof(v), f); v = LittleShort(v); @@ -627,7 +627,7 @@ static int read_short(FILE *f) static int read_int(FILE *f) { - int v; + int32_t v; read_data(&v, sizeof(v), f); v = LittleLong(v); From 10cfdb9df290443db7a8e95d70663ce466989689 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 3 Oct 2023 17:00:18 +0200 Subject: [PATCH 15/59] Enable PIC on zlibstatic --- extern/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index e071bd2ca..dbc22dd3f 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -8,7 +8,7 @@ if (NOT CONFIG_LINUX_STEAM_RUNTIME_SUPPORT) target_include_directories(zlibstatic PUBLIC $ $) set_target_properties(zlib PROPERTIES FOLDER extern) - set_target_properties(zlibstatic PROPERTIES FOLDER extern) + set_target_properties(zlibstatic PROPERTIES FOLDER extern POSITION_INDEPENDENT_CODE ON) set_target_properties(minigzip PROPERTIES FOLDER extern) set_target_properties(example PROPERTIES FOLDER extern) endif() From a56441422c2c9fbcab10ebe7e254f2d09af5dc4e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 30 Sep 2022 23:04:00 +0300 Subject: [PATCH 16/59] Compress savegames with gzip. --- src/CMakeLists.txt | 2 + src/baseq2/g_save.c | 129 ++++++++++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf7d4ae2d..e344015ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -567,11 +567,13 @@ if (CONFIG_LINUX_STEAM_RUNTIME_SUPPORT) TARGET_LINK_LIBRARIES(client SDL2main SDL2-static z) ENDIF() TARGET_LINK_LIBRARIES(server z) + TARGET_LINK_LIBRARIES(baseq2 z) else() IF(TARGET client) TARGET_LINK_LIBRARIES(client SDL2main SDL2-static zlibstatic) ENDIF() TARGET_LINK_LIBRARIES(server zlibstatic) + TARGET_LINK_LIBRARIES(baseq2 zlibstatic) endif() IF(UNIX) diff --git a/src/baseq2/g_save.c b/src/baseq2/g_save.c index c955ceff7..1df1ba20a 100644 --- a/src/baseq2/g_save.c +++ b/src/baseq2/g_save.c @@ -19,6 +19,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "g_local.h" #include "g_ptrs.h" +#if USE_ZLIB +#include +#else +#define gzopen(name, mode) fopen(name, mode) +#define gzclose(file) fclose(file) +#define gzwrite(file, buf, len) fwrite(buf, 1, len, file) +#define gzread(file, buf, len) fread(buf, 1, len, file) +#define gzbuffer(file, size) (void)0 +#define gzFile FILE * +#endif + typedef struct { fieldtype_t type; #if USE_DEBUG @@ -432,33 +443,33 @@ static const save_field_t gamefields[] = { //========================================================= -static void write_data(void *buf, size_t len, FILE *f) +static void write_data(void *buf, size_t len, gzFile f) { - if (fwrite(buf, 1, len, f) != len) { - fclose(f); + if (gzwrite(f, buf, len) != len) { + gzclose(f); gi.error("%s: couldn't write %zu bytes", __func__, len); } } -static void write_short(FILE *f, int16_t v) +static void write_short(gzFile f, int16_t v) { v = LittleShort(v); write_data(&v, sizeof(v), f); } -static void write_int(FILE *f, int32_t v) +static void write_int(gzFile f, int32_t v) { v = LittleLong(v); write_data(&v, sizeof(v), f); } -static void write_float(FILE *f, float v) +static void write_float(gzFile f, float v) { v = LittleFloat(v); write_data(&v, sizeof(v), f); } -static void write_string(FILE *f, char *s) +static void write_string(gzFile f, char *s) { size_t len; @@ -469,21 +480,21 @@ static void write_string(FILE *f, char *s) len = strlen(s); if (len >= 65536) { - fclose(f); + gzclose(f); gi.error("%s: bad length", __func__); } write_int(f, len); write_data(s, len, f); } -static void write_vector(FILE *f, vec_t *v) +static void write_vector(gzFile f, vec_t *v) { write_float(f, v[0]); write_float(f, v[1]); write_float(f, v[2]); } -static void write_index(FILE *f, void *p, size_t size, void *start, int max_index) +static void write_index(gzFile f, void *p, size_t size, void *start, int max_index) { uintptr_t diff; @@ -494,17 +505,17 @@ static void write_index(FILE *f, void *p, size_t size, void *start, int max_inde diff = (uintptr_t)p - (uintptr_t)start; if (diff > max_index * size) { - fclose(f); + gzclose(f); gi.error("%s: pointer out of range: %p", __func__, p); } if (diff % size) { - fclose(f); + gzclose(f); gi.error("%s: misaligned pointer: %p", __func__, p); } write_int(f, (int)(diff / size)); } -static void write_pointer(FILE *f, void *p, ptr_type_t type) +static void write_pointer(gzFile f, void *p, ptr_type_t type) { const save_ptr_t *ptr; int i; @@ -521,11 +532,11 @@ static void write_pointer(FILE *f, void *p, ptr_type_t type) } } - fclose(f); + gzclose(f); gi.error("%s: unknown pointer: %p", __func__, p); } -static void write_field(FILE *f, const save_field_t *field, void *base) +static void write_field(gzFile f, const save_field_t *field, void *base) { void *p = (byte *)base + field->ofs; int i; @@ -591,7 +602,7 @@ static void write_field(FILE *f, const save_field_t *field, void *base) } } -static void write_fields(FILE *f, const save_field_t *fields, void *base) +static void write_fields(gzFile f, const save_field_t *fields, void *base) { const save_field_t *field; @@ -601,21 +612,21 @@ static void write_fields(FILE *f, const save_field_t *fields, void *base) } typedef struct game_read_context_s { - FILE *f; + gzFile f; bool frametime_is_float; const save_ptr_t* save_ptrs; int num_save_ptrs; } game_read_context_t; -static void read_data(void *buf, size_t len, FILE *f) +static void read_data(void *buf, size_t len, gzFile f) { - if (fread(buf, 1, len, f) != len) { - fclose(f); + if (gzread(f, buf, len) != len) { + gzclose(f); gi.error("%s: couldn't read %zu bytes", __func__, len); } } -static int read_short(FILE *f) +static int read_short(gzFile f) { int16_t v; @@ -625,7 +636,7 @@ static int read_short(FILE *f) return v; } -static int read_int(FILE *f) +static int read_int(gzFile f) { int32_t v; @@ -635,7 +646,7 @@ static int read_int(FILE *f) return v; } -static float read_float(FILE *f) +static float read_float(gzFile f) { float v; @@ -646,7 +657,7 @@ static float read_float(FILE *f) } -static char *read_string(FILE *f) +static char *read_string(gzFile f) { int len; char *s; @@ -657,7 +668,7 @@ static char *read_string(FILE *f) } if (len < 0 || len >= 65536) { - fclose(f); + gzclose(f); gi.error("%s: bad length", __func__); } @@ -668,13 +679,13 @@ static char *read_string(FILE *f) return s; } -static void read_zstring(FILE *f, char *s, size_t size) +static void read_zstring(gzFile f, char *s, size_t size) { int len; len = read_int(f); if (len < 0 || len >= size) { - fclose(f); + gzclose(f); gi.error("%s: bad length", __func__); } @@ -682,14 +693,14 @@ static void read_zstring(FILE *f, char *s, size_t size) s[len] = 0; } -static void read_vector(FILE *f, vec_t *v) +static void read_vector(gzFile f, vec_t *v) { v[0] = read_float(f); v[1] = read_float(f); v[2] = read_float(f); } -static void *read_index(FILE *f, size_t size, void *start, int max_index) +static void *read_index(gzFile f, size_t size, void *start, int max_index) { int index; byte *p; @@ -700,7 +711,7 @@ static void *read_index(FILE *f, size_t size, void *start, int max_index) } if (index < 0 || index > max_index) { - fclose(f); + gzclose(f); gi.error("%s: bad index", __func__); } @@ -719,13 +730,13 @@ static void *read_pointer(game_read_context_t* ctx, ptr_type_t type) } if (index < 0 || index >= ctx->num_save_ptrs) { - fclose(ctx->f); + gzclose(ctx->f); gi.error("%s: bad index", __func__); } ptr = &ctx->save_ptrs[index]; if (ptr->type != type) { - fclose(ctx->f); + gzclose(ctx->f); gi.error("%s: type mismatch", __func__); } @@ -819,6 +830,14 @@ static void read_fields(game_read_context_t* ctx, const save_field_t *fields, vo #define SAVE_MAGIC2 MakeLittleLong('S','A','V','1') #define SAVE_VERSION 8 +static void check_gzip(int magic) +{ +#if !USE_ZLIB + if ((magic & 0xe0ffffff) == 0x00088b1f) + gi.error("Savegame is compressed, but no gzip support linked in"); +#endif +} + /* ============ WriteGame @@ -835,13 +854,13 @@ last save position. */ void WriteGame(const char *filename, qboolean autosave) { - FILE *f; + gzFile f; int i; if (!autosave) SaveClientData(); - f = fopen(filename, "wb"); + f = gzopen(filename, "wb"); if (!f) gi.error("Couldn't open %s", filename); @@ -856,11 +875,11 @@ void WriteGame(const char *filename, qboolean autosave) write_fields(f, clientfields, &game.clients[i]); } - if (fclose(f)) + if (gzclose(f)) gi.error("Couldn't write %s", filename); } -static game_read_context_t make_read_context(FILE* f, int version) +static game_read_context_t make_read_context(gzFile f, int version) { game_read_context_t ctx; ctx.f = f; @@ -880,25 +899,28 @@ static game_read_context_t make_read_context(FILE* f, int version) void ReadGame(const char *filename) { - FILE *f; + gzFile f; int i; gi.FreeTags(TAG_GAME); - f = fopen(filename, "rb"); + f = gzopen(filename, "rb"); if (!f) gi.error("Couldn't open %s", filename); + gzbuffer(f, 65536); + i = read_int(f); if (i != SAVE_MAGIC1) { - fclose(f); + gzclose(f); + check_gzip(i); gi.error("Not a save game"); } i = read_int(f); if ((i != SAVE_VERSION) && (i != 2)) { // Version 2 was written by Q2RTX 1.5.0, and the savegame code was crafted such to allow reading it - fclose(f); + gzclose(f); gi.error("Savegame from different version (got %d, expected %d)", i, SAVE_VERSION); } @@ -908,11 +930,11 @@ void ReadGame(const char *filename) // should agree with server's version if (game.maxclients != (int)maxclients->value) { - fclose(f); + gzclose(f); gi.error("Savegame has bad maxclients"); } if (game.maxentities <= game.maxclients || game.maxentities > MAX_EDICTS) { - fclose(f); + gzclose(f); gi.error("Savegame has bad maxentities"); } @@ -925,7 +947,7 @@ void ReadGame(const char *filename) read_fields(&ctx, clientfields, &game.clients[i]); } - fclose(f); + gzclose(f); } //========================================================== @@ -941,9 +963,9 @@ void WriteLevel(const char *filename) { int i; edict_t *ent; - FILE *f; + gzFile f; - f = fopen(filename, "wb"); + f = gzopen(filename, "wb"); if (!f) gi.error("Couldn't open %s", filename); @@ -963,7 +985,7 @@ void WriteLevel(const char *filename) } write_int(f, -1); - if (fclose(f)) + if (gzclose(f)) gi.error("Couldn't write %s", filename); } @@ -987,7 +1009,7 @@ No clients are connected yet. void ReadLevel(const char *filename) { int entnum; - FILE *f; + gzFile f; int i; edict_t *ent; @@ -995,24 +1017,27 @@ void ReadLevel(const char *filename) // base state gi.FreeTags(TAG_LEVEL); - f = fopen(filename, "rb"); + f = gzopen(filename, "rb"); if (!f) gi.error("Couldn't open %s", filename); + gzbuffer(f, 65536); + // wipe all the entities memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); globals.num_edicts = maxclients->value + 1; i = read_int(f); if (i != SAVE_MAGIC2) { - fclose(f); + gzclose(f); + check_gzip(i); gi.error("Not a save game"); } i = read_int(f); if ((i != SAVE_VERSION) && (i != 2)) { // Version 2 was written by Q2RTX 1.5.0, and the savegame code was crafted such to allow reading it - fclose(f); + gzclose(f); gi.error("Savegame from different version (got %d, expected %d)", i, SAVE_VERSION); } @@ -1027,7 +1052,7 @@ void ReadLevel(const char *filename) if (entnum == -1) break; if (entnum < 0 || entnum >= game.maxentities) { - fclose(f); + gzclose(f); gi.error("%s: bad entity number", __func__); } if (entnum >= globals.num_edicts) @@ -1043,7 +1068,7 @@ void ReadLevel(const char *filename) gi.linkentity(ent); } - fclose(f); + gzclose(f); // mark all clients as unconnected for (i = 0 ; i < maxclients->value ; i++) { From 19b9959aef40cb1e4c41fae061b7c5507399faa2 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 10 Oct 2022 00:06:08 +0300 Subject: [PATCH 17/59] =?UTF-8?q?Fix=20UB=20if=20=E2=80=98flood=5Fmsgs?= =?UTF-8?q?=E2=80=99=20is=20out=20of=20range.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/baseq2/g_cmds.c | 59 +++++++++++++++++++++++++------------------- src/baseq2/g_local.h | 8 +++--- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/baseq2/g_cmds.c b/src/baseq2/g_cmds.c index 3cae38ecb..2899e8ad9 100644 --- a/src/baseq2/g_cmds.c +++ b/src/baseq2/g_cmds.c @@ -723,6 +723,36 @@ void Cmd_Wave_f(edict_t *ent) } } +static bool FloodProtect(edict_t *ent) +{ + int i, msgs = flood_msgs->value; + gclient_t *cl = ent->client; + + if (msgs < 1) + return false; + + if (level.time < cl->flood_locktill) { + gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n", + (int)(cl->flood_locktill - level.time)); + return true; + } + + i = cl->flood_whenhead - min(msgs, FLOOD_MSGS) + 1; + if (i < 0) + i += FLOOD_MSGS; + if (cl->flood_when[i] && + level.time - cl->flood_when[i] < flood_persecond->value) { + cl->flood_locktill = level.time + flood_waitdelay->value; + gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n", + (int)flood_waitdelay->value); + return true; + } + + cl->flood_whenhead = (cl->flood_whenhead + 1) % FLOOD_MSGS; + cl->flood_when[cl->flood_whenhead] = level.time; + return false; +} + /* ================== Cmd_Say_f @@ -730,15 +760,17 @@ Cmd_Say_f */ void Cmd_Say_f(edict_t *ent, bool team, bool arg0) { - int i, j; + int j; edict_t *other; char *p; char text[2048]; - gclient_t *cl; if (gi.argc() < 2 && !arg0) return; + if (FloodProtect(ent)) + return; + if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) team = false; @@ -767,29 +799,6 @@ void Cmd_Say_f(edict_t *ent, bool team, bool arg0) strcat(text, "\n"); - if (flood_msgs->value) { - cl = ent->client; - - if (level.time < cl->flood_locktill) { - gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n", - (int)(cl->flood_locktill - level.time)); - return; - } - i = cl->flood_whenhead - flood_msgs->value + 1; - if (i < 0) - i = (sizeof(cl->flood_when) / sizeof(cl->flood_when[0])) + i; - if (cl->flood_when[i] && - level.time - cl->flood_when[i] < flood_persecond->value) { - cl->flood_locktill = level.time + flood_waitdelay->value; - gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n", - (int)flood_waitdelay->value); - return; - } - cl->flood_whenhead = (cl->flood_whenhead + 1) % - (sizeof(cl->flood_when) / sizeof(cl->flood_when[0])); - cl->flood_when[cl->flood_whenhead] = level.time; - } - if (dedicated->value) gi.cprintf(NULL, PRINT_CHAT, "%s", text); diff --git a/src/baseq2/g_local.h b/src/baseq2/g_local.h index c30466019..136682ce4 100644 --- a/src/baseq2/g_local.h +++ b/src/baseq2/g_local.h @@ -944,9 +944,11 @@ struct gclient_s { int pickup_msg_framenum; - float flood_locktill; // locked from talking - float flood_when[10]; // when messages were said - int flood_whenhead; // head pointer for when said +#define FLOOD_MSGS 10 + + float flood_locktill; // locked from talking + float flood_when[FLOOD_MSGS]; // when messages were said + int flood_whenhead; // head pointer for when said int respawn_framenum; // can respawn when time > this From bb9f10a2efd0c636c9bb8cf9c95afcc6ee509cb5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 21 Oct 2022 16:48:29 +0300 Subject: [PATCH 18/59] Fix func_explosive_use() to pass proper activator. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes ‘PF_centerprintf to a non-client’ warning on map ‘command’ in single player. Fixes #273. --- src/baseq2/g_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/g_misc.c b/src/baseq2/g_misc.c index 91afa3ee4..9d58ea024 100644 --- a/src/baseq2/g_misc.c +++ b/src/baseq2/g_misc.c @@ -756,7 +756,7 @@ void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator) { - func_explosive_explode(self, other, activator, self->health, self->s.origin); + func_explosive_explode(self, self, activator, self->health, self->s.origin); } void func_explosive_spawn(edict_t *self, edict_t *other, edict_t *activator) From a9a3246d4ca79bdf1cb4d9467f05d855fb3326a6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 2 Nov 2022 16:58:33 +0300 Subject: [PATCH 19/59] Fix possible misc_viper_bomb_use() crash. --- src/baseq2/g_misc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_misc.c b/src/baseq2/g_misc.c index 9d58ea024..8b47ca3d5 100644 --- a/src/baseq2/g_misc.c +++ b/src/baseq2/g_misc.c @@ -1306,12 +1306,13 @@ void misc_viper_bomb_use(edict_t *self, edict_t *other, edict_t *activator) self->prethink = misc_viper_bomb_prethink; self->touch = misc_viper_bomb_touch; self->activator = activator; + self->timestamp = level.framenum; viper = G_Find(NULL, FOFS(classname), "misc_viper"); - VectorScale(viper->moveinfo.dir, viper->moveinfo.speed, self->velocity); - - self->timestamp = level.framenum; - VectorCopy(viper->moveinfo.dir, self->moveinfo.dir); + if (viper) { + VectorScale(viper->moveinfo.dir, viper->moveinfo.speed, self->velocity); + VectorCopy(viper->moveinfo.dir, self->moveinfo.dir); + } } void SP_misc_viper_bomb(edict_t *self) From 25a0fd4a11cc9f09a79ad397cdc2a2c2a229f1ab Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 2 Nov 2022 18:24:31 +0300 Subject: [PATCH 20/59] Fix possible BeginIntermission() crash. --- src/baseq2/p_hud.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 5f7ec6483..01c83503b 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -128,8 +128,10 @@ void BeginIntermission(edict_t *targ) } } - VectorCopy(ent->s.origin, level.intermission_origin); - VectorCopy(ent->s.angles, level.intermission_angle); + if (ent) { + VectorCopy(ent->s.origin, level.intermission_origin); + VectorCopy(ent->s.angles, level.intermission_angle); + } // move all clients to the intermission point for (i = 0 ; i < maxclients->value ; i++) { From f6d22029c21194f149b70b89b621b07d74ab7832 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 9 Nov 2022 14:33:28 +0300 Subject: [PATCH 21/59] Clip player entity to spawn point. Fixes annoying issue when player spawns higher than spawn point. Code originally from OpenTDM. --- src/baseq2/p_client.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index c13f9c333..7e192d498 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -877,7 +877,6 @@ void SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles) } VectorCopy(spot->s.origin, origin); - origin[2] += 9; VectorCopy(spot->s.angles, angles); } @@ -1080,6 +1079,8 @@ void PutClientInServer(edict_t *ent) int i; client_persistant_t saved; client_respawn_t resp; + vec3_t temp, temp2; + trace_t tr; // find a spawn point // do it before setting health back up, so farthest @@ -1156,10 +1157,6 @@ void PutClientInServer(edict_t *ent) // clear playerstate values memset(&ent->client->ps, 0, sizeof(client->ps)); - for (i = 0; i < 3; i++) { - client->ps.pmove.origin[i] = COORD2SHORT(spawn_origin[i]); - } - if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { client->ps.fov = 90; } else { @@ -1179,12 +1176,28 @@ void PutClientInServer(edict_t *ent) // sknum is player num and weapon number // weapon number will be added in changeweapon ent->s.skinnum = ent - g_edicts - 1; - ent->s.frame = 0; - VectorCopy(spawn_origin, ent->s.origin); - ent->s.origin[2] += 1; // make sure off ground + + // try to properly clip to the floor / spawn + VectorCopy(spawn_origin, temp); + VectorCopy(spawn_origin, temp2); + temp[2] -= 64; + temp2[2] += 16; + tr = gi.trace(temp2, ent->mins, ent->maxs, temp, ent, MASK_PLAYERSOLID); + if (!tr.allsolid && !tr.startsolid) { + VectorCopy(tr.endpos, ent->s.origin); + ent->groundentity = tr.ent; + } else { + VectorCopy(spawn_origin, ent->s.origin); + ent->s.origin[2] += 10; // make sure off ground + } + VectorCopy(ent->s.origin, ent->s.old_origin); + for (i = 0; i < 3; i++) { + client->ps.pmove.origin[i] = COORD2SHORT(ent->s.origin[i]); + } + // set the delta angle for (i = 0 ; i < 3 ; i++) { client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]); From ba07758a3a0415dcf311b064859a45aad650e96a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 9 Nov 2022 14:47:26 +0300 Subject: [PATCH 22/59] Reset spawn pitch/roll angle before setting delta angles. Otherwise delta angles will be wrong if spawn point has non-zero pitch/roll. --- src/baseq2/p_client.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 7e192d498..573f00949 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1198,16 +1198,17 @@ void PutClientInServer(edict_t *ent) client->ps.pmove.origin[i] = COORD2SHORT(ent->s.origin[i]); } + spawn_angles[PITCH] = 0; + spawn_angles[ROLL] = 0; + // set the delta angle for (i = 0 ; i < 3 ; i++) { client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]); } - ent->s.angles[PITCH] = 0; - ent->s.angles[YAW] = spawn_angles[YAW]; - ent->s.angles[ROLL] = 0; - VectorCopy(ent->s.angles, client->ps.viewangles); - VectorCopy(ent->s.angles, client->v_angle); + VectorCopy(spawn_angles, ent->s.angles); + VectorCopy(spawn_angles, client->ps.viewangles); + VectorCopy(spawn_angles, client->v_angle); // spawn a spectator if (client->pers.spectator) { From 3f400cd349ce220cc2ef676f1498f95e7f746d0d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 9 Nov 2022 16:15:45 +0300 Subject: [PATCH 23/59] Clarify error message. --- src/baseq2/g_save.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/baseq2/g_save.c b/src/baseq2/g_save.c index 1df1ba20a..d901f160e 100644 --- a/src/baseq2/g_save.c +++ b/src/baseq2/g_save.c @@ -656,7 +656,6 @@ static float read_float(gzFile f) return v; } - static char *read_string(gzFile f) { int len; @@ -914,7 +913,7 @@ void ReadGame(const char *filename) if (i != SAVE_MAGIC1) { gzclose(f); check_gzip(i); - gi.error("Not a save game"); + gi.error("Not a Q2PRO save game"); } i = read_int(f); @@ -1031,7 +1030,7 @@ void ReadLevel(const char *filename) if (i != SAVE_MAGIC2) { gzclose(f); check_gzip(i); - gi.error("Not a save game"); + gi.error("Not a Q2PRO save game"); } i = read_int(f); From 15d055108cf14ade446461746c62de0e35aa7c5a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 16 Nov 2022 18:17:21 +0300 Subject: [PATCH 24/59] Attempt to fix missing jump sounds. When the player jumps again "quickly enough" after landing change to groundentity can go unnoticed. Check for PMF_JUMP_HELD flag for a more proper way to detect jumps. --- src/baseq2/p_client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 573f00949..599e1b198 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1607,10 +1607,6 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) // perform a pmove gi.Pmove(&pm); - // save results of pmove - client->ps.pmove = pm.s; - client->old_pmove = pm.s; - for (i = 0 ; i < 3 ; i++) { ent->s.origin[i] = SHORT2COORD(pm.s.origin[i]); ent->velocity[i] = SHORT2COORD(pm.s.velocity[i]); @@ -1623,11 +1619,15 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); - if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0)) { + if (~client->ps.pmove.pm_flags & pm.s.pm_flags & PMF_JUMP_HELD) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); } + // save results of pmove + client->ps.pmove = pm.s; + client->old_pmove = pm.s; + ent->viewheight = pm.viewheight; ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; From a3fd33d4fc3926868322f36dc693608451203506 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 19 Nov 2022 19:07:50 +0300 Subject: [PATCH 25/59] Fix annoying FOV change when exiting SP level. Exit intermission before ClientEndServerFrames() to avoid resetting player FOV to 90 for a single server frame. --- src/baseq2/g_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index 35cd4d7cb..509c42976 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -488,7 +488,6 @@ void G_RunFrame(void) AI_SetSightClient(); // exit intermissions - if (level.exitintermission) { ExitLevel(); return; @@ -523,6 +522,12 @@ void G_RunFrame(void) G_RunEntity(ent); } + // exit intermission right now to avoid annoying fov change + if (level.exitintermission) { + ExitLevel(); + return; + } + // see if it is time to end a deathmatch CheckDMRules(); From 54425e80d4b7a955772eea435490e839dc5897e6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 20 Nov 2022 17:09:14 +0300 Subject: [PATCH 26/59] Add monster_makron to spawn_funcs[]. --- src/baseq2/g_spawn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index d3c771d61..82bef2b88 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -138,6 +138,7 @@ void SP_monster_hover(edict_t *self); void SP_monster_mutant(edict_t *self); void SP_monster_supertank(edict_t *self); void SP_monster_boss2(edict_t *self); +void SP_monster_makron(edict_t *self); void SP_monster_jorg(edict_t *self); void SP_monster_boss3_stand(edict_t *self); @@ -259,6 +260,7 @@ static const spawn_func_t spawn_funcs[] = { {"monster_supertank", SP_monster_supertank}, {"monster_boss2", SP_monster_boss2}, {"monster_boss3_stand", SP_monster_boss3_stand}, + {"monster_makron", SP_monster_makron}, {"monster_jorg", SP_monster_jorg}, {"monster_commander_body", SP_monster_commander_body}, From 55ec547f49f8be99e8ae577de169128960c4a360 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 21 Nov 2022 17:07:30 +0300 Subject: [PATCH 27/59] Fix screaming sound when jumping in shallow lava. Ensure that jumping in shallow lava will not override player screaming sound on the same channel. Follow-up fix to commit f69d77e4 that removed waterlevel check. --- src/baseq2/p_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 599e1b198..a2e1fe6ae 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1619,7 +1619,7 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); - if (~client->ps.pmove.pm_flags & pm.s.pm_flags & PMF_JUMP_HELD) { + if (~client->ps.pmove.pm_flags & pm.s.pm_flags & PMF_JUMP_HELD && !(pm.watertype & CONTENTS_LAVA)) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); } From 5138c79cc80587c3ab0e7da1cc115a186f1f25fc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 21 Nov 2022 20:56:40 +0300 Subject: [PATCH 28/59] Restore original waterlevel jump sound check. Probably better to keep original behavior after all (no sound when jumping in shallow water). --- src/baseq2/p_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index a2e1fe6ae..309a1ab72 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1619,7 +1619,7 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); - if (~client->ps.pmove.pm_flags & pm.s.pm_flags & PMF_JUMP_HELD && !(pm.watertype & CONTENTS_LAVA)) { + if (~client->ps.pmove.pm_flags & pm.s.pm_flags & PMF_JUMP_HELD && pm.waterlevel == 0) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); } From 2669fbefd89c2cef6b60fa373e95c70bc3e4ee3b Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 3 Dec 2022 01:08:51 +0300 Subject: [PATCH 29/59] Add RF_NOSHADOW to some game entities. --- src/baseq2/g_misc.c | 5 ++++- src/baseq2/g_weapon.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/baseq2/g_misc.c b/src/baseq2/g_misc.c index 8b47ca3d5..0238a27f5 100644 --- a/src/baseq2/g_misc.c +++ b/src/baseq2/g_misc.c @@ -990,7 +990,7 @@ void SP_misc_blackhole(edict_t *ent) VectorSet(ent->mins, -64, -64, 0); VectorSet(ent->maxs, 64, 64, 8); ent->s.modelindex = gi.modelindex("models/objects/black/tris.md2"); - ent->s.renderfx = RF_TRANSLUCENT; + ent->s.renderfx = RF_TRANSLUCENT | RF_NOSHADOW; ent->use = misc_blackhole_use; ent->think = misc_blackhole_think; ent->nextthink = level.framenum + 2; @@ -1145,6 +1145,7 @@ void SP_misc_banner(edict_t *ent) ent->solid = SOLID_NOT; ent->s.modelindex = gi.modelindex("models/objects/banner/tris.md2"); ent->s.frame = Q_rand() % 16; + ent->s.renderfx |= RF_NOSHADOW; gi.linkentity(ent); ent->think = misc_banner_think; @@ -1759,6 +1760,7 @@ void SP_misc_teleporter(edict_t *ent) gi.setmodel(ent, "models/objects/dmspot/tris.md2"); ent->s.skinnum = 1; ent->s.effects = EF_TELEPORTER; + ent->s.renderfx = RF_NOSHADOW; ent->s.sound = gi.soundindex("world/amb10.wav"); ent->solid = SOLID_BBOX; @@ -1787,6 +1789,7 @@ void SP_misc_teleporter_dest(edict_t *ent) ent->s.skinnum = 0; ent->solid = SOLID_BBOX; // ent->s.effects |= EF_FLIES; + ent->s.renderfx |= RF_NOSHADOW; VectorSet(ent->mins, -32, -32, -24); VectorSet(ent->maxs, 32, 32, -16); gi.linkentity(ent); diff --git a/src/baseq2/g_weapon.c b/src/baseq2/g_weapon.c index b70b085db..35918341f 100644 --- a/src/baseq2/g_weapon.c +++ b/src/baseq2/g_weapon.c @@ -338,6 +338,7 @@ void fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed bolt->clipmask = MASK_SHOT; bolt->solid = SOLID_BBOX; bolt->s.effects |= effect; + bolt->s.renderfx |= RF_NOSHADOW; VectorClear(bolt->mins); VectorClear(bolt->maxs); bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2"); From 1565232aec1eaf276d77b12f6b0d204da1c9ff4b Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 10 Dec 2022 16:12:25 +0300 Subject: [PATCH 30/59] Remove tv() function. --- src/baseq2/g_items.c | 11 ++++------- src/baseq2/g_local.h | 2 -- src/baseq2/g_utils.c | 27 --------------------------- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/baseq2/g_items.c b/src/baseq2/g_items.c index 674ec185a..da9d8c555 100644 --- a/src/baseq2/g_items.c +++ b/src/baseq2/g_items.c @@ -868,12 +868,9 @@ void droptofloor(edict_t *ent) { trace_t tr; vec3_t dest; - float *v; - v = tv(-15, -15, -15); - VectorCopy(v, ent->mins); - v = tv(15, 15, 15); - VectorCopy(v, ent->maxs); + VectorSet(ent->mins, -15, -15, -15); + VectorSet(ent->maxs, 15, 15, 15); if (ent->model) gi.setmodel(ent, ent->model); @@ -883,8 +880,8 @@ void droptofloor(edict_t *ent) ent->movetype = MOVETYPE_TOSS; ent->touch = Touch_Item; - v = tv(0, 0, -128); - VectorAdd(ent->s.origin, v, dest); + VectorCopy(ent->s.origin, dest); + dest[2] -= 128; tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID); if (tr.startsolid) { diff --git a/src/baseq2/g_local.h b/src/baseq2/g_local.h index 136682ce4..a108b2840 100644 --- a/src/baseq2/g_local.h +++ b/src/baseq2/g_local.h @@ -635,8 +635,6 @@ void G_TouchSolids(edict_t *ent); char *G_CopyString(char *in); -float *tv(float x, float y, float z); - float vectoyaw(vec3_t vec); void vectoangles(vec3_t vec, vec3_t angles); diff --git a/src/baseq2/g_utils.c b/src/baseq2/g_utils.c index 730b12dde..22c857c27 100644 --- a/src/baseq2/g_utils.c +++ b/src/baseq2/g_utils.c @@ -237,33 +237,6 @@ void G_UseTargets(edict_t *ent, edict_t *activator) } -/* -============= -TempVector - -This is just a convenience function -for making temporary vectors for function calls -============= -*/ -float *tv(float x, float y, float z) -{ - static int index; - static vec3_t vecs[8]; - float *v; - - // use an array so that multiple tempvectors won't collide - // for a while - v = vecs[index]; - index = (index + 1) & 7; - - v[0] = x; - v[1] = y; - v[2] = z; - - return v; -} - - vec3_t VEC_UP = {0, -1, 0}; vec3_t MOVEDIR_UP = {0, 0, 1}; vec3_t VEC_DOWN = {0, -2, 0}; From 986da0d45cc8e8293e8e4cc1a3fdb45c74b26f1a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 21 Dec 2022 09:54:03 +0300 Subject: [PATCH 31/59] Reduce code duplication. --- src/baseq2/g_misc.c | 57 ++++++++------------------------------------- 1 file changed, 10 insertions(+), 47 deletions(-) diff --git a/src/baseq2/g_misc.c b/src/baseq2/g_misc.c index 0238a27f5..1d1ed8264 100644 --- a/src/baseq2/g_misc.c +++ b/src/baseq2/g_misc.c @@ -139,9 +139,7 @@ void ThrowGib(edict_t *self, char *gibname, int damage, int type) VectorScale(self->size, 0.5f, size); VectorAdd(self->absmin, size, origin); - gib->s.origin[0] = origin[0] + crandom() * size[0]; - gib->s.origin[1] = origin[1] + crandom() * size[1]; - gib->s.origin[2] = origin[2] + crandom() * size[2]; + VectorMA(origin, crandom(), size, gib->s.origin); gi.setmodel(gib, gibname); gib->solid = SOLID_NOT; @@ -728,9 +726,7 @@ void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker if (count > 8) count = 8; while (count--) { - chunkorigin[0] = origin[0] + crandom() * size[0]; - chunkorigin[1] = origin[1] + crandom() * size[1]; - chunkorigin[2] = origin[2] + crandom() * size[2]; + VectorMA(origin, crandom(), size, chunkorigin); ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin); } } @@ -740,9 +736,7 @@ void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker if (count > 16) count = 16; while (count--) { - chunkorigin[0] = origin[0] + crandom() * size[0]; - chunkorigin[1] = origin[1] + crandom() * size[1]; - chunkorigin[2] = origin[2] + crandom() * size[2]; + VectorMA(origin, crandom(), size, chunkorigin); ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin); } @@ -833,6 +827,7 @@ void barrel_explode(edict_t *self) vec3_t org; float spd; vec3_t save; + int i; T_RadiusDamage(self, self->activator, self->dmg, NULL, self->dmg + 40, MOD_BARREL); @@ -841,13 +836,9 @@ void barrel_explode(edict_t *self) // a few big chunks spd = 1.5f * (float)self->dmg / 200.0f; - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; + VectorMA(self->s.origin, crandom(), self->size, org); ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; + VectorMA(self->s.origin, crandom(), self->size, org); ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org); // bottom corners @@ -867,38 +858,10 @@ void barrel_explode(edict_t *self) // a bunch of little chunks spd = 2 * self->dmg / 200; - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self->s.origin[0] + crandom() * self->size[0]; - org[1] = self->s.origin[1] + crandom() * self->size[1]; - org[2] = self->s.origin[2] + crandom() * self->size[2]; - ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); + for (i = 0; i < 8; i++) { + VectorMA(self->s.origin, crandom(), self->size, org); + ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); + } VectorCopy(save, self->s.origin); if (self->groundentity) From 84e5f6b22d856b5a3ac76b8a85930d7b07dea850 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 9 Jan 2023 21:41:49 +0300 Subject: [PATCH 32/59] Use macro to clear blend. --- src/baseq2/p_view.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index 0bea526ff..45373cb5b 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -393,8 +393,7 @@ void SV_CalcBlend(edict_t *ent) vec3_t vieworg; int remaining; - ent->client->ps.blend[0] = ent->client->ps.blend[1] = - ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0; + Vector4Clear(ent->client->ps.blend); // add for contents VectorAdd(ent->s.origin, ent->client->ps.viewoffset, vieworg); From db647368643e73bdef4d0b9eedf9db91e23faba5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 9 Jan 2023 21:42:04 +0300 Subject: [PATCH 33/59] Unlink player entity before moving to intermission. Prevents player view from being pushed into wall in fact1 during intermission. Also clear more entity state and set SVF_NOCLIENT. --- src/baseq2/p_hud.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 01c83503b..4b7d87895 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -49,14 +49,21 @@ void MoveClientToIntermission(edict_t *ent) ent->client->grenade_blew_up = false; ent->client->grenade_framenum = 0; + ent->watertype = 0; + ent->waterlevel = 0; ent->viewheight = 0; ent->s.modelindex = 0; ent->s.modelindex2 = 0; ent->s.modelindex3 = 0; ent->s.modelindex4 = 0; ent->s.effects = 0; + ent->s.renderfx = 0; ent->s.sound = 0; + ent->s.event = 0; + ent->s.solid = 0; ent->solid = SOLID_NOT; + ent->svflags = SVF_NOCLIENT; + gi.unlinkentity(ent); // add the layout From 45f4f25e5034f2a28ed971c15549943ab42ca467 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 9 Jan 2023 21:45:43 +0300 Subject: [PATCH 34/59] Copy less entity state in CopyToBodyQue(). --- src/baseq2/p_client.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 309a1ab72..c91ba2ada 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -929,8 +929,14 @@ void CopyToBodyQue(edict_t *ent) } gi.unlinkentity(body); - body->s = ent->s; + body->s.number = body - g_edicts; + VectorCopy(ent->s.origin, body->s.origin); + VectorCopy(ent->s.origin, body->s.old_origin); + VectorCopy(ent->s.angles, body->s.angles); + body->s.modelindex = ent->s.modelindex; + body->s.frame = ent->s.frame; + body->s.skinnum = ent->s.skinnum; body->s.event = EV_OTHER_TELEPORT; body->svflags = ent->svflags; From c57087e4bd62aa1b8ee464922821469a35138f26 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 10 Jan 2023 14:52:22 +0300 Subject: [PATCH 35/59] Don't update player view in ExitLevel(). Avoids annoying viewheight change when exiting intermission. --- src/baseq2/g_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index 509c42976..dded2cced 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -456,7 +456,6 @@ void ExitLevel(void) level.changemap = NULL; level.exitintermission = 0; level.intermission_framenum = 0; - ClientEndServerFrames(); // clear some things before going to next level for (i = 0 ; i < maxclients->value ; i++) { From 56cc07772c9c5bb3a58c5c359a8281099d08ddb8 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 10 Jan 2023 14:53:35 +0300 Subject: [PATCH 36/59] Fix CreateTargetChangeLevel() snprintf()-ing string into self. Fixes going to next map in deathmatch when no map list is set. Why no one ever complained this wasn't working? --- src/baseq2/g_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index dded2cced..94ccf2fdc 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -310,7 +310,8 @@ edict_t *CreateTargetChangeLevel(char *map) ent = G_Spawn(); ent->classname = "target_changelevel"; - Q_snprintf(level.nextmap, sizeof(level.nextmap), "%s", map); + if (map != level.nextmap) + Q_strlcpy(level.nextmap, map, sizeof(level.nextmap)); ent->map = level.nextmap; return ent; } From c6a176bdbd9f02b2710553a1a38a59dee0c47744 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 10 Jan 2023 14:54:33 +0300 Subject: [PATCH 37/59] Replace strstr() with strchr(). --- src/baseq2/g_target.c | 2 +- src/baseq2/p_hud.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/baseq2/g_target.c b/src/baseq2/g_target.c index b665a90ff..29cfc38ae 100644 --- a/src/baseq2/g_target.c +++ b/src/baseq2/g_target.c @@ -284,7 +284,7 @@ void use_target_changelevel(edict_t *self, edict_t *other, edict_t *activator) } // if going to a new unit, clear cross triggers - if (strstr(self->map, "*")) + if (strchr(self->map, '*')) game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK); BeginIntermission(self); diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 4b7d87895..3d3087703 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -96,7 +96,7 @@ void BeginIntermission(edict_t *targ) level.intermission_framenum = level.framenum; level.changemap = targ->map; - if (strstr(level.changemap, "*")) { + if (strchr(level.changemap, '*')) { if (coop->value) { for (i = 0 ; i < maxclients->value ; i++) { client = g_edicts + 1 + i; From e1e1bbc6973a1e85743bd5820eb5ffc2b03cf906 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 10 Jan 2023 15:04:48 +0300 Subject: [PATCH 38/59] Use COM_StripQuotes() in Cmd_Say_f(). --- src/baseq2/g_cmds.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/baseq2/g_cmds.c b/src/baseq2/g_cmds.c index 2899e8ad9..a931b2e55 100644 --- a/src/baseq2/g_cmds.c +++ b/src/baseq2/g_cmds.c @@ -762,7 +762,6 @@ void Cmd_Say_f(edict_t *ent, bool team, bool arg0) { int j; edict_t *other; - char *p; char text[2048]; if (gi.argc() < 2 && !arg0) @@ -784,13 +783,7 @@ void Cmd_Say_f(edict_t *ent, bool team, bool arg0) strcat(text, " "); strcat(text, gi.args()); } else { - p = gi.args(); - - if (*p == '"') { - p++; - p[strlen(p) - 1] = 0; - } - strcat(text, p); + Q_strlcat(text, COM_StripQuotes(gi.args()), sizeof(text)); } // don't let text be too long for malicious reasons From 98c099643829deeec7e7166cc939c9e05fe4c2cf Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 10 Jan 2023 19:18:10 +0300 Subject: [PATCH 39/59] Avoid possible use of uninitialized data in SV_FilterPacket(). --- src/baseq2/g_svcmds.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_svcmds.c b/src/baseq2/g_svcmds.c index 0f9c6b2dd..d6f7b8fe8 100644 --- a/src/baseq2/g_svcmds.c +++ b/src/baseq2/g_svcmds.c @@ -79,10 +79,7 @@ static bool StringToFilter(char *s, ipfilter_t *f) unsigned u32; } b, m; - for (i = 0 ; i < 4 ; i++) { - b.bytes[i] = 0; - m.bytes[i] = 0; - } + b.u32 = m.u32 = 0; for (i = 0 ; i < 4 ; i++) { if (*s < '0' || *s > '9') { @@ -125,6 +122,8 @@ bool SV_FilterPacket(char *from) } m; char *p; + m.u32 = 0; + i = 0; p = from; while (*p && i < 4) { From 730c1f617e5297836e03eecd7cc4ef296e307f13 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 12:58:55 +0300 Subject: [PATCH 40/59] Use SnapToEights() in SV_Push(). --- src/baseq2/g_phys.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/baseq2/g_phys.c b/src/baseq2/g_phys.c index 07403070a..8074f8af6 100644 --- a/src/baseq2/g_phys.c +++ b/src/baseq2/g_phys.c @@ -378,6 +378,8 @@ pushed_t pushed[MAX_EDICTS], *pushed_p; edict_t *obstacle; +float SnapToEights(float x); + /* ============ SV_Push @@ -396,15 +398,8 @@ bool SV_Push(edict_t *pusher, vec3_t move, vec3_t amove) // clamp the move to 1/8 units, so the position will // be accurate for client side prediction - for (i = 0 ; i < 3 ; i++) { - float temp; - temp = move[i] * 8.0f; - if (temp > 0.0f) - temp += 0.5f; - else - temp -= 0.5f; - move[i] = 0.125f * (int)temp; - } + for (i = 0 ; i < 3 ; i++) + move[i] = SnapToEights(move[i]); // find the bounding box for (i = 0 ; i < 3 ; i++) { From fe3b28154316beaaa88681be7a1a537c2f3541ba Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 19:24:34 +0300 Subject: [PATCH 41/59] Clear more entity state on respawn/disconnect. --- src/baseq2/p_client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index c91ba2ada..dd6343140 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1176,7 +1176,9 @@ void PutClientInServer(edict_t *ent) client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model); // clear entity state values + ent->s.sound = 0; ent->s.effects = 0; + ent->s.renderfx = 0; ent->s.modelindex = 255; // will use the skin specified model ent->s.modelindex2 = 255; // custom gun model // sknum is player num and weapon number @@ -1498,9 +1500,12 @@ void ClientDisconnect(edict_t *ent) gi.unlinkentity(ent); ent->s.modelindex = 0; + ent->s.modelindex2 = 0; ent->s.sound = 0; ent->s.event = 0; ent->s.effects = 0; + ent->s.renderfx = 0; + ent->s.solid = 0; ent->solid = SOLID_NOT; ent->inuse = false; ent->classname = "disconnected"; From 08607fdc3bdf05095ef172aacad24e7941e4b961 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 19:25:43 +0300 Subject: [PATCH 42/59] Precache more stuff. --- src/baseq2/g_items.c | 8 ++++---- src/baseq2/g_spawn.c | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_items.c b/src/baseq2/g_items.c index da9d8c555..1f79a7108 100644 --- a/src/baseq2/g_items.c +++ b/src/baseq2/g_items.c @@ -1231,7 +1231,7 @@ gitem_t itemlist[] = { WEAP_BLASTER, NULL, 0, - /* precache */ "weapons/blastf1a.wav misc/lasfly.wav" + /* precache */ "models/objects/laser/tris.md2 weapons/blastf1a.wav misc/lasfly.wav" }, /*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) @@ -1323,7 +1323,7 @@ gitem_t itemlist[] = { WEAP_CHAINGUN, NULL, 0, - /* precache */ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav" + /* precache */ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav weapons/chngnd1a.wav" }, /*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) @@ -1346,7 +1346,7 @@ gitem_t itemlist[] = { WEAP_GRENADES, NULL, AMMO_GRENADES, - /* precache */ "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav " + /* precache */ "models/objects/grenade2/tris.md2 weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav" }, /*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) @@ -1415,7 +1415,7 @@ gitem_t itemlist[] = { WEAP_HYPERBLASTER, NULL, 0, - /* precache */ "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav" + /* precache */ "models/objects/laser/tris.md2 weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav" }, /*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index 82bef2b88..f80f78407 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -915,6 +915,7 @@ void SP_worldspawn(edict_t *ent) gi.soundindex("player/lava2.wav"); gi.soundindex("misc/pc_up.wav"); + gi.soundindex("misc/talk.wav"); gi.soundindex("misc/talk1.wav"); gi.soundindex("misc/udeath.wav"); From 87ca687fcb28729bec0793454878a456c8d3f2f5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 19:26:25 +0300 Subject: [PATCH 43/59] Compress status bar whitespace. --- src/baseq2/g_spawn.c | 110 +++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index f80f78407..4894e845a 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -707,50 +707,50 @@ static const char single_statusbar[] = // ammo "if 2 " -" xv 100 " -" anum " -" xv 150 " -" pic 2 " + "xv 100 " + "anum " + "xv 150 " + "pic 2 " "endif " // armor "if 4 " -" xv 200 " -" rnum " -" xv 250 " -" pic 4 " + "xv 200 " + "rnum " + "xv 250 " + "pic 4 " "endif " // selected item "if 6 " -" xv 296 " -" pic 6 " + "xv 296 " + "pic 6 " "endif " "yb -50 " // picked up item "if 7 " -" xv 0 " -" pic 7 " -" xv 26 " -" yb -42 " -" stat_string 8 " -" yb -50 " + "xv 0 " + "pic 7 " + "xv 26 " + "yb -42 " + "stat_string 8 " + "yb -50 " "endif " // timer "if 9 " -" xv 262 " -" num 2 10 " -" xv 296 " -" pic 9 " + "xv 262 " + "num 2 10 " + "xv 296 " + "pic 9 " "endif " -// help / weapon icon +// help / weapon icon "if 11 " -" xv 148 " -" pic 11 " + "xv 148 " + "pic 11 " "endif " ; @@ -765,71 +765,71 @@ static const char dm_statusbar[] = // ammo "if 2 " -" xv 100 " -" anum " -" xv 150 " -" pic 2 " + "xv 100 " + "anum " + "xv 150 " + "pic 2 " "endif " // armor "if 4 " -" xv 200 " -" rnum " -" xv 250 " -" pic 4 " + "xv 200 " + "rnum " + "xv 250 " + "pic 4 " "endif " // selected item "if 6 " -" xv 296 " -" pic 6 " + "xv 296 " + "pic 6 " "endif " "yb -50 " // picked up item "if 7 " -" xv 0 " -" pic 7 " -" xv 26 " -" yb -42 " -" stat_string 8 " -" yb -50 " + "xv 0 " + "pic 7 " + "xv 26 " + "yb -42 " + "stat_string 8 " + "yb -50 " "endif " // timer "if 9 " -" xv 246 " -" num 2 10 " -" xv 296 " -" pic 9 " + "xv 246 " + "num 2 10 " + "xv 296 " + "pic 9 " "endif " -// help / weapon icon +// help / weapon icon "if 11 " -" xv 148 " -" pic 11 " + "xv 148 " + "pic 11 " "endif " -// frags +// frags "xr -50 " "yt 2 " "num 3 14 " // spectator "if 17 " -"xv 0 " -"yb -58 " -"string2 \"SPECTATOR MODE\" " + "xv 0 " + "yb -58 " + "string2 \"SPECTATOR MODE\" " "endif " // chase camera "if 16 " -"xv 0 " -"yb -68 " -"string \"Chasing\" " -"xv 64 " -"stat_string 16 " + "xv 0 " + "yb -68 " + "string \"Chasing\" " + "xv 64 " + "stat_string 16 " "endif " ; From 0c9368b8e37ad08d280bbe2e987a401edbe6f244 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 19:26:55 +0300 Subject: [PATCH 44/59] Don't add view bobbing while midair. --- src/baseq2/p_view.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index 45373cb5b..432515fb7 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -940,6 +940,8 @@ void ClientEndServerFrame(edict_t *ent) bobmove = 0.125f; else bobmove = 0.0625f; + } else { + bobmove = 0; } bobtime = (current_client->bobtime += bobmove); From 55d46d0e6eaf808a53ecfdca36c2f8fb33436a77 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 20:08:16 +0300 Subject: [PATCH 45/59] Simplify clamping skill level. --- src/baseq2/g_spawn.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index 4894e845a..b4a70e942 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -579,10 +579,7 @@ void SpawnEntities(const char *mapname, const char *entities, const char *spawnp float skill_level; skill_level = floor(skill->value); - if (skill_level < 0) - skill_level = 0; - if (skill_level > 3) - skill_level = 3; + clamp(skill_level, 0, 3); if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); From abf5c249d0bd8fd52aa384495cb7a624d6135851 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 20:26:54 +0300 Subject: [PATCH 46/59] Reduce status bar string duplication. --- src/baseq2/g_spawn.c | 58 +------------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index b4a70e942..5b4adb56d 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -752,62 +752,6 @@ static const char single_statusbar[] = ; static const char dm_statusbar[] = -"yb -24 " - -// health -"xv 0 " -"hnum " -"xv 50 " -"pic 0 " - -// ammo -"if 2 " - "xv 100 " - "anum " - "xv 150 " - "pic 2 " -"endif " - -// armor -"if 4 " - "xv 200 " - "rnum " - "xv 250 " - "pic 4 " -"endif " - -// selected item -"if 6 " - "xv 296 " - "pic 6 " -"endif " - -"yb -50 " - -// picked up item -"if 7 " - "xv 0 " - "pic 7 " - "xv 26 " - "yb -42 " - "stat_string 8 " - "yb -50 " -"endif " - -// timer -"if 9 " - "xv 246 " - "num 2 10 " - "xv 296 " - "pic 9 " -"endif " - -// help / weapon icon -"if 11 " - "xv 148 " - "pic 11 " -"endif " - // frags "xr -50 " "yt 2 " @@ -886,7 +830,7 @@ void SP_worldspawn(edict_t *ent) // status bar program if (deathmatch->value) - gi.configstring(CS_STATUSBAR, dm_statusbar); + gi.configstring(CS_STATUSBAR, va("%s%s", single_statusbar, dm_statusbar)); else gi.configstring(CS_STATUSBAR, single_statusbar); From 6d7a5832f0503c57a81a747088ea444b7649d3e9 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 12 Jan 2023 20:38:35 +0300 Subject: [PATCH 47/59] Add separate timers for quad/pent. --- src/baseq2/g_spawn.c | 12 +++++++++++- src/baseq2/p_hud.c | 24 +++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index 5b4adb56d..54336b3f4 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -736,7 +736,7 @@ static const char single_statusbar[] = "yb -50 " "endif " -// timer +// timer 1 (quad, enviro, breather) "if 9 " "xv 262 " "num 2 10 " @@ -744,6 +744,16 @@ static const char single_statusbar[] = "pic 9 " "endif " +// timer 2 (pent) +"if 18 " + "yb -76 " + "xv 262 " + "num 2 19 " + "xv 296 " + "pic 18 " + "yb -50 " +"endif " + // help / weapon icon "if 11 " "xv 148 " diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 3d3087703..700d579f0 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -15,9 +15,11 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "g_local.h" +#include "g_local.h" +#define STAT_TIMER2_ICON 18 +#define STAT_TIMER2 19 /* ====================================================================== @@ -423,14 +425,11 @@ void G_SetStats(edict_t *ent) } // - // timers + // timer 1 (quad, enviro, breather) // if (ent->client->quad_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_quad"); ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum) / 10; - } else if (ent->client->invincible_framenum > level.framenum) { - ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_invulnerability"); - ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum) / 10; } else if (ent->client->enviro_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_envirosuit"); ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum) / 10; @@ -442,6 +441,21 @@ void G_SetStats(edict_t *ent) ent->client->ps.stats[STAT_TIMER] = 0; } + // + // timer 2 (pent) + // + ent->client->ps.stats[STAT_TIMER2_ICON] = 0; + ent->client->ps.stats[STAT_TIMER2] = 0; + if (ent->client->invincible_framenum > level.framenum) { + if (ent->client->ps.stats[STAT_TIMER_ICON]) { + ent->client->ps.stats[STAT_TIMER2_ICON] = gi.imageindex("p_invulnerability"); + ent->client->ps.stats[STAT_TIMER2] = (ent->client->invincible_framenum - level.framenum) / 10; + } else { + ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_invulnerability"); + ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum) / 10; + } + } + // // selected item // From 12df1a6e8662682ad01d407ed67947ade44c50db Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 15 Jan 2023 15:34:08 +0300 Subject: [PATCH 48/59] Add proper suffix to floating point constants. --- src/baseq2/g_items.c | 6 +++--- src/baseq2/p_view.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/baseq2/g_items.c b/src/baseq2/g_items.c index 1f79a7108..ef30e97dd 100644 --- a/src/baseq2/g_items.c +++ b/src/baseq2/g_items.c @@ -35,9 +35,9 @@ void Weapon_Railgun(edict_t *ent); void Weapon_BFG(edict_t *ent); void Weapon_FlareGun(edict_t *ent); -gitem_armor_t jacketarmor_info = { 25, 50, .30, .00, ARMOR_JACKET}; -gitem_armor_t combatarmor_info = { 50, 100, .60, .30, ARMOR_COMBAT}; -gitem_armor_t bodyarmor_info = {100, 200, .80, .60, ARMOR_BODY}; +gitem_armor_t jacketarmor_info = { 25, 50, .30f, .00f, ARMOR_JACKET}; +gitem_armor_t combatarmor_info = { 50, 100, .60f, .30f, ARMOR_COMBAT}; +gitem_armor_t bodyarmor_info = {100, 200, .80f, .60f, ARMOR_BODY}; static int jacket_armor_index; static int combat_armor_index; diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index 432515fb7..6f3823b04 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -73,9 +73,9 @@ void P_DamageFeedback(edict_t *player) float realcount, count, kick; vec3_t v; int r, l; - static vec3_t power_color = {0.0, 1.0, 0.0}; - static vec3_t acolor = {1.0, 1.0, 1.0}; - static vec3_t bcolor = {1.0, 0.0, 0.0}; + static vec3_t power_color = {0, 1, 0}; + static vec3_t acolor = {1, 1, 1}; + static vec3_t bcolor = {1, 0, 0}; client = player->client; From 3180a42817b9bf23ff7e5ab336e18efaf015161f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 15 Jan 2023 15:34:31 +0300 Subject: [PATCH 49/59] Add missing else keyword. --- src/baseq2/g_items.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/g_items.c b/src/baseq2/g_items.c index ef30e97dd..82d690310 100644 --- a/src/baseq2/g_items.c +++ b/src/baseq2/g_items.c @@ -982,7 +982,7 @@ void PrecacheItem(gitem_t *it) gi.modelindex(data); else if (!strcmp(data + len - 3, "wav")) gi.soundindex(data); - if (!strcmp(data + len - 3, "pcx")) + else if (!strcmp(data + len - 3, "pcx")) gi.imageindex(data); } } From 5dd961290af91d0feea0f77e6298d6d2b523eda7 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 16 Jan 2023 13:20:18 +0300 Subject: [PATCH 50/59] Add workaround for bugged map. tech5 has a func_train that teleports into starting position after player has spawned, killing the player if spawned too low. --- src/baseq2/p_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index dd6343140..1347bda8b 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1192,7 +1192,7 @@ void PutClientInServer(edict_t *ent) temp[2] -= 64; temp2[2] += 16; tr = gi.trace(temp2, ent->mins, ent->maxs, temp, ent, MASK_PLAYERSOLID); - if (!tr.allsolid && !tr.startsolid) { + if (!tr.allsolid && !tr.startsolid && Q_stricmp(level.mapname, "tech5")) { VectorCopy(tr.endpos, ent->s.origin); ent->groundentity = tr.ent; } else { From 39396b73daa30dbea45109e8a57e6b858eff05a1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 11 Mar 2023 00:23:32 +0300 Subject: [PATCH 51/59] Fix out of array access. --- src/baseq2/p_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 700d579f0..498800ff6 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -105,7 +105,7 @@ void BeginIntermission(edict_t *targ) if (!client->inuse) continue; // strip players of all keys between units - for (n = 0; n < MAX_ITEMS; n++) { + for (n = 0; n < game.num_items; n++) { if (itemlist[n].flags & IT_KEY) client->client->pers.inventory[n] = 0; } From 05e507c021ec2be5ff6d1a2bad9f95bbcacbbad3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 11 Mar 2023 00:55:36 +0300 Subject: [PATCH 52/59] Fix player skin reset after map change in SP. --- src/baseq2/p_client.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 1347bda8b..3c1b4da83 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1077,6 +1077,7 @@ a deathmatch. */ void PutClientInServer(edict_t *ent) { + char userinfo[MAX_INFO_STRING]; vec3_t mins = { -16, -16, -24}; vec3_t maxs = {16, 16, 32}; int index; @@ -1096,20 +1097,16 @@ void PutClientInServer(edict_t *ent) index = ent - g_edicts - 1; client = ent->client; + memcpy(userinfo, client->pers.userinfo, sizeof(userinfo)); + // deathmatch wipes most client data every spawn if (deathmatch->value) { - char userinfo[MAX_INFO_STRING]; - resp = client->resp; - memcpy(userinfo, client->pers.userinfo, sizeof(userinfo)); InitClientPersistant(client); - ClientUserinfoChanged(ent, userinfo); } else { // int n; - char userinfo[MAX_INFO_STRING]; resp = client->resp; - memcpy(userinfo, client->pers.userinfo, sizeof(userinfo)); // this is kind of ugly, but it's how we want to handle keys in coop // for (n = 0; n < game.num_items; n++) // { @@ -1119,11 +1116,12 @@ void PutClientInServer(edict_t *ent) resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged; resp.coop_respawn.helpchanged = client->pers.helpchanged; client->pers = resp.coop_respawn; - ClientUserinfoChanged(ent, userinfo); if (resp.score > client->pers.score) client->pers.score = resp.score; } + ClientUserinfoChanged(ent, userinfo); + // clear everything but the persistant data saved = client->pers; memset(client, 0, sizeof(*client)); From c76948650e27918c2afe3882c6c09ddcf2082f38 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 18 Mar 2023 21:15:28 +0300 Subject: [PATCH 53/59] Precache more sounds. --- src/baseq2/g_spawn.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index 54336b3f4..975add138 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -860,6 +860,11 @@ void SP_worldspawn(edict_t *ent) snd_fry = gi.soundindex("player/fry.wav"); // standing in lava / slime + gi.soundindex("player/lava_in.wav"); + gi.soundindex("player/burn1.wav"); + gi.soundindex("player/burn2.wav"); + gi.soundindex("player/drown1.wav"); + PrecacheItem(FindItem("Blaster")); gi.soundindex("player/lava1.wav"); From 9aa4ecfed525d56bad0dddc9b776b1db8d9a1d7d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 31 Mar 2023 20:15:34 +0300 Subject: [PATCH 54/59] Remove power cubes at end of unit. --- src/baseq2/p_hud.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/baseq2/p_hud.c b/src/baseq2/p_hud.c index 498800ff6..271b2dc5f 100644 --- a/src/baseq2/p_hud.c +++ b/src/baseq2/p_hud.c @@ -109,6 +109,7 @@ void BeginIntermission(edict_t *targ) if (itemlist[n].flags & IT_KEY) client->client->pers.inventory[n] = 0; } + client->client->pers.power_cubes = 0; } } } else { From 20945f91db982690b73d08463b22c6dfa46f6049 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 18 Aug 2023 12:33:38 +0300 Subject: [PATCH 55/59] Simplify velocity clamping. --- src/baseq2/g_misc.c | 15 +++------------ src/baseq2/g_phys.c | 12 ++++-------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/baseq2/g_misc.c b/src/baseq2/g_misc.c index 1d1ed8264..0a6543091 100644 --- a/src/baseq2/g_misc.c +++ b/src/baseq2/g_misc.c @@ -67,18 +67,9 @@ void VelocityForDamage(int damage, vec3_t v) void ClipGibVelocity(edict_t *ent) { - if (ent->velocity[0] < -300) - ent->velocity[0] = -300; - else if (ent->velocity[0] > 300) - ent->velocity[0] = 300; - if (ent->velocity[1] < -300) - ent->velocity[1] = -300; - else if (ent->velocity[1] > 300) - ent->velocity[1] = 300; - if (ent->velocity[2] < 200) - ent->velocity[2] = 200; // always some upwards - else if (ent->velocity[2] > 500) - ent->velocity[2] = 500; + clamp(ent->velocity[0], -300, 300); + clamp(ent->velocity[1], -300, 300); + clamp(ent->velocity[2], 200, 500); // always some upwards } diff --git a/src/baseq2/g_phys.c b/src/baseq2/g_phys.c index 8074f8af6..428f376a1 100644 --- a/src/baseq2/g_phys.c +++ b/src/baseq2/g_phys.c @@ -74,12 +74,8 @@ void SV_CheckVelocity(edict_t *ent) // // bound velocity // - for (i = 0 ; i < 3 ; i++) { - if (ent->velocity[i] > sv_maxvelocity->value) - ent->velocity[i] = sv_maxvelocity->value; - else if (ent->velocity[i] < -sv_maxvelocity->value) - ent->velocity[i] = -sv_maxvelocity->value; - } + for (i = 0; i < 3; i++) + clamp(ent->velocity[i], -sv_maxvelocity->value, sv_maxvelocity->value); } /* @@ -901,7 +897,7 @@ void G_RunEntity(edict_t *ent) if (ent->prethink) ent->prethink(ent); - switch ((int)ent->movetype) { + switch (ent->movetype) { case MOVETYPE_PUSH: case MOVETYPE_STOP: SV_Physics_Pusher(ent); @@ -922,6 +918,6 @@ void G_RunEntity(edict_t *ent) SV_Physics_Toss(ent); break; default: - gi.error("SV_Physics: bad movetype %i", (int)ent->movetype); + gi.error("SV_Physics: bad movetype %i", ent->movetype); } } From 1752db42471fa8237e63d90c1481c37bacb1b4b5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 3 Sep 2023 00:50:17 +0300 Subject: [PATCH 56/59] Use vtos() where appropriate. --- src/baseq2/g_monster.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/baseq2/g_monster.c b/src/baseq2/g_monster.c index 2bbcffba7..da8ce9374 100644 --- a/src/baseq2/g_monster.c +++ b/src/baseq2/g_monster.c @@ -574,10 +574,9 @@ void monster_start_go(edict_t *self) target = NULL; while ((target = G_Find(target, FOFS(targetname), self->combattarget)) != NULL) { if (strcmp(target->classname, "point_combat") != 0) { - gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n", - self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2], - self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1], - (int)target->s.origin[2]); + gi.dprintf("%s at %s has a bad combattarget %s : %s at %s\n", + self->classname, vtos(self->s.origin), + self->combattarget, target->classname, vtos(target->s.origin)); } } } From c34b1ddb27665d5338566447b7d00e302a952890 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 4 Sep 2023 14:20:46 +0300 Subject: [PATCH 57/59] Remove unused code. --- src/baseq2/p_client.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 3c1b4da83..1de7a89f9 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1529,23 +1529,6 @@ trace_t q_gameabi PM_trace(const vec3_t start, const vec3_t mins, const vec3_t m return gi.trace(start, mins, maxs, end, pm_passent, MASK_DEADSOLID); } -unsigned CheckBlock(void *b, int c) -{ - int v, i; - v = 0; - for (i = 0 ; i < c ; i++) - v += ((byte *)b)[i]; - return v; -} -void PrintPmove(pmove_t *pm) -{ - unsigned c1, c2; - - c1 = CheckBlock(&pm->s, sizeof(pm->s)); - c2 = CheckBlock(&pm->cmd, sizeof(pm->cmd)); - Com_Printf("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2); -} - /* ============== ClientThink From 592e6d0ad1f495f30aea6c294e754b9884bd72db Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 4 Sep 2023 14:26:46 +0300 Subject: [PATCH 58/59] Remove commented out AI debug prints. --- src/baseq2/g_ai.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/baseq2/g_ai.c b/src/baseq2/g_ai.c index 8fca12e4b..2a1beddb6 100644 --- a/src/baseq2/g_ai.c +++ b/src/baseq2/g_ai.c @@ -860,8 +860,6 @@ void ai_run(edict_t *self, float dist) } if (enemy_vis) { -// if (self.aiflags & AI_LOST_SIGHT) -// dprint("regained sight\n"); M_MoveToGoal(self, dist); self->monsterinfo.aiflags &= ~AI_LOST_SIGHT; VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting); @@ -879,7 +877,6 @@ void ai_run(edict_t *self, float dist) if ((self->monsterinfo.search_framenum) && (level.framenum > (self->monsterinfo.search_framenum + 20 * BASE_FRAMERATE))) { M_MoveToGoal(self, dist); self->monsterinfo.search_framenum = 0; -// dprint("search timeout\n"); return; } @@ -891,7 +888,6 @@ void ai_run(edict_t *self, float dist) if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT)) { // just lost sight of the player, decide where to go first -// dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n"); self->monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN); self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP); new = true; @@ -899,13 +895,11 @@ void ai_run(edict_t *self, float dist) if (self->monsterinfo.aiflags & AI_PURSUE_NEXT) { self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT; -// dprint("reached current goal: "); dprint(vtos(self.origin)); dprint(" "); dprint(vtos(self.last_sighting)); dprint(" "); dprint(ftos(vlen(self.origin - self.last_sighting))); dprint("\n"); // give ourself more time since we got this far self->monsterinfo.search_framenum = level.framenum + 5 * BASE_FRAMERATE; if (self->monsterinfo.aiflags & AI_PURSUE_TEMP) { -// dprint("was temp goal; retrying original\n"); self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP; marker = NULL; VectorCopy(self->monsterinfo.saved_goal, self->monsterinfo.last_sighting); @@ -921,9 +915,6 @@ void ai_run(edict_t *self, float dist) VectorCopy(marker->s.origin, self->monsterinfo.last_sighting); self->monsterinfo.trail_framenum = marker->timestamp; self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW]; -// dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n"); - -// debug_drawline(self.origin, self.last_sighting, 52); new = true; } } @@ -938,8 +929,6 @@ void ai_run(edict_t *self, float dist) VectorCopy(self->monsterinfo.last_sighting, self->goalentity->s.origin); if (new) { -// gi.dprintf("checking for course correction\n"); - tr = gi.trace(self->s.origin, self->mins, self->maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID); if (tr.fraction < 1) { VectorSubtract(self->goalentity->s.origin, self->s.origin, v); @@ -964,7 +953,6 @@ void ai_run(edict_t *self, float dist) if (left < 1) { VectorSet(v, d2 * left * 0.5f, -16, 0); G_ProjectSource(self->s.origin, v, v_forward, v_right, left_target); -// gi.dprintf("incomplete path, go part way and adjust again\n"); } VectorCopy(self->monsterinfo.last_sighting, self->monsterinfo.saved_goal); self->monsterinfo.aiflags |= AI_PURSUE_TEMP; @@ -972,13 +960,10 @@ void ai_run(edict_t *self, float dist) VectorCopy(left_target, self->monsterinfo.last_sighting); VectorSubtract(self->goalentity->s.origin, self->s.origin, v); self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v); -// gi.dprintf("adjusted left\n"); -// debug_drawline(self.origin, self.last_sighting, 152); } else if (right >= center && right > left) { if (right < 1) { VectorSet(v, d2 * right * 0.5f, 16, 0); G_ProjectSource(self->s.origin, v, v_forward, v_right, right_target); -// gi.dprintf("incomplete path, go part way and adjust again\n"); } VectorCopy(self->monsterinfo.last_sighting, self->monsterinfo.saved_goal); self->monsterinfo.aiflags |= AI_PURSUE_TEMP; @@ -986,11 +971,8 @@ void ai_run(edict_t *self, float dist) VectorCopy(right_target, self->monsterinfo.last_sighting); VectorSubtract(self->goalentity->s.origin, self->s.origin, v); self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v); -// gi.dprintf("adjusted right\n"); -// debug_drawline(self.origin, self.last_sighting, 152); } } -// else gi.dprintf("course was fine\n"); } M_MoveToGoal(self, dist); From aefb270bd9080f14a45346f83dd85dc57a951a4e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 4 Sep 2023 22:06:19 +0300 Subject: [PATCH 59/59] Fix RF_BEAM entities that are not lasers. RF_BEAM entities that don't update their old_origin each frame were broken. --- src/baseq2/g_main.c | 3 ++- src/server/world.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index 94ccf2fdc..c1491aff4 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -504,7 +504,8 @@ void G_RunFrame(void) level.current_entity = ent; - VectorCopy(ent->s.origin, ent->s.old_origin); + if (!(ent->s.renderfx & RF_BEAM)) + VectorCopy(ent->s.origin, ent->s.old_origin); // if the ground entity moved, make sure we are still on it if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount)) { diff --git a/src/server/world.c b/src/server/world.c index f9cd67e30..ba7ffe283 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -284,7 +284,8 @@ void PF_LinkEdict(edict_t *ent) // if first time, make sure old_origin is valid if (!ent->linkcount) { - VectorCopy(ent->s.origin, ent->s.old_origin); + if (!(ent->s.renderfx & RF_BEAM)) + VectorCopy(ent->s.origin, ent->s.old_origin); #if USE_FPS VectorCopy(ent->s.origin, sent->create_origin); sent->create_framenum = sv.framenum;