Merge branch 'ironman' into 'master'

HOSTCODE 'ironman'

See merge request KartKrew/Kart!745
This commit is contained in:
Oni 2022-11-26 11:56:11 +00:00
commit dbb548d8ad
26 changed files with 1228 additions and 518 deletions

View file

@ -2550,6 +2550,9 @@ void CL_ClearPlayer(INT32 playernum)
memset(&players[playernum], 0, sizeof (player_t));
players[playernum].followerskin = -1; // don't have a ghost follower
players[playernum].fakeskin = players[playernum].lastfakeskin = MAXSKINS; // don't avoid eggman
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}

View file

@ -35,8 +35,8 @@
// Extra abilities/settings for skins (combinable stuff)
typedef enum
{
SF_HIRES = 1, // Draw the sprite at different size?
SF_MACHINE = 1<<1, // Beep boop. Are you a robot?
SF_MACHINE = 1, // Beep boop. Are you a robot?
SF_IRONMAN = 1<<1, // Pick a new skin during POSITION. I main Random!
// free up to and including 1<<31
} skinflags_t;
@ -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
@ -385,6 +387,9 @@ typedef struct player_s
INT32 skin;
UINT32 availabilities;
UINT8 fakeskin; // ironman
UINT8 lastfakeskin;
UINT8 kartspeed; // Kart speed stat between 1 and 9
UINT8 kartweight; // Kart weight stat between 1 and 9

View file

@ -3282,6 +3282,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
//"S_ITEMCAPSULE_BOTTOM",
//"S_ITEMCAPSULE_INSIDE",
"S_MAGICIANBOX",
"S_MAGICIANBOXTOP",
"S_MAGICIANBOXBOTTOM",
// Signpost sparkles
"S_SIGNSPARK1",
"S_SIGNSPARK2",
@ -5284,6 +5288,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_FLOATINGITEM",
"MT_ITEMCAPSULE",
"MT_ITEMCAPSULE_PART",
"MT_MAGICIANBOX",
"MT_SIGNSPARKLE",
@ -6323,8 +6328,8 @@ struct int_const_s const INT_CONST[] = {
{"CR_ZOOMTUBE",CR_ZOOMTUBE},
// Character flags (skinflags_t)
{"SF_HIRES",SF_HIRES},
{"SF_MACHINE",SF_MACHINE},
{"SF_IRONMAN",SF_IRONMAN},
// Sound flags
{"SF_TOTALLYSINGLE",SF_TOTALLYSINGLE},
@ -6691,6 +6696,7 @@ struct int_const_s const INT_CONST[] = {
{"V_OVERLAY",V_OVERLAY},
{"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE},
{"V_FLIP",V_FLIP},
{"V_VFLIP",V_VFLIP},
{"V_SNAPTOTOP",V_SNAPTOTOP},
{"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM},
{"V_SNAPTOLEFT",V_SNAPTOLEFT},

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -2239,6 +2239,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT16 skincolor;
INT32 skin;
UINT32 availabilities;
UINT8 fakeskin;
UINT8 lastfakeskin;
tic_t jointime;
@ -2285,9 +2287,21 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
skincolor = players[player].skincolor;
skin = players[player].skin;
// SRB2kart
kartspeed = players[player].kartspeed;
kartweight = players[player].kartweight;
if (betweenmaps)
{
fakeskin = MAXSKINS;
kartspeed = skins[players[player].skin].kartspeed;
kartweight = skins[players[player].skin].kartweight;
charflags = skins[players[player].skin].flags;
}
else
{
fakeskin = players[player].fakeskin;
kartspeed = players[player].kartspeed;
kartweight = players[player].kartweight;
charflags = players[player].charflags;
}
lastfakeskin = players[player].lastfakeskin;
followerready = players[player].followerready;
followercolor = players[player].followercolor;
@ -2295,8 +2309,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
availabilities = players[player].availabilities;
charflags = players[player].charflags;
followitem = players[player].followitem;
bot = players[player].bot;
@ -2413,10 +2425,13 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
// save player config truth reborn
p->skincolor = skincolor;
p->skin = skin;
p->fakeskin = fakeskin;
p->kartspeed = kartspeed;
p->kartweight = kartweight;
//
p->charflags = charflags;
p->lastfakeskin = lastfakeskin;
p->availabilities = availabilities;
p->followitem = followitem;

View file

@ -188,7 +188,10 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
offsetx = (float)(gpatch->leftoffset) * fscalew;
// top offset
offsety = (float)(gpatch->topoffset) * fscaleh;
if (option & V_VFLIP)
offsety = (float)(gpatch->height - gpatch->topoffset) * fscaleh;
else
offsety = (float)(gpatch->topoffset) * fscaleh;
cx -= offsetx;
cy -= offsety;
@ -249,8 +252,16 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
v[2].s = v[1].s = hwrPatch->max_s;
}
v[0].t = v[1].t = 0.0f;
v[2].t = v[3].t = hwrPatch->max_t;
if (option & V_VFLIP)
{
v[0].t = v[1].t = hwrPatch->max_t;
v[2].t = v[3].t = 0.0f;
}
else
{
v[0].t = v[1].t = 0.0f;
v[2].t = v[3].t = hwrPatch->max_t;
}
flags = PF_NoDepthTest;

View file

@ -5298,7 +5298,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip ^= (1<<rot);
}
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT)
this_scale *= FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
spr_width = spritecachedinfo[lumpoff].width;

View file

@ -543,6 +543,9 @@ char sprnames[NUMSPRITES + 1][5] =
"KINF", // Invincibility flash
"INVI", // Invincibility speedlines
"ICAP", // Item capsules
"MGBX", // Heavy Magician transform box
"MGBT", // Heavy Magician transform box top
"MGBB", // Heavy Magician transform box bottom
"WIPD", // Wipeout dust trail
"DRIF", // Drift Sparks
@ -3891,6 +3894,10 @@ state_t states[NUMSTATES] =
//{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM
//{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE
{SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX
{SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP
{SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3
@ -22398,6 +22405,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_MAGICIANBOX
-1, // doomednum
S_MAGICIANBOX, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
20*FRACUNIT, // radius
20*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_SIGNSPARKLE
-1, // doomednum
S_SIGNSPARK1, // spawnstate

View file

@ -1089,6 +1089,9 @@ typedef enum sprite
SPR_KINF, // Invincibility flash
SPR_INVI, // Invincibility speedlines
SPR_ICAP, // Item capsules
SPR_MGBX, // Heavy Magician transform box
SPR_MGBT, // Heavy Magician transform box top
SPR_MGBB, // Heavy Magician transform box bottom
SPR_WIPD, // Wipeout dust trail
SPR_DRIF, // Drift Sparks
@ -4295,6 +4298,10 @@ typedef enum state
//S_ITEMCAPSULE_BOTTOM,
//S_ITEMCAPSULE_INSIDE,
S_MAGICIANBOX,
S_MAGICIANBOX_TOP,
S_MAGICIANBOX_BOTTOM,
// Signpost sparkles
S_SIGNSPARK1,
S_SIGNSPARK2,
@ -6333,6 +6340,7 @@ typedef enum mobj_type
MT_FLOATINGITEM,
MT_ITEMCAPSULE,
MT_ITEMCAPSULE_PART,
MT_MAGICIANBOX,
MT_SIGNSPARKLE,

View file

@ -1745,7 +1745,10 @@ static boolean K_drawKartPositionFaces(void)
boolean completed[MAXPLAYERS];
INT32 rankplayer[MAXPLAYERS];
INT32 bumperx, emeraldx, numplayersingame = 0;
INT32 xoff, yoff, flipflag = 0;
UINT8 workingskin;
UINT8 *colormap;
UINT32 skinflags;
ranklines = 0;
memset(completed, 0, sizeof (completed));
@ -1830,15 +1833,36 @@ 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 (skinflags & SF_IRONMAN
&& !(players[rankplayer[i]].charflags & SF_IRONMAN) )
{
flipflag = V_FLIP|V_VFLIP; // blonic flip
xoff = yoff = 16;
} else
{
flipflag = 0;
xoff = yoff = 0;
}
if (players[rankplayer[i]].mo->color)
{
colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
if ((skin_t*)players[rankplayer[i]].mo->skin)
workingskin = (skin_t*)players[rankplayer[i]].mo->skin - skins;
else
workingskin = players[rankplayer[i]].skin;
colormap = R_GetTranslationColormap(workingskin, players[rankplayer[i]].mo->color, GTC_CACHE);
if (players[rankplayer[i]].mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, players[rankplayer[i]].mo->color, GTC_CACHE);
else
colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
colormap = R_GetTranslationColormap(workingskin, players[rankplayer[i]].mo->color, GTC_CACHE);
V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, faceprefix[players[rankplayer[i]].skin][FACE_RANK], colormap);
V_DrawMappedPatch(FACE_X + xoff, Y + yoff, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT|flipflag, faceprefix[workingskin][FACE_RANK], colormap);
if (LUA_HudEnabled(hud_battlebumpers))
{

View file

@ -2717,6 +2717,47 @@ void K_SpawnBumpEffect(mobj_t *mo)
S_StartSound(mo, sfx_s3k49);
}
void K_SpawnMagicianParticles(mobj_t *mo, int spread)
{
INT32 i;
mobj_t *target = mo->target;
if (P_MobjWasRemoved(target))
target = mo;
for (i = 0; i < 16; i++)
{
fixed_t hmomentum = P_RandomRange(PR_DECORATION, spread * -1, spread) * mo->scale;
fixed_t vmomentum = P_RandomRange(PR_DECORATION, spread * -1, spread) * mo->scale;
UINT16 color = P_RandomKey(PR_DECORATION, numskincolors);
fixed_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT);
SINT8 flip = 1;
mobj_t *dust;
if (i & 1)
ang -= ANGLE_90;
else
ang += ANGLE_90;
dust = P_SpawnMobjFromMobj(mo,
FixedMul(mo->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)),
FixedMul(mo->radius, FINESINE(ang >> ANGLETOFINESHIFT)),
target->height, (i%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST
);
flip = P_MobjFlip(dust);
dust->momx = target->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT));
dust->momy = target->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT));
dust->momz = vmomentum * flip;
dust->scale = dust->scale*4;
dust->frame |= FF_SUBTRACT|FF_TRANS90;
dust->color = color;
dust->colorized = true;
}
}
static SINT8 K_GlanceAtPlayers(player_t *glancePlayer)
{
const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));

View file

@ -110,6 +110,7 @@ void K_SpawnBoostTrail(player_t *player);
void K_SpawnSparkleTrail(mobj_t *mo);
void K_SpawnWipeoutTrail(mobj_t *mo);
void K_SpawnDraftDust(mobj_t *mo);
void K_SpawnMagicianParticles(mobj_t *mo, int spread);
void K_DriftDustHandling(mobj_t *spawner);
void K_Squish(mobj_t *mo);
mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset);

View file

@ -1250,7 +1250,7 @@ static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, boolean charf
addflags ^= V_FLIP; // This sprite is left/right flipped!
}
if (skins[skin].flags & SF_HIRES)
if (skins[skin].highresscale != FRACUNIT)
{
V_DrawFixedPatch(x<<FRACBITS,
y<<FRACBITS,

View file

@ -410,6 +410,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->skin);
else if (fastcmp(field,"availabilities"))
lua_pushinteger(L, plr->availabilities);
else if (fastcmp(field,"fakeskin"))
lua_pushinteger(L, plr->fakeskin);
else if (fastcmp(field,"lastfakeskin"))
lua_pushinteger(L, plr->lastfakeskin);
else if (fastcmp(field,"score"))
lua_pushinteger(L, plr->score);
// SRB2kart
@ -575,6 +579,10 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"availabilities"))
return NOSET;
else if (fastcmp(field,"fakeskin"))
return NOSET;
else if (fastcmp(field,"lastfakeskin"))
return NOSET;
else if (fastcmp(field,"score"))
plr->score = luaL_checkinteger(L, 3);
// SRB2kart

View file

@ -46,6 +46,7 @@ typedef enum
PR_PLAYERSTARTS, // Player starts
PR_VOICES, // Player voice sounds
PR_RANDOMSKIN, // Random skin select from Heavy Magician(?)
PR_RULESCRAMBLE, // Rule scrambing events

View file

@ -7699,6 +7699,109 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|(trans << RF_TRANSSHIFT);
}
break;
case MT_MAGICIANBOX:
{
fixed_t destx, desty;
fixed_t zoff = 0;
// EV1: rotation rate
// EV2: lifetime
// cusval: responsible for disappear FX (should only happen once)
// S_MAGICANBOX: sides, starting angle is set in the spawner (SetRandomFakePlayerSkin)
// S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets
mobj->extravalue2--;
if (mobj->extravalue2 == 0)
{
P_RemoveMobj(mobj);
break;
}
else if (mobj->extravalue2 < TICRATE/3)
{
P_SetTarget(&mobj->target, NULL);
if (mobj->extravalue2 & 1)
mobj->renderflags |= RF_DONTDRAW;
else
mobj->renderflags &= ~RF_DONTDRAW;
}
else if (mobj->extravalue2 == TICRATE/3 && !P_MobjWasRemoved(mobj->target))
{
mobj->momx = mobj->target->momx;
mobj->momy = mobj->target->momy;
mobj->momz = mobj->target->momz;
if (mobj->state == &states[S_MAGICIANBOX]) // sides
P_Thrust(mobj, mobj->angle + ANGLE_90, 32*mapobjectscale);
mobj->flags &= ~MF_NOGRAVITY;
mobj->momz += 10*mapobjectscale;
if (mobj->state == &states[S_MAGICIANBOX_BOTTOM])
mobj->momz *= -1;
if (!mobj->cusval) // Some stuff should only occur once per box
return true;
S_StartSound(mobj, sfx_kc2e);
S_StartSound(mobj, sfx_s3k9f);
if (mobj->target->player->hyudorotimer)
{
P_RemoveMobj(mobj);
break;
}
else
{
K_SpawnMagicianParticles(mobj, 5);
}
return true;
}
else if (mobj->target && !P_MobjWasRemoved(mobj->target))
{
mobj->renderflags &= ~RF_DONTDRAW;
mobj->renderflags |= (mobj->target->renderflags & RF_DONTDRAW);
// NB: This depends on order of thinker execution!
// SetRandomFakePlayerSkin (r_skins.c) sets cusval on the bottom (last) side (i=5).
// This writes to the player's visibility only after every other side has ticked and inherited it.
if (mobj->cusval)
mobj->target->renderflags |= RF_DONTDRAW;
}
if (P_MobjWasRemoved(mobj->target) || !mobj->target->health || !mobj->target->player) {
mobj->extravalue2 = min(mobj->extravalue2, TICRATE/3);
return true;
}
mobj->extravalue1 += 1;
mobj->angle += ANG1*mobj->extravalue1;
mobj->scale = mobj->target->scale;
destx = mobj->target->x;
desty = mobj->target->y;
if (mobj->state == &states[S_MAGICIANBOX]) // sides
{
destx += FixedMul(mobj->radius*2, FINECOSINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT));
desty += FixedMul(mobj->radius*2, FINESINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT));
}
else if (mobj->state == &states[S_MAGICIANBOX_TOP]) // top
{
zoff = mobj->radius*4;
}
if (mobj->flags2 & MF2_AMBUSH)
{
P_SetOrigin(mobj, destx, desty, mobj->target->z + zoff);
mobj->flags2 &= ~MF2_AMBUSH;
}
else
{
P_MoveOrigin(mobj, destx, desty, mobj->target->z + zoff);
}
break;
}
case MT_LIGHTNINGSHIELD:
{
fixed_t destx, desty;

View file

@ -151,6 +151,8 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].skincolor);
WRITEINT32(save_p, players[i].skin);
WRITEUINT32(save_p, players[i].availabilities);
WRITEUINT8(save_p, players[i].fakeskin);
WRITEUINT8(save_p, players[i].lastfakeskin);
WRITEUINT32(save_p, players[i].score);
WRITESINT8(save_p, players[i].lives);
WRITESINT8(save_p, players[i].xtralife);
@ -470,6 +472,8 @@ static void P_NetUnArchivePlayers(void)
players[i].skincolor = READUINT8(save_p);
players[i].skin = READINT32(save_p);
players[i].availabilities = READUINT32(save_p);
players[i].fakeskin = READUINT8(save_p);
players[i].lastfakeskin = READUINT8(save_p);
players[i].score = READUINT32(save_p);
players[i].lives = READSINT8(save_p);
players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter

View file

@ -1928,6 +1928,17 @@ static void K_HandleLapIncrement(player_t *player)
P_DoPlayerExit(player);
P_SetupSignExit(player);
}
else
{
UINT32 skinflags = (demo.playback)
? demo.skinlist[demo.currentskinid[(player-players)]].flags
: skins[player->skin].flags;
if (skinflags & SF_IRONMAN)
{
SetRandomFakePlayerSkin(player, true);
}
}
if (player->laps > player->latestlap)
{

View file

@ -1264,6 +1264,8 @@ void P_DoPlayerExit(player_t *player)
if (!player->spectator)
{
ClearFakePlayerSkin(player);
if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow
{
K_KartUpdatePosition(player);
@ -4167,6 +4169,35 @@ void P_PlayerThink(player_t *player)
{
player->stairjank--;
}
// Random skin / "ironman"
{
UINT32 skinflags = (demo.playback)
? demo.skinlist[demo.currentskinid[playeri]].flags
: skins[player->skin].flags;
if (skinflags & SF_IRONMAN) // we are Heavy Magician
{
if (player->charflags & SF_IRONMAN) // no fakeskin yet
{
if (leveltime >= starttime && !player->exiting)
{
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);
}
}
}
K_KartPlayerThink(player, cmd); // SRB2kart

View file

@ -27,6 +27,8 @@
#include "p_local.h"
#include "dehacked.h" // get_number (for thok)
#include "m_cond.h"
#include "k_kart.h"
#include "m_random.h"
#if 0
#include "k_kart.h" // K_KartResetPlayerColor
#endif
@ -334,6 +336,136 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
SetPlayerSkinByNum(playernum, 0); // not found, put in the default skin
}
// Set mo skin but not player_t skin, for ironman
void SetFakePlayerSkin(player_t* player, INT32 skinid)
{
if (player->fakeskin != skinid)
{
if (player->fakeskin != MAXSKINS)
player->lastfakeskin = player->fakeskin;
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;
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);
if (player->mo)
{
S_StartSound(player->mo, sfx_kc33);
S_StartSound(player->mo, sfx_cdfm44);
mobj_t *parent = player->mo;
fixed_t baseangle = P_RandomRange(PR_DECORATION, 0, 359);
INT32 j;
for (j = 0; j < 6; j++) // 0-3 = sides, 4 = top, 5 = bottom
{
mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX);
P_SetTarget(&box->target, parent);
box->angle = FixedAngle((baseangle + j*90) * FRACUNIT);
box->flags2 |= MF2_AMBUSH;
if (fast)
{
box->extravalue1 = 10; // Rotation rate
box->extravalue2 = 5*TICRATE/4; // Lifetime
}
else
{
box->extravalue1 = 1;
box->extravalue2 = 3*TICRATE/2;
}
// cusval controls behavior that should run only once, like disappear FX and RF_DONTDRAW handling.
// NB: Order of thinker execution matters here!
// We want the other sides to inherit the player's "existing" RF_DONTDRAW before the last side writes to it.
// See the MT_MAGICIANBOX thinker in p_mobj.c.
if (j == 5)
box->cusval = 1;
else
box->cusval = 0;
if (j > 3)
{
P_SetMobjState(box, (j == 4) ? S_MAGICIANBOX_TOP : S_MAGICIANBOX_BOTTOM);
box->renderflags |= RF_NOSPLATBILLBOARD;
box->angle = FixedAngle(baseangle*FRACUNIT);
}
}
K_SpawnMagicianParticles(player->mo, 10);
}
}
// Return to base skin from an SF_IRONMAN randomization
void ClearFakePlayerSkin(player_t* player)
{
UINT8 skinid;
UINT32 flags;
if (demo.playback)
{
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;
}
//
// Add skins from a pwad, each skin preceded by 'S_SKIN' marker
//
@ -482,8 +614,8 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
// parameters for individual character flags
// these are uppercase so they can be concatenated with SF_
// 1, true, yes are all valid values
GETFLAG(HIRES)
GETFLAG(MACHINE)
GETFLAG(IRONMAN)
#undef GETFLAG
else // let's check if it's a sound, otherwise error out

View file

@ -81,6 +81,9 @@ void R_InitSkins(void);
void SetPlayerSkin(INT32 playernum,const char *skinname);
void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002
void SetFakePlayerSkin(player_t* player, INT32 skinnum);
void SetRandomFakePlayerSkin(player_t* player, boolean fast);
void ClearFakePlayerSkin(player_t* player);
boolean R_SkinUsable(INT32 playernum, INT32 skinnum);
UINT32 R_GetSkinAvailabilities(void);
INT32 R_SkinAvailable(const char *name);

View file

@ -181,7 +181,7 @@ void R_DrawFloorSplat(vissprite_t *spr)
splat.height = spr->patch->height;
splat.scale = mobj->scale;
if (mobj->skin && ((skin_t *)mobj->skin)->flags & SF_HIRES)
if (mobj->skin && ((skin_t *)mobj->skin)->highresscale != FRACUNIT)
splat.scale = FixedMul(splat.scale, ((skin_t *)mobj->skin)->highresscale);
if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)

View file

@ -945,7 +945,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
frac = vis->startfrac;
windowtop = windowbottom = sprbotscreen = INT32_MAX;
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES)
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->highresscale != FRACUNIT)
this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale);
if (this_scale <= 0)
@ -1410,7 +1410,7 @@ static void R_ProjectDropShadow(
shadow->gzt = groundz + patch->height * shadowyscale / 2;
shadow->gz = shadow->gzt - patch->height * shadowyscale;
shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT)
shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale);
shadow->scalestep = 0;
shadow->shear.tan = shadowskew; // repurposed variable
@ -1797,7 +1797,7 @@ static void R_ProjectSprite(mobj_t *thing)
I_Assert(lump < max_spritelumps);
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT)
this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale);
spr_width = spritecachedinfo[lump].width;

View file

@ -619,10 +619,6 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
// So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible
// For now let's just at least give V_OFFSET the ability to support V_FLIP
// I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff
// -- Monster Iestyn 29/10/18
{
fixed_t offsetx = 0, offsety = 0;
@ -633,15 +629,17 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale);
// top offset
// TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
if (scrn & V_VFLIP)
offsety = FixedMul((patch->height - patch->topoffset)<<FRACBITS, vscale) + 1;
else
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
// Subtract the offsets from x/y positions
x -= offsetx;
y -= offsety;
}
desttop = screens[scrn&V_PARAMMASK];
desttop = screens[scrn&V_SCREENMASK];
if (!desttop)
return;
@ -700,6 +698,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
break;
}
column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS]));
while (column->topdelta != 0xff)
@ -709,17 +708,31 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
topdelta += prevdelta;
prevdelta = topdelta;
source = (const UINT8 *)(column) + 3;
dest = desttop;
if (scrn & V_FLIP)
dest = deststart + (destend - desttop);
dest = deststart + (destend - dest);
dest += FixedInt(FixedMul(topdelta<<FRACBITS,vdup))*vid.width;
for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac)
if (scrn & V_VFLIP)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
for (ofs = (column->length << FRACBITS)-1; dest < deststop && ofs >= 0; ofs -= rowfrac)
{
if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
else
{
for (ofs = 0; dest < deststop && ofs < (column->length << FRACBITS); ofs += rowfrac)
{
if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
column = (const column_t *)((const UINT8 *)column + column->length + 4);
}
}
@ -778,7 +791,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
y -= FixedMul(patch->topoffset<<FRACBITS, pscale);
x -= FixedMul(patch->leftoffset<<FRACBITS, pscale);
desttop = screens[scrn&V_PARAMMASK];
desttop = screens[scrn&V_SCREENMASK];
if (!desttop)
return;
@ -830,7 +843,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}

View file

@ -82,11 +82,14 @@ void V_CubeApply(RGBA_t *input);
#define V_GetColor(color) (pLocalPalette[color&0xFF])
#define V_GetMasterColor(color) (pMasterPalette[color&0xFF])
// Bottom 8 bits are used for parameter (screen or character)
// Bottom 8 bits are used for parameter (character)
#define V_PARAMMASK 0x000000FF
// strings/characters only
#define V_STRINGDANCE 0x00000002
// Bottom bit is used for screen (patches)
#define V_SCREENMASK 0x0000000F
#define V_STRINGDANCE 0x00000002 // (strings/characters only) funny undertale
#define V_VFLIP 0x00000010 // (patches only) Vertical flip
// flags hacked in scrn (not supported by all functions (see src))
// patch scaling uses bits 9 and 10