Skip to content

Commit ad7a11a

Browse files
committed
WIPEOUT: smoother player tracking while dead
Now using trackent, which utilizes the client's built-in interpolation for spectators. Simplified spectator tracking to switch to an alive teammate when current tracking target dies.
1 parent 8ab40a7 commit ad7a11a

File tree

2 files changed

+51
-54
lines changed

2 files changed

+51
-54
lines changed

src/clan_arena.c

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,6 @@ void CA_MatchBreak(void)
366366
void track_player(gedict_t *observer)
367367
{
368368
gedict_t *player = ca_get_player(observer);
369-
vec3_t delta;
370-
float vlen;
371-
int follow_distance;
372-
int upward_distance;
373369

374370
if (player && !observer->in_play && observer->tracking_enabled)
375371
{
@@ -396,37 +392,12 @@ void track_player(gedict_t *observer)
396392
observer->track_target = player;
397393
}
398394

399-
// { spectate in 1st person
400-
follow_distance = -10;
401-
upward_distance = 0;
402-
observer->hideentity = EDICT_TO_PROG(player); // in this mode we want to hide player model for watcher's view
403-
VectorCopy(player->s.v.v_angle, observer->s.v.angles);
404-
// }
405-
406-
observer->s.v.fixangle = true; // force client v_angle (disable in 3rd person view)
407-
408-
trap_makevectors(player->s.v.angles);
409-
VectorMA(player->s.v.origin, follow_distance, g_globalvars.v_forward, observer->s.v.origin);
410-
VectorMA(observer->s.v.origin, upward_distance, g_globalvars.v_up, observer->s.v.origin);
411-
412-
// avoid positionning in walls
413-
traceline(PASSVEC3(player->s.v.origin), PASSVEC3(observer->s.v.origin), false, player);
414-
VectorCopy(g_globalvars.trace_endpos, observer->s.v.origin);
395+
// Use trackent for smooth tracking
396+
observer->trackent = NUM_FOR_EDICT(player);
397+
observer->hideentity = EDICT_TO_PROG(player); // Hide tracked player model
415398

416-
if (g_globalvars.trace_fraction == 1)
417-
{
418-
VectorCopy(g_globalvars.trace_endpos, observer->s.v.origin);
419-
VectorMA(observer->s.v.origin, 10, g_globalvars.v_forward, observer->s.v.origin);
420-
}
421-
else
422-
{
423-
VectorSubtract(g_globalvars.trace_endpos, player->s.v.origin, delta);
424-
vlen = VectorLength(delta);
425-
vlen = vlen - 40;
426-
VectorNormalize(delta);
427-
VectorScale(delta, vlen, delta);
428-
VectorAdd(player->s.v.origin, delta, observer->s.v.origin);
429-
}
399+
// Lock observer's orientation to player POV
400+
observer->s.v.movetype = MOVETYPE_LOCK;
430401

431402
// set observer's health/armor/ammo/weapon to match the player's
432403
observer->s.v.ammo_nails = player->s.v.ammo_nails;
@@ -442,17 +413,14 @@ void track_player(gedict_t *observer)
442413
observer->weaponmodel = player->weaponmodel;
443414
observer->s.v.weaponframe = player->s.v.weaponframe;
444415

445-
// smooth playing for ezq / zq
446-
observer->s.v.movetype = MOVETYPE_LOCK;
447-
448416
show_tracking_info(observer);
449417
}
450-
451-
if (!player || !observer->tracking_enabled)
418+
else
452419
{
453-
// restore movement and show racer entity
454-
observer->s.v.movetype = MOVETYPE_NOCLIP;
420+
// Clear tracking
421+
observer->trackent = 0;
455422
observer->hideentity = 0;
423+
observer->s.v.movetype = MOVETYPE_NOCLIP;
456424

457425
// set health/item values back to nothing
458426
observer->s.v.ammo_nails = 0;
@@ -641,6 +609,7 @@ void CA_PutClientInServer(void)
641609

642610
// tracking enabled by default
643611
self->tracking_enabled = 1;
612+
self->trackent = 0; // Initialize trackent for dead players
644613

645614
self->in_play = false;
646615
self->round_deaths++; //increment death count for wipeout
@@ -766,9 +735,9 @@ void CA_SendTeamInfo(gedict_t *t)
766735
break;
767736
}
768737

769-
if (t->trackent && (t->trackent == NUM_FOR_EDICT(p)))
738+
if (t->ct == ctSpec && t->trackent && (t->trackent == NUM_FOR_EDICT(p)))
770739
{
771-
continue; // we pseudo speccing such player, no point to send info about him
740+
continue; // if we're spectating the player, don't send info about him
772741
}
773742

774743
if (p->ca_ready || match_in_progress != 2) // be sure to send info if in prewar
@@ -1488,26 +1457,34 @@ void CA_player_pre_think(void)
14881457

14891458
void CA_spectator_think(void)
14901459
{
1491-
gedict_t *p;
1460+
gedict_t *target, *teammate;
1461+
int id;
14921462

1493-
p = PROG_TO_EDICT(self->s.v.goalentity); // who we are spectating
1463+
target = PROG_TO_EDICT(self->s.v.goalentity); // who we are spectating
14941464

1495-
if (p->ct == ctPlayer && !p->in_play && p->tracking_enabled)
1496-
{
1497-
// if the player you're observing is following someone else, hide the player model
1498-
self->hideentity = EDICT_TO_PROG(p->track_target);
1499-
}
1500-
else
1465+
// If spectating a dead player, switch to an alive teammate
1466+
if (target && target->ct == ctPlayer && !target->in_play)
15011467
{
1502-
self->hideentity = 0;
1468+
// Find any alive teammate
1469+
teammate = ca_find_player(world, target);
1470+
if (teammate && teammate->in_play && teammate != target)
1471+
{
1472+
// Use stuffcmd to switch the spectator to the alive teammate
1473+
if ((id = GetUserID(teammate)) > 0)
1474+
{
1475+
stuffcmd_flags(self, STUFFCMD_IGNOREINDEMO, "track %d\n", id);
1476+
}
1477+
}
15031478
}
15041479

1505-
if (p->ct == ctPlayer)
1480+
// Get the current viewing target (may have changed due to stuffcmd)
1481+
target = PROG_TO_EDICT(self->s.v.goalentity);
1482+
if (target && target->ct == ctPlayer)
15061483
{
15071484
if (match_in_progress == 2 && ra_match_fight == 2 && round_time > 2 && !ca_round_pause)
15081485
{
15091486
// any centerprint the player sees is sent to the spec
1510-
G_centerprint(self, "%s\n", p->cptext);
1487+
G_centerprint(self, "%s\n", target->cptext);
15111488
}
15121489
}
15131490
}

src/client.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2895,6 +2895,7 @@ void set_important_fields(gedict_t *p)
28952895
void ClientDisconnect(void)
28962896
{
28972897
extern void mv_stop_playback(void);
2898+
gedict_t *spec;
28982899

28992900
k_nochange = 0; // force recalculate frags scores
29002901

@@ -2909,6 +2910,25 @@ void ClientDisconnect(void)
29092910

29102911
del_from_specs_favourites(self);
29112912

2913+
// Clean up spectators tracking this player
2914+
for (spec = world; (spec = find_client(spec));)
2915+
{
2916+
if (spec->ct == ctSpec)
2917+
{
2918+
// Check if spectator is tracking the disconnecting player
2919+
if (spec->trackent == NUM_FOR_EDICT(self))
2920+
{
2921+
spec->trackent = 0;
2922+
}
2923+
2924+
// Check if spectator's goalentity is the disconnecting player
2925+
if (PROG_TO_EDICT(spec->s.v.goalentity) == self)
2926+
{
2927+
spec->s.v.goalentity = EDICT_TO_PROG(world);
2928+
}
2929+
}
2930+
}
2931+
29122932
ra_ClientDisconnect();
29132933

29142934
if (match_in_progress == 2 && self->ct == ctPlayer)

0 commit comments

Comments
 (0)