From fd4a7abc588e5b5ab23b79bbc87c3766ee03c57b Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Fri, 27 Dec 2024 17:26:33 +0200 Subject: [PATCH] game: sync target_camera with ReRelease Based on: https://github.com/Paril/quake2-rerelease-dll.git --- src/common/cmodels.c | 2 +- src/game/g_target.c | 220 ++++++++++++++++++++++- src/game/header/local.h | 1 + src/game/player/view.c | 9 +- src/game/savegame/tables/gamefunc_decs.h | 2 + src/game/savegame/tables/gamefunc_list.h | 2 + 6 files changed, 226 insertions(+), 10 deletions(-) diff --git a/src/common/cmodels.c b/src/common/cmodels.c index 83530cea9..9cf5c452f 100644 --- a/src/common/cmodels.c +++ b/src/common/cmodels.c @@ -174,7 +174,7 @@ Mod_DecompressVis(const byte *in, byte *out, const byte* numvisibility, int row) { int c; - if (*in && (in + 2) < numvisibility) + if (((in + 2) < numvisibility) && *in) { *out_p++ = *in++; continue; diff --git a/src/game/g_target.c b/src/game/g_target.c index 438d08252..6751de081 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -1474,12 +1474,161 @@ SP_target_earthquake(edict_t *self) /* * QUAKED target_camera (1 0 0) (-8 -8 -8) (8 8 8) - * [Sam-KEX] Creates a camera path as seen in the N64 version. + * + * Creates a camera path as seen in the N64 version. */ +static void +camera_lookat_pathtarget(edict_t* self, vec3_t origin, vec3_t* dest) +{ + if(self->pathtarget) + { + edict_t* pt = NULL; + + pt = G_Find(pt, FOFS(targetname), self->pathtarget); + if (pt) + { + float yaw, pitch, d; + vec3_t delta; + + VectorSubtract(pt->s.origin, origin, delta); + + d = delta[0] * delta[0] + delta[1] * delta[1]; + if(d == 0.0f) + { + yaw = 0.0f; + pitch = (delta[2] > 0.0f) ? 90.0f : -90.0f; + } + else + { + yaw = atan2(delta[1], delta[0]) * (180.0f / M_PI); + pitch = atan2(delta[2], sqrt(d)) * (180.0f / M_PI); + } + + (*dest)[YAW] = yaw; + (*dest)[PITCH] = -pitch; + (*dest)[ROLL] = 0; + } + } +} + +void +update_target_camera_think(edict_t *self) +{ + if (self->movetarget) + { + self->moveinfo.remaining_distance -= (self->moveinfo.move_speed * FRAMETIME) * 0.8f; + + if(self->moveinfo.remaining_distance <= 0) + { + VectorCopy(self->movetarget->s.origin, self->s.origin); + self->nextthink = level.time + self->movetarget->wait; + if (self->movetarget->target) + { + self->movetarget = G_PickTarget(self->movetarget->target); + + if (self->movetarget) + { + vec3_t diff; + + self->moveinfo.move_speed = self->movetarget->speed ? self->movetarget->speed : 55; + VectorSubtract(self->movetarget->s.origin, self->s.origin, diff); + self->moveinfo.remaining_distance = VectorNormalize(diff); + self->moveinfo.distance = self->moveinfo.remaining_distance; + } + } + else + { + self->movetarget = NULL; + } + + return; + } + else + { + vec3_t delta, newpos; + float frac; + int i; + + frac = 1.0f - (self->moveinfo.remaining_distance / self->moveinfo.distance); + + VectorSubtract(self->movetarget->s.origin, self->s.origin, delta); + VectorScale(delta, frac, delta); + + VectorAdd(self->s.origin, delta, newpos); + + camera_lookat_pathtarget(self, newpos, &level.intermission_angle); + VectorCopy(newpos, level.intermission_origin); + + /* move all clients to the intermission point */ + for (i = 0; i < game.maxclients; i++) + { + edict_t *client = g_edicts + 1 + i; + + if (!client->inuse) + { + continue; + } + + MoveClientToIntermission(client); + } + } + } + else + { + if (self->killtarget) + { + edict_t *t = NULL; + + /* destroy dummy player */ + if (self->enemy) + { + G_FreeEdict(self->enemy); + } + + level.intermissiontime = 0; + + while ((t = G_Find(t, FOFS(targetname), self->killtarget))) + { + t->use(t, self, self->activator); + } + + level.intermissiontime = level.time; + + /* end of unit requires a wait */ + if (level.changemap && !strchr(level.changemap, '*')) + { + level.exitintermission = true; + } + } + + self->think = NULL; + return; + } + + self->nextthink = level.time + FRAMETIME; +} + +void +target_camera_dummy_think(edict_t *self) +{ + /* + * bit of a hack, but this will let the dummy + * move like a player + */ + self->client = self->owner->client; + G_SetClientFrame(self, sqrtf( + self->velocity[0] * self->velocity[0] + + self->velocity[1] * self->velocity[1])); + self->client = NULL; + + self->nextthink = level.time + FRAMETIME; +} + void use_target_camera(edict_t *self, edict_t *other, edict_t *activator) { - edict_t *target; + vec3_t diff; + int i; if (!self) { @@ -1491,20 +1640,77 @@ use_target_camera(edict_t *self, edict_t *other, edict_t *activator) gi.configstring(CS_CDTRACK, va("%i", self->sounds)); } - if (!self->killtarget) + if (!self->target) { return; } - target = G_PickTarget(self->killtarget); + self->movetarget = G_PickTarget(self->target); - if (!target || !target->use) + if (!self->movetarget) { return; } - /* TODO: Fully implement target camera logic */ - target->use(target, self, activator); + level.intermissiontime = level.time; + level.exitintermission = 0; + + /* spawn fake player dummy where we were */ + if (activator->client) + { + edict_t *dummy; + + dummy = self->enemy = G_Spawn(); + dummy->owner = activator; + dummy->clipmask = activator->clipmask; + VectorCopy(activator->s.origin, dummy->s.origin); + VectorCopy(activator->s.angles, dummy->s.angles); + dummy->groundentity = activator->groundentity; + dummy->groundentity_linkcount = dummy->groundentity ? dummy->groundentity->linkcount : 0; + dummy->think = target_camera_dummy_think; + dummy->nextthink = level.time + FRAMETIME; + dummy->solid = SOLID_BBOX; + dummy->movetype = MOVETYPE_STEP; + VectorCopy(activator->mins, dummy->mins); + VectorCopy(activator->maxs, dummy->maxs); + dummy->s.modelindex = dummy->s.modelindex2 = CUSTOM_PLAYER_MODEL; + dummy->s.skinnum = activator->s.skinnum; + VectorCopy(activator->velocity, dummy->velocity); + dummy->s.renderfx = RF_MINLIGHT; + dummy->s.frame = activator->s.frame; + gi.linkentity(dummy); + } + + camera_lookat_pathtarget(self, self->s.origin, &level.intermission_angle); + VectorCopy(self->s.origin, level.intermission_origin); + + /* move all clients to the intermission point */ + for (i = 0; i < game.maxclients; i++) + { + edict_t* client = g_edicts + 1 + i; + if (!client->inuse) + { + continue; + } + + /* respawn any dead clients */ + if (client->health <= 0) + { + respawn(client); + } + + MoveClientToIntermission(client); + } + + self->activator = activator; + self->think = update_target_camera_think; + self->nextthink = level.time + self->wait; + self->moveinfo.move_speed = self->speed; + + VectorSubtract(self->movetarget->s.origin, self->s.origin, diff); + + self->moveinfo.remaining_distance = VectorNormalize(diff); + self->moveinfo.distance = self->moveinfo.remaining_distance; } void diff --git a/src/game/header/local.h b/src/game/header/local.h index 00d8207fd..1f7bc6050 100644 --- a/src/game/header/local.h +++ b/src/game/header/local.h @@ -983,6 +983,7 @@ void ServerCommand(void); qboolean SV_FilterPacket(char *from); /* p_view.c */ +void G_SetClientFrame(edict_t *ent, float speed); void ClientEndServerFrame(edict_t *ent); /* p_hud.c */ diff --git a/src/game/player/view.c b/src/game/player/view.c index a554375a6..51b91da77 100644 --- a/src/game/player/view.c +++ b/src/game/player/view.c @@ -1329,7 +1329,7 @@ G_SetClientSound(edict_t *ent) } void -G_SetClientFrame(edict_t *ent) +G_SetClientFrame(edict_t *ent, float speed) { gclient_t *client; qboolean duck, run; @@ -1344,6 +1344,11 @@ G_SetClientFrame(edict_t *ent) return; /* not in the player model */ } + if (speed) + { + xyspeed = speed; + } + client = ent->client; if (client->ps.pmove.pm_flags & PMF_DUCKED) @@ -1615,7 +1620,7 @@ ClientEndServerFrame(edict_t *ent) G_SetClientEvent(ent); G_SetClientEffects(ent); G_SetClientSound(ent); - G_SetClientFrame(ent); + G_SetClientFrame(ent, 0); VectorCopy(ent->velocity, ent->client->oldvelocity); VectorCopy(ent->client->ps.viewangles, ent->client->oldviewangles); diff --git a/src/game/savegame/tables/gamefunc_decs.h b/src/game/savegame/tables/gamefunc_decs.h index d3112635d..48a669385 100644 --- a/src/game/savegame/tables/gamefunc_decs.h +++ b/src/game/savegame/tables/gamefunc_decs.h @@ -1356,6 +1356,7 @@ extern void tarbaby_stand ( edict_t * self ) ; extern void tarbaby_touch ( edict_t * self , edict_t * other , cplane_t *plane, csurface_t *surf); extern void target_actor_touch ( edict_t * self , edict_t * other , cplane_t * plane , csurface_t * surf ) ; extern void target_anger_use ( edict_t * self , edict_t * other , edict_t * activator ) ; +extern void target_camera_dummy_think ( edict_t * self ) ; extern void target_crosslevel_target_think ( edict_t * self ) ; extern void target_earthquake_think ( edict_t * self ) ; extern void target_earthquake_use ( edict_t * self , edict_t * other , edict_t * activator ) ; @@ -1454,6 +1455,7 @@ extern void use_target_splash ( edict_t * self , edict_t * other , edict_t * act extern void use_target_steam ( edict_t * self , edict_t * other , edict_t * activator ) ; extern void use_target_soundfx ( edict_t *self, edict_t *other, edict_t *activator ) ; extern void use_target_gravity ( edict_t *self, edict_t *other, edict_t *activator ) ; +extern void update_target_camera_think ( edict_t *self); extern void update_target_soundfx ( edict_t *self); extern void vengeance_pain ( edict_t * self , edict_t * other , float kick , int damage ) ; extern void vengeance_think ( edict_t * self ) ; diff --git a/src/game/savegame/tables/gamefunc_list.h b/src/game/savegame/tables/gamefunc_list.h index b8f93a5dc..dd197964f 100644 --- a/src/game/savegame/tables/gamefunc_list.h +++ b/src/game/savegame/tables/gamefunc_list.h @@ -1351,6 +1351,7 @@ {"target_actor_touch", (byte *)target_actor_touch}, {"target_anger_use", (byte *)target_anger_use}, {"target_angle", (byte *)target_angle}, +{"target_camera_dummy_think", (byte *)target_camera_dummy_think}, {"target_crosslevel_target_think", (byte *)target_crosslevel_target_think}, {"target_earthquake_think", (byte *)target_earthquake_think}, {"target_earthquake_use", (byte *)target_earthquake_use}, @@ -1449,6 +1450,7 @@ {"use_target_splash", (byte *)use_target_splash}, {"use_target_steam", (byte *)use_target_steam}, {"use_target_gravity", (byte *)use_target_gravity}, +{"update_target_camera_think", (byte *)update_target_camera_think}, {"update_target_soundfx", (byte *)update_target_soundfx}, {"use_target_soundfx", (byte *)use_target_soundfx}, {"vengeance_pain", (byte *)vengeance_pain},