mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Skin and playerstate code in demos has been partly rewritten to support more than was previously possible.
Notable new features:
- Guaranteed native compatibility with SF_IRONMAN even with differing # of skins
- Bots (todo: can still desync midway through round)
Implementation details:
- Demo code (skins):
- Instead of writing a skin name string, and the player's kartspeed, kartweight, and charflags for each player in the initial player-interpreting loop...
- Write a skinlist of EVERY skin's name string, kartspeed, kartweight, and flags next to the file list, to be read into `demo.skinlist`.
- If the skin name isn't loaded, find the skin with (in order)
- SF_IRONMAN if your skin had SF_IRONMAN, since that's more important to signal
- the closest stats otherwise (as per previous implementation)
- Just as tolerant to stats AND the number of base skins changing between versions (the bonuschars aegis situation)
- Not tolerant to restat, but we can add a DXD or EZT later if we want to natively support that kind of mod
- In the initial loop and DXD_SKIN, just write an index that can be used for `demo.skinlist`, and store it in `demo.currentskinid[p]`
- The player's skin is now encoded as EZT_IRONMAN for ghosts (and just in case RNG sync fails for unrelated reasons)
- In the SF_IRONMAN code when demo.playback is true
- everywhere where `skins[player->skin]` is referenced instead uses an index into `demo.skinlist`
- SetRandomFakePlayerSkin uses the `demo.skinlist` to build a table to ensure exact random call parity
- Also means it no longer double rejection-samples.
- `player->fakeskin` and `lastfakeskin` are always == their original recording values, a skin id which can be used into `demo.skinlist`
- Demo code (playstate, initial player setup loop):
- Add bot flag (`DXD_PST_ISBOT`, `DEMO_BOT`)
- Add in-between-level botvars (difficulty, diffincrease, rival)
- Don't rely on `PF_WANTSTOJOIN` to activate
Additional bugfixes:
- Followerskin set to -1 in CL_ClearPlayer so a bad follower isn't recorded on player join without name and color change arriving immediately
- Accomodate new joiners in demo code even if they're not on DXD_PST_SPECTATING for one reason or another
- Demo extra file list saving is now its own function for code cleanliness
- Actually only modify players relevant to the demo at the end of G_DoPlayDemo, not all 16 by supplying and overwriting garbage values (POSSIBLE MEMORY CORRUPTION FIX, mobj_t pointer was previously dereferenced)
This commit is contained in:
parent
e65d17cd4d
commit
b8f59fd227
8 changed files with 771 additions and 499 deletions
|
|
@ -2550,6 +2550,8 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
|
||||
memset(&players[playernum], 0, sizeof (player_t));
|
||||
|
||||
players[playernum].followerskin = -1; // don't have a ghost follower
|
||||
|
||||
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -310,6 +310,8 @@ typedef struct botvars_s
|
|||
UINT8 diffincrease; // In GP: bot difficulty will increase this much next round
|
||||
boolean rival; // If true, they're the GP rival
|
||||
|
||||
// All entries above persist between rounds and must be recorded in demos
|
||||
|
||||
fixed_t rubberband; // Bot rubberband value
|
||||
UINT16 controller; // Special bot controller linedef ID
|
||||
|
||||
|
|
|
|||
1111
src/g_demo.c
1111
src/g_demo.c
File diff suppressed because it is too large
Load diff
28
src/g_demo.h
28
src/g_demo.h
|
|
@ -28,6 +28,13 @@ extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality;
|
|||
|
||||
extern tic_t demostarttime;
|
||||
|
||||
typedef struct democharlist_s {
|
||||
UINT8 mapping; // No, this isn't about levels. It maps to loaded character ID.
|
||||
UINT8 kartspeed;
|
||||
UINT8 kartweight;
|
||||
UINT32 flags;
|
||||
} democharlist_t;
|
||||
|
||||
// Publicly-accessible demo vars
|
||||
struct demovars_s {
|
||||
char titlename[65];
|
||||
|
|
@ -54,6 +61,9 @@ struct demovars_s {
|
|||
|
||||
boolean freecam;
|
||||
|
||||
UINT8 numskins;
|
||||
democharlist_t *skinlist;
|
||||
UINT8 currentskinid[MAXPLAYERS];
|
||||
};
|
||||
|
||||
extern struct demovars_s demo;
|
||||
|
|
@ -102,20 +112,18 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname);
|
|||
typedef enum
|
||||
{
|
||||
GHC_NORMAL = 0,
|
||||
GHC_SUPER,
|
||||
GHC_FIREFLOWER,
|
||||
GHC_INVINCIBLE,
|
||||
GHC_RETURNSKIN // not actually a colour
|
||||
GHC_SUPER
|
||||
} ghostcolor_t;
|
||||
|
||||
extern UINT8 demo_extradata[MAXPLAYERS];
|
||||
extern UINT8 demo_writerng;
|
||||
|
||||
#define DXD_RESPAWN 0x01 // "respawn" command in console
|
||||
#define DXD_SKIN 0x02 // skin changed
|
||||
#define DXD_NAME 0x04 // name changed
|
||||
#define DXD_COLOR 0x08 // color changed
|
||||
#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game
|
||||
#define DXD_PLAYSTATE 0x01 // state changed between playing, spectating, or not in-game
|
||||
#define DXD_RESPAWN 0x02 // "respawn" command in console
|
||||
#define DXD_SKIN 0x04 // skin changed
|
||||
#define DXD_NAME 0x08 // name changed
|
||||
#define DXD_COLOR 0x10 // color changed
|
||||
#define DXD_FOLLOWER 0x20 // follower was changed
|
||||
#define DXD_WEAPONPREF 0x40 // netsynced playsim settings were changed
|
||||
|
||||
|
|
@ -123,6 +131,8 @@ extern UINT8 demo_writerng;
|
|||
#define DXD_PST_SPECTATING 0x02
|
||||
#define DXD_PST_LEFT 0x03
|
||||
|
||||
#define DXD_PST_ISBOT 0x80 // extra flag
|
||||
|
||||
// Record/playback tics
|
||||
void G_ReadDemoExtraData(void);
|
||||
void G_WriteDemoExtraData(void);
|
||||
|
|
@ -155,6 +165,8 @@ typedef struct demoghost {
|
|||
UINT8 *buffer, *p, color;
|
||||
UINT8 fadein;
|
||||
UINT16 version;
|
||||
UINT8 numskins;
|
||||
democharlist_t *skinlist;
|
||||
mobj_t oldmo, *mo;
|
||||
struct demoghost *next;
|
||||
} demoghost;
|
||||
|
|
|
|||
10
src/k_hud.c
10
src/k_hud.c
|
|
@ -1748,6 +1748,7 @@ static boolean K_drawKartPositionFaces(void)
|
|||
INT32 xoff, yoff, flipflag = 0;
|
||||
UINT8 workingskin;
|
||||
UINT8 *colormap;
|
||||
UINT32 skinflags;
|
||||
|
||||
ranklines = 0;
|
||||
memset(completed, 0, sizeof (completed));
|
||||
|
|
@ -1832,10 +1833,13 @@ static boolean K_drawKartPositionFaces(void)
|
|||
bumperx = FACE_X+19;
|
||||
emeraldx = FACE_X+16;
|
||||
|
||||
skinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[rankplayer[i]]].flags
|
||||
: skins[players[rankplayer[i]].skin].flags;
|
||||
|
||||
// Flip SF_IRONMAN portraits, but only if they're transformed
|
||||
if (skins[players[rankplayer[i]].skin].flags & SF_IRONMAN
|
||||
&& !P_MobjWasRemoved(players[rankplayer[i]].mo)
|
||||
&& !(((skin_t*)players[rankplayer[i]].mo->skin)->flags & SF_IRONMAN) )
|
||||
if (skinflags & SF_IRONMAN
|
||||
&& !(players[rankplayer[i]].charflags & SF_IRONMAN) )
|
||||
{
|
||||
flipflag = V_FLIP|V_VFLIP; // blonic flip
|
||||
xoff = yoff = 16;
|
||||
|
|
|
|||
11
src/p_spec.c
11
src/p_spec.c
|
|
@ -1927,9 +1927,16 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
{
|
||||
P_DoPlayerExit(player);
|
||||
P_SetupSignExit(player);
|
||||
} else if (skins[player->skin].flags & SF_IRONMAN)
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRandomFakePlayerSkin(player, true);
|
||||
UINT32 skinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[(player-players)]].flags
|
||||
: skins[player->skin].flags;
|
||||
if (skinflags & SF_IRONMAN)
|
||||
{
|
||||
SetRandomFakePlayerSkin(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
32
src/p_user.c
32
src/p_user.c
|
|
@ -4171,25 +4171,31 @@ void P_PlayerThink(player_t *player)
|
|||
}
|
||||
|
||||
// Random skin / "ironman"
|
||||
if ((!P_MobjWasRemoved(player->mo)) && (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj
|
||||
{
|
||||
if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) // no fakeskin yet
|
||||
UINT32 skinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[playeri]].flags
|
||||
: skins[player->skin].flags;
|
||||
|
||||
if (skinflags & SF_IRONMAN) // we are Heavy Magician
|
||||
{
|
||||
if (leveltime >= starttime && !player->exiting)
|
||||
if (player->charflags & SF_IRONMAN) // no fakeskin yet
|
||||
{
|
||||
if (player->fakeskin != MAXSKINS)
|
||||
if (leveltime >= starttime && !player->exiting)
|
||||
{
|
||||
SetFakePlayerSkin(player, player->fakeskin);
|
||||
}
|
||||
else if (!(gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
SetRandomFakePlayerSkin(player, false);
|
||||
if (player->fakeskin != MAXSKINS)
|
||||
{
|
||||
SetFakePlayerSkin(player, player->fakeskin);
|
||||
}
|
||||
else if (!(gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
SetRandomFakePlayerSkin(player, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (player->exiting) // wearing a fakeskin, but need to display signpost postrace etc
|
||||
{
|
||||
ClearFakePlayerSkin(player);
|
||||
else if (player->exiting) // wearing a fakeskin, but need to display signpost postrace etc
|
||||
{
|
||||
ClearFakePlayerSkin(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -337,23 +337,53 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
|
|||
}
|
||||
|
||||
// Set mo skin but not player_t skin, for ironman
|
||||
void SetFakePlayerSkin(player_t* player, INT32 skinnum)
|
||||
void SetFakePlayerSkin(player_t* player, INT32 skinid)
|
||||
{
|
||||
player->mo->skin = &skins[skinnum];
|
||||
player->fakeskin = skinnum;
|
||||
player->lastfakeskin = skinnum;
|
||||
player->kartspeed = skins[skinnum].kartspeed;
|
||||
player->kartweight = skins[skinnum].kartweight;
|
||||
player->charflags = skins[skinnum].flags;
|
||||
player->fakeskin = skinid;
|
||||
|
||||
if (demo.playback)
|
||||
{
|
||||
player->kartspeed = demo.skinlist[skinid].kartspeed;
|
||||
player->kartweight = demo.skinlist[skinid].kartweight;
|
||||
player->charflags = demo.skinlist[skinid].flags;
|
||||
skinid = demo.skinlist[skinid].mapping;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->kartspeed = skins[skinid].kartspeed;
|
||||
player->kartweight = skins[skinid].kartweight;
|
||||
player->charflags = skins[skinid].flags;
|
||||
}
|
||||
|
||||
player->mo->skin = &skins[skinid];
|
||||
}
|
||||
|
||||
// Loudly rerandomize
|
||||
void SetRandomFakePlayerSkin(player_t* player, boolean fast)
|
||||
{
|
||||
INT32 i;
|
||||
do {
|
||||
i = P_RandomKey(PR_RANDOMSKIN, numskins);
|
||||
} while (skins[i].flags & SF_IRONMAN || i == player->lastfakeskin);
|
||||
UINT8 usableskins = 0, maxskinpick;
|
||||
UINT8 grabskins[MAXSKINS];
|
||||
|
||||
maxskinpick = (demo.playback ? demo.numskins : numskins);
|
||||
|
||||
for (i = 0; i < maxskinpick; i++)
|
||||
{
|
||||
if (i == player->lastfakeskin)
|
||||
continue;
|
||||
if (demo.playback)
|
||||
{
|
||||
if (demo.skinlist[i].flags & SF_IRONMAN)
|
||||
continue;
|
||||
}
|
||||
else if (skins[i].flags & SF_IRONMAN)
|
||||
continue;
|
||||
/*if (K_SkinLocked(i))
|
||||
continue;*/
|
||||
grabskins[usableskins++] = i;
|
||||
}
|
||||
|
||||
i = grabskins[P_RandomKey(PR_RANDOMSKIN, usableskins)];
|
||||
|
||||
SetFakePlayerSkin(player, i);
|
||||
|
||||
|
|
@ -407,16 +437,28 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast)
|
|||
// Return to base skin from an SF_IRONMAN randomization
|
||||
void ClearFakePlayerSkin(player_t* player)
|
||||
{
|
||||
if ((skins[player->skin].flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo))
|
||||
UINT8 skinid;
|
||||
UINT32 flags;
|
||||
|
||||
if (demo.playback)
|
||||
{
|
||||
player->mo->skin = &skins[player->skin];
|
||||
player->fakeskin = MAXSKINS;
|
||||
player->kartspeed = skins[player->skin].kartspeed;
|
||||
player->kartweight = skins[player->skin].kartweight;
|
||||
player->charflags = skins[player->skin].flags;
|
||||
skinid = demo.currentskinid[(player-players)];
|
||||
flags = demo.skinlist[skinid].flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
skinid = player->skin;
|
||||
flags = skins[player->skin].flags;
|
||||
}
|
||||
|
||||
if ((flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
SetFakePlayerSkin(player, skinid);
|
||||
S_StartSound(player->mo, sfx_s3k9f);
|
||||
K_SpawnMagicianParticles(player->mo, 5);
|
||||
}
|
||||
|
||||
player->fakeskin = MAXSKINS;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue