diff --git a/src/Sourcefile b/src/Sourcefile index 91851dc62..6c8cabbcd 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -113,3 +113,4 @@ k_grandprix.c k_hud.c k_terrain.c k_brightmap.c +k_director.c \ No newline at end of file diff --git a/src/k_director.c b/src/k_director.c new file mode 100644 index 000000000..685e581c9 --- /dev/null +++ b/src/k_director.c @@ -0,0 +1,169 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +/// \file k_director.c +/// \brief SRB2kart automatic spectator camera. + +#include "k_kart.h" +#include "k_respawn.h" +#include "doomdef.h" +#include "g_game.h" +#include "v_video.h" +#include "k_director.h" +#include "d_netcmd.h" +#include "p_local.h" + +#define SWITCHTIME TICRATE*5 +#define DEBOUNCETIME TICRATE*2 +#define BOREDOMTIME 3*TICRATE/2 +#define TRANSFERTIME TICRATE +#define BREAKAWAYDIST 4000 +#define CONFUSINGDIST 250 + +INT32 FindPlayerByPlace(INT32 place); +void K_UpdateDirectorPositions(void); +boolean K_CanSwitchDirector(void); +fixed_t K_GetFinishGap(INT32 leader, INT32 follower); +void K_DirectorSwitch(INT32 player); +void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source); +void K_UpdateDirector(void); + +INT32 cooldown = 0; +INT32 bored = 0; +INT32 positions[MAXPLAYERS] = {0}; +INT32 confidence[MAXPLAYERS] = {0}; + +INT32 freeze = 0; +INT32 attacker = 0; + +INT32 FindPlayerByPlace(INT32 place) +{ + INT32 playernum; + for (playernum = 0; playernum < MAXPLAYERS; ++playernum) + if (playeringame[playernum]) + { + if (players[playernum].position == place) + { + return playernum; + } + } + return -1; +} + +void K_UpdateDirectorPositions(void) { + INT32 playernum; + for (playernum = 0; playernum < MAXPLAYERS; ++playernum) + if (playeringame[playernum]) + { + if (players[playernum].position == positions[playernum]) { + confidence[playernum]++; + } + else { + confidence[playernum] = 0; + positions[playernum] = players[playernum].position; + } + } else { + positions[playernum] = 0; + confidence[playernum] = 0; + } +} + +boolean K_CanSwitchDirector(void) { + INT32 *displayplayerp = &displayplayers[0]; + if (players[*displayplayerp].trickpanel > 0) { + // CONS_Printf("NO SWITCH, panel"); + return false; + } + return cooldown >= SWITCHTIME; +} + +fixed_t K_GetFinishGap(INT32 leader, INT32 follower) { + fixed_t dista = players[follower].distancetofinish; + fixed_t distb = players[leader].distancetofinish; + if (players[follower].position < players[leader].position) { + return distb-dista; + } else { + return dista-distb; + } +} + +void K_DirectorSwitch(INT32 player) { + if (!K_CanSwitchDirector()) + return; + // CONS_Printf("SWITCHING: %s\n", player_names[player]); + G_ResetView(1, player, true); + cooldown = 0; +} + +void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source) { + if (!P_IsDisplayPlayer(player)) + return; + if (inflictor && inflictor->player) { + // CONS_Printf("INFLICTOR SET\n"); + attacker = inflictor->player-players; + freeze = TRANSFERTIME; + cooldown = SWITCHTIME; + } + if (source && source->player) { + // CONS_Printf("SOURCE SET\n"); + attacker = source->player-players; + freeze = TRANSFERTIME; + cooldown = SWITCHTIME; + } + // CONS_Printf("FOLLOW ATTACK\n"); + // CONS_Printf(M_GetText("%s attacked\n"), player_names[attacker]); +} + +void K_UpdateDirector(void) { + INT32 *displayplayerp = &displayplayers[0]; + INT32 targetposition; + + K_UpdateDirectorPositions(); + cooldown++; + + if (freeze >= 1) { + // CONS_Printf("FROZEN\n"); + if (freeze == 1) { + K_DirectorSwitch(attacker); + // CONS_Printf("ATTACKER SWITCH\n"); + } + freeze--; + return; + } + + for(targetposition = 2; targetposition < MAXPLAYERS; targetposition++) { + INT32 leader = FindPlayerByPlace(targetposition - 1); + INT32 follower = FindPlayerByPlace(targetposition); + fixed_t gap = K_GetFinishGap(leader, follower); + + /* + CONS_Printf("Eval %d GP %d CD %d FC %d DC %d\n", + targetposition, gap, cooldown, confidence[follower], confidence[*displayplayerp]); + */ + + if (gap > BREAKAWAYDIST) { + bored++; + if (bored > BOREDOMTIME) { + // CONS_Printf("BREAKAWAY, falling back to %d\n", targetposition); + continue; + } + } else if (bored > 0) { + bored--; + } + + /* + if (gap < CONFUSINGDIST && *displayplayerp == leader) { + CONS_Printf("No switch: too close\n"); + break; + } + */ + + if (*displayplayerp != follower && confidence[follower] > DEBOUNCETIME) { + K_DirectorSwitch(FindPlayerByPlace(targetposition)); + } + if (positions[*displayplayerp] != targetposition && confidence[*displayplayerp] > DEBOUNCETIME) { + K_DirectorSwitch(FindPlayerByPlace(targetposition)); + } + + break; + } +} \ No newline at end of file diff --git a/src/k_director.h b/src/k_director.h new file mode 100644 index 000000000..96701ffa7 --- /dev/null +++ b/src/k_director.h @@ -0,0 +1,7 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +/// \file k_director.h +/// \brief SRB2kart automatic spectator camera. + +void K_UpdateDirector(void); +void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source); \ No newline at end of file diff --git a/src/k_kart.c b/src/k_kart.c index b9fff95ba..6c61ab6b1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -34,6 +34,7 @@ #include "k_bot.h" #include "k_hud.h" #include "k_terrain.h" +#include "k_director.h" // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) @@ -3231,6 +3232,7 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type) { + K_DirectorFollowAttack(player, inflictor, source); (void)inflictor; (void)source; @@ -3273,6 +3275,7 @@ static void K_RemoveGrowShrink(player_t *player) void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) { + K_DirectorFollowAttack(player, inflictor, source); fixed_t gravityadjust; (void)source; @@ -3410,6 +3413,8 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A { INT32 ringburst = 10; + K_DirectorFollowAttack(player, inflictor, source); + (void)source; player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!! diff --git a/src/p_tick.c b/src/p_tick.c index 9a4baa092..a320ce5b3 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -706,6 +706,8 @@ void P_Ticker(boolean run) } } + K_UpdateDirector(); + // Always move the camera. for (i = 0; i <= r_splitscreen; i++) {