Merge pull request 'SRB2Kart Skin support' (#17) from skincompat into ACS2

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/17
This commit is contained in:
NepDisk 2025-01-27 06:41:52 +00:00
commit ccca144494
16 changed files with 367 additions and 124 deletions

View file

@ -12,13 +12,14 @@
/* Manually defined asset hashes
* Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets
* Last updated 2020 / 08 / 30 - Kart v1.3 - patch.kart
* updated 2025 - BlanKart Indev -
*/
#define ASSET_HASH_MAIN_PK3 "daf9a1a67b5e465c13789e96a09f7171"
#define ASSET_HASH_SRB2_SRB "c1b9577687f8a795104aef4600720ea7"
#define ASSET_HASH_GFX_KART "06f86ee16136eb8a7043b15001797034"
#define ASSET_HASH_TEXTURES_KART "abb53d56aba47c3a8cb0f764da1c8b80"
#define ASSET_HASH_CHARS_PK3 "bf014478cdda5e9208e3dea3c51f58c5"
#define ASSET_HASH_CHARS_KART "e2c428347dde52858a3dacd29fc5b964"
#define ASSET_HASH_MAPS_KART "d051e55141ba736582228c456953cd98"
#define ASSET_HASH_FOLLOWERS_PK3 "00000000000000000000000000000000"
#ifdef USE_PATCH_FILE

View file

@ -1191,7 +1191,7 @@ static void IdentifyVersion(void)
#define PATCHNAME "patch.pk3"
#define MUSICNAME "music.kart"
#define FOLLOWERSNAME "followers.pk3"
#define CHARSNAME "chars.pk3"
#define CHARSNAME "chars.kart"
#define GRAPHICSNAME "gfx.kart"
#define SOUNDSNAME "sounds.kart"
@ -1487,7 +1487,7 @@ void D_SRB2Main(void)
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAIN_PK3); // main.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_KART); // textures.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_PK3); // chars.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.pk3 -- 4 - If you touch this, make sure to touch up the majormods stuff below.
//mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_FOLLOWERS_PK3); // followers.pk3
#ifdef USE_PATCH_FILE
@ -1497,7 +1497,7 @@ void D_SRB2Main(void)
mainwads++; // main.pk3
mainwads++; // gfx.kart
mainwads++; // textures.kart
mainwads++; // chars.pk3
mainwads++; // chars.kart
mainwads++; // maps.kart
//mainwads++; // followers.pk3
#ifdef USE_PATCH_FILE

View file

@ -1422,7 +1422,7 @@ void PT_FileFragment(void)
|| !strcmp(filename, "srb2.srb")
|| !strcmp(filename, "gfx.kart")
|| !strcmp(filename, "textures.kart")
|| !strcmp(filename, "chars.pk3")
|| !strcmp(filename, "chars.kart")
|| !strcmp(filename, "maps.kart")
|| !strcmp(filename, "patch.pk3")
|| !strcmp(filename, "sounds.kart")

View file

@ -41,6 +41,8 @@ typedef enum
{
SF_HIRES = 1, // Draw the sprite at different size?
SF_MACHINE = 1<<1, // Beep boop. Are you a robot?
SF_NOGIBS = 1<<2, // Does this kart smash into pieces?
SF_OLDDEATH = 1<<3, // Kart V1 styled death animation
// free up to and including 1<<31
} skinflags_t;

View file

@ -79,6 +79,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_SIGN
0, // SPR2_XTRA
0, // SPR2_KART
};
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)

View file

@ -22,3 +22,5 @@ _(DEAD) // Dead
_(SIGN) // Finish signpost
_(XTRA) // Three Faces of Darkness
_(KART) // Extra frames from Kart skins

View file

@ -2602,7 +2602,7 @@ void K_KartMoveAnimation(player_t *player)
}
// Sliptides: drift -> lookback frames
if (abs(player->aizdriftturn) >= ANGLE_90)
if (abs(player->aizdriftturn) >= ANGLE_90 && !wadfiles[((skin_t *)player->mo->skin)->wadnum]->compatmode)
{
destGlanceDir = -(2*intsign(player->aizdriftturn));
player->glanceDir = destGlanceDir;

View file

@ -501,6 +501,69 @@ static int mobj_get(lua_State *L)
return 1;
}
#define F(x) case x - 'A':
static void frame2spr2(mobj_t *mo, UINT32 inframe)
{
UINT8 spr2, outframe = 0;
switch (inframe & FF_FRAMEMASK)
{
F('A') F('B')
spr2 = SPR2_STIN;
outframe = inframe & 1;
break;
F('C') F('D')
spr2 = SPR2_STIL;
outframe = inframe & 1;
break;
F('E') F('F')
spr2 = SPR2_STIR;
outframe = inframe & 1;
break;
F('G')
spr2 = SPR2_SLWN;
break;
F('H')
spr2 = SPR2_SLWL;
break;
F('I')
spr2 = SPR2_SLWR;
break;
F('J')
spr2 = SPR2_FSTN;
break;
F('K')
spr2 = SPR2_FSTL;
break;
F('L')
spr2 = SPR2_FSTR;
break;
F('M') F('N')
spr2 = SPR2_DRLN;
outframe = inframe & 1;
break;
F('O') F('P')
spr2 = SPR2_DRRN;
outframe = inframe & 1;
break;
F('Q')
spr2 = SPR2_SPIN;
break;
F('R')
spr2 = SPR2_KART;
break;
F('S')
spr2 = SPR2_SIGN;
break;
default:
spr2 = SPR2_KART;
outframe = inframe - 18; // not 19! frame 0 is squish
break;
}
mo->frame = (inframe & ~FF_FRAMEMASK) | outframe;
mo->sprite2 = P_GetSkinSprite2((skin_t *)mo->skin, spr2, mo->player);
}
#undef F
#define NOSET luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly.", mobj_opt[field])
#define NOSETPOS luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_Move") ", " LUA_QL("P_TryMove") ", or " LUA_QL("P_SetOrigin") ", or " LUA_QL("P_MoveOrigin") " instead.", mobj_opt[field])
static int mobj_set(lua_State *L)
@ -559,64 +622,15 @@ static int mobj_set(lua_State *L)
mo->rollangle = luaL_checkangle(L, 3);
break;
case mobj_sprite:
mo->sprite = luaL_checkinteger(L, 3);
if (mo->sprite == SPR_PLAY)
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_STIN, mo->player);
spritenum_t newsprite = luaL_checkinteger(L, 3);
if (lua_compatmode && mo->sprite != SPR_PLAY && newsprite == SPR_PLAY)
frame2spr2(mo, mo->frame);
mo->sprite = newsprite;
break;
case mobj_frame:
// Check for SPR2
if (mo->sprite == SPR_PLAY)
{
UINT32 frame = (UINT32)luaL_checkinteger(L, 3);
switch (frame)
{
case 0:
case 1:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_STIN, mo->player);
break;
case 2:
case 3:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_STIL, mo->player);
break;
case 4:
case 5:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_STIR, mo->player);
break;
case 6:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_SLWN, mo->player);
break;
case 7:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_SLWL, mo->player);
break;
case 8:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_SLWR, mo->player);
break;
case 9:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_FSTN, mo->player);
break;
case 10:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_FSTL, mo->player);
break;
case 11:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_FSTR, mo->player);
break;
case 12:
case 13:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_DRLN, mo->player);
break;
case 14:
case 15:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_DRRN, mo->player);
break;
case 16:
case 17: // squish technically doesnt really exist
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_SPIN, mo->player);
break;
case 18:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), SPR2_SIGN, mo->player);
break;
}
}
if (lua_compatmode && mo->sprite == SPR_PLAY)
frame2spr2(mo, (UINT32)luaL_checkinteger(L, 3));
else
mo->frame = (UINT32)luaL_checkinteger(L, 3);
break;

View file

@ -1394,76 +1394,84 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->fuse = 2*TICRATE; // timer before mobj disappears from view (even if not an actual player)
target->momx = target->momy = target->momz = 0;
angle_t playerFlingAngle;
angle_t kartFlingAngle;
if (source && !P_MobjWasRemoved(source))
if (target->player && !(skins[target->player->skin].flags & SF_NOGIBS))
{
playerFlingAngle = kartFlingAngle = R_PointToAngle2(
source->x - source->momx, source->y - source->momy,
target->x, target->y
);
}
else
{
kartFlingAngle = target->angle;
angle_t playerFlingAngle;
angle_t kartFlingAngle;
if (P_RandomByte() & 1)
if (source && !P_MobjWasRemoved(source))
{
kartFlingAngle -= ANGLE_45;
playerFlingAngle = kartFlingAngle = R_PointToAngle2(
source->x - source->momx, source->y - source->momy,
target->x, target->y
);
}
else
{
kartFlingAngle += ANGLE_45;
kartFlingAngle = target->angle;
if (P_RandomByte() & 1)
{
kartFlingAngle -= ANGLE_45;
}
else
{
kartFlingAngle += ANGLE_45;
}
playerFlingAngle = kartFlingAngle + ANGLE_180;
}
playerFlingAngle = kartFlingAngle + ANGLE_180;
}
// Spawn kart frame
mobj_t *kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER);
// Spawn kart frame
mobj_t *kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER);
if (kart && !P_MobjWasRemoved(kart))
{
kart->angle = target->angle;
kart->color = target->color;
kart->extravalue1 = target->player->kartweight;
kart->fuse = 2*TICRATE;
// Copy interp data
kart->old_angle = target->old_angle;
kart->old_x = target->old_x;
kart->old_y = target->old_y;
kart->old_z = target->old_z;
P_InstaThrust(kart, kartFlingAngle, 1 * kart->scale);
P_SetObjectMomZ(kart, 10*FRACUNIT, false);
const angle_t aOffset = ANGLE_22h;
UINT8 i;
angle_t tireAngle;
mobj_t *tire;
// Spawn tires
tireAngle = kartFlingAngle - ANGLE_90 - ANGLE_22h;
for (i = 0; i < 4; i++)
if (kart && !P_MobjWasRemoved(kart))
{
if (i == 2) tireAngle += ANGLE_90;
kart->angle = target->angle;
kart->color = target->color;
kart->extravalue1 = target->player->kartweight;
kart->fuse = 2*TICRATE;
tire = P_SpawnMobjFromMobj(kart, 0, 0, 0, MT_KART_TIRE);
tire->fuse = 2*TICRATE;
// Copy interp data
kart->old_angle = target->old_angle;
kart->old_x = target->old_x;
kart->old_y = target->old_y;
kart->old_z = target->old_z;
tire->angle = tireAngle;
P_InstaThrust(tire, tireAngle, 3 * tire->scale);
P_SetObjectMomZ(tire, 10*FRACUNIT, false);
P_InstaThrust(kart, kartFlingAngle, 1 * kart->scale);
P_SetObjectMomZ(kart, 10*FRACUNIT, false);
tireAngle += (aOffset * 2);
const angle_t aOffset = ANGLE_22h;
UINT8 i;
angle_t tireAngle;
mobj_t *tire;
// Spawn tires
tireAngle = kartFlingAngle - ANGLE_90 - ANGLE_22h;
for (i = 0; i < 4; i++)
{
if (i == 2) tireAngle += ANGLE_90;
tire = P_SpawnMobjFromMobj(kart, 0, 0, 0, MT_KART_TIRE);
tire->fuse = 2*TICRATE;
tire->angle = tireAngle;
P_InstaThrust(tire, tireAngle, 3 * tire->scale);
P_SetObjectMomZ(tire, 10*FRACUNIT, false);
tireAngle += (aOffset * 2);
}
}
P_InstaThrust(target, playerFlingAngle, 4 * target->scale);
P_SetObjectMomZ(target, 14*FRACUNIT, false);
}
P_InstaThrust(target, playerFlingAngle, 4 * target->scale);
P_SetObjectMomZ(target, 14*FRACUNIT, false);
if (target->player && (skins[target->player->skin].flags & SF_OLDDEATH))
{
P_SetObjectMomZ(target, 14*FRACUNIT, false);
}
P_PlayDeathSound(target);
}

View file

@ -6427,6 +6427,11 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
else // Apply gravity to fall downwards.
{
P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true);
if (mobj->player && (skins[mobj->player->skin].flags && SF_OLDDEATH))
{
mobj->player->drawangle -= ANGLE_22h;
}
}
break;
case MT_METALSONIC_RACE:

View file

@ -15,6 +15,7 @@
#include "r_fps.h"
#include "r_main.h"
#include "r_skins.h"
#include "g_game.h"
#include "i_video.h"
#include "r_plane.h"
@ -287,6 +288,9 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
if (mobj->player && mobj->player->aizdriftturn)
{
addangle += mobj->player->aizdriftturn;
if (mobj->skin && wadfiles[((skin_t *)mobj->skin)->wadnum]->compatmode)
// don't turn too much in compatmode
addangle = (INT32)addangle / 4;
}
if (mobj->state == &states[S_KART_DRIFT_L]
|| mobj->state == &states[S_KART_DRIFT_L_OUT]

View file

@ -109,6 +109,9 @@ static void Sk_SetDefaultValue(skin_t *skin)
skin->flags = 0;
strcpy(skin->realname, "Someone");
strncpy(skin->facerank, "MISSING", 9);
strncpy(skin->facewant, "MISSING", 9);
strncpy(skin->facemmap, "MISSING", 9);
skin->starttranscolor = 96;
skin->prefcolor = SKINCOLOR_GREEN;
skin->supercolor = SKINCOLOR_SUPERGOLD1;
@ -126,6 +129,8 @@ static void Sk_SetDefaultValue(skin_t *skin)
skin->soundsid[S_sfx[i].skinsound] = i;
}
static void R_IHateThatHedgehog(UINT16 wadnum);
//
// Initialize the basic skins
//
@ -148,6 +153,8 @@ void R_InitSkins(void)
for (i = 0; i < numwadfiles; i++)
{
if (i == 4) // chars.kart
R_IHateThatHedgehog((UINT16)i);
R_AddSkins((UINT16)i);
R_PatchSkins((UINT16)i);
R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps);
@ -396,6 +403,38 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
return INT16_MAX; // not found
}
#define NUMKARTFRAMES 19
#define S(f, s) { f - 'A', SPR2_##s },
static UINT8 KART_TO_SPR2[][2] = {
S('A', STIN)
S('B', STIN)
S('C', STIL)
S('D', STIL)
S('E', STIR)
S('F', STIR)
S('J', SLWN)
S('G', SLWN)
S('K', SLWL)
S('H', SLWL)
S('L', SLWR)
S('I', SLWR)
S('A', FSTN)
S('J', FSTN)
S('C', FSTL)
S('K', FSTL)
S('E', FSTR)
S('L', FSTR)
S('M', DRLN)
S('N', DRLN)
S('O', DRRN)
S('P', DRRN)
S('Q', SPIN)
S('Q', DEAD)
S('R', KART)
S('S', SIGN)
};
#undef S
static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin)
{
UINT16 newlastlump;
@ -427,20 +466,126 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
*lastlump = newlastlump; // okay, make the normal sprite set loading end there
}*/
// load all sprite sets we are aware of... for normal stuff.
for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump);
if (!wadfiles[wadnum]->compatmode)
{
// load all sprite sets we are aware of... for normal stuff.
for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump);
}
else
{
// okay, now we have to get fancy...
// first, just dump all the frames in a temporary def
size_t i;
spritedef_t *sd;
spriteframe_t *sf;
spritedef_t tmp = {};
const char *sprname = W_CheckNameForNumPwad(wadnum, *lump);
R_AddSingleSpriteDef(sprname, &tmp, wadnum, *lump, *lastlump);
if (tmp.numframes < NUMKARTFRAMES)
I_Error("R_LoadSkinSprites: too few frames for kart skin");
// now shuffle them around to fit the new SPR2 system
// iterate over KART_TO_SPR2, then add any excess frames to SPR2_KART
#define SPR2COUNT sizeof(KART_TO_SPR2)/sizeof(*KART_TO_SPR2)
for (i = 0; i < SPR2COUNT - NUMKARTFRAMES + tmp.numframes; i++)
{
boolean excess = i >= SPR2COUNT;
sf = &tmp.spriteframes[excess ? i - SPR2COUNT + NUMKARTFRAMES : KART_TO_SPR2[i][0]];
sd = &skin->sprites[excess ? SPR2_KART : KART_TO_SPR2[i][1]];
sd->spriteframes = Z_Realloc(sd->spriteframes, sizeof(*sd->spriteframes) * (sd->numframes+1), PU_STATIC, NULL);
sd->spriteframes[sd->numframes++] = *sf;
}
Z_Free(tmp.spriteframes);
#undef SPR2COUNT
// now we have to rotate the drift frames. i hate this.
sd = &skin->sprites[SPR2_DRRN];
for (i = 0; i < sd->numframes; i++)
{
sf = &sd->spriteframes[i];
if (sf->rotate != SRF_3D)
continue;
lumpnum_t lastpat = sf->lumppat[7];
size_t lastid = sf->lumpid[7];
for (int r = 7; r >= 1; r--)
{
sf->lumppat[r] = sf->lumppat[r-1];
sf->lumpid[r] = sf->lumpid[r-1];
}
sf->lumppat[0] = lastpat;
sf->lumpid[0] = lastid;
}
sd = &skin->sprites[SPR2_DRLN];
for (i = 0; i < sd->numframes; i++)
{
sf = &sd->spriteframes[i];
if (sf->rotate != SRF_3D)
continue;
lumpnum_t firstpat = sf->lumppat[0];
size_t firstid = sf->lumpid[0];
for (int r = 0; r < 8; r++)
{
sf->lumppat[r] = sf->lumppat[r+1];
sf->lumpid[r] = sf->lumpid[r+1];
}
sf->lumppat[7] = firstpat;
sf->lumpid[7] = firstid;
}
R_AddKartFaces(skin);
skin->flags |= SF_OLDDEATH|SF_NOGIBS;
}
if (skin->sprites[0].numframes == 0)
I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]);
}
#undef NUMKARTFRAMES
static void R_IHateThatHedgehog(UINT16 wadnum)
{
skin_t *skin = &skins[0];
Sk_SetDefaultValue(skin);
skin->wadnum = wadnum;
strcpy(skin->name, "sonic");
strcpy(skin->realname, "Sonic");
strcpy(skin->facerank, "PLAYRANK");
strcpy(skin->facewant, "PLAYWANT");
strcpy(skin->facemmap, "PLAYMMAP");
skin->prefcolor = SKINCOLOR_BLUE;
skin->starttranscolor = R_GetPaletteRemap(160);
skin->kartspeed = 8;
skin->kartweight = 2;
UINT16 lump = W_CheckNumForNamePwad("S_START", wadnum, 0);
if (lump == INT16_MAX)
I_Error("R_IHateThatHedgehog: could not find the hedgehog");
R_LoadSkinSprites(wadnum, &lump, &(UINT16){}, skin);
#ifdef SKINVALUES
skin_cons_t[0].value = 0;
skin_cons_t[0].strvalue = skin->name;
#endif
Forceskin_cons_t[1].value = 0;
Forceskin_cons_t[1].strvalue = skin->name;
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_AddPlayerModel(0);
#endif
numskins = (UINT8)('r'+'a'+'c'+'e'+' '+'a'+'s'+' '+'a'+' '+'r'+'i'+'n'+'g'+'!');
}
// returns whether found appropriate property
static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value, boolean compat)
{
// custom translation table
if (!stricmp(stoken, "startcolor"))
skin->starttranscolor = atoi(value);
skin->starttranscolor = compat ? R_GetPaletteRemap(atoi(value)) : atoi(value);
#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
// character type identification
@ -492,6 +637,11 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
GETFLAG(MACHINE)
#undef GETFLAG
#define GETPATCH(field) else if (compat && !stricmp(stoken, #field)) strncpy(skin->field, value, 8);
GETPATCH(facerank)
GETPATCH(facewant)
GETPATCH(facemmap)
else // let's check if it's a sound, otherwise error out
{
boolean found = false;
@ -667,7 +817,7 @@ void R_AddSkins(UINT16 wadnum)
pos++;
}
}
else if (!R_ProcessPatchableFields(skin, stoken, value))
else if (!R_ProcessPatchableFields(skin, stoken, value, wadfiles[wadnum]->compatmode))
CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
next_token:
@ -822,7 +972,7 @@ void R_PatchSkins(UINT16 wadnum)
pos++;
}
}
else if (!R_ProcessPatchableFields(skin, stoken, value))
else if (!R_ProcessPatchableFields(skin, stoken, value, wadfiles[wadnum]->compatmode))
CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
}

View file

@ -42,6 +42,7 @@ struct skin_t
skinflags_t flags;
char realname[SKINNAMESIZE+1]; // Display name for level completion.
char facerank[9], facewant[9], facemmap[9]; // Arbitrarily named patch lumps
// SRB2kart
UINT8 kartspeed;

View file

@ -249,6 +249,30 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
sprtemp[frame].flip &= ~(1<<rotation);
}
#define NUMFACES 3
static size_t KART_FACES[NUMFACES] = {
offsetof(skin_t, facerank),
offsetof(skin_t, facewant),
offsetof(skin_t, facemmap),
};
void R_AddKartFaces(skin_t *skin)
{
memset(sprtemp, 0xff, sizeof(sprtemp));
spritedef_t *sd = &skin->sprites[SPR2_XTRA];
for (size_t f = 0; f < NUMFACES; f++)
{
lumpnum_t lumpnum = W_CheckNumForName(reinterpret_cast<char *>(skin) + KART_FACES[f]); // how do you do, fellow C++ers?
if (lumpnum == LUMPERROR)
I_Error("R_AddKartFaces: missing patch %s for skin %s", reinterpret_cast<char *>(skin) + KART_FACES[f], skin->name);
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), numspritelumps++, f, 0, 0);
}
sd->numframes = NUMFACES;
sd->spriteframes = static_cast<spriteframe_t*>(Z_Realloc(sd->spriteframes, sizeof(spriteframe_t)*NUMFACES, PU_STATIC, NULL));
M_Memcpy(sd->spriteframes, sprtemp, sizeof(spriteframe_t)*NUMFACES);
}
#undef NUMFACES
// Install a single sprite, given its identifying name (4 chars)
//
// (originally part of R_AddSpriteDefs)

View file

@ -31,6 +31,7 @@ extern "C" {
#define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
void R_AddKartFaces(skin_t *skin);
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump);
//faB: find sprites in wadfile, replace existing, add new ones

View file

@ -298,10 +298,40 @@ static inline boolean CheckCompatFilename(char *filename)
return toupper(basename ? basename[1] : filename[0]) == 'K';
}
static inline boolean CheckCompatSkins(UINT16 wadnum)
{
#if 0
UINT16 skin = W_CheckNumForNamePwad("S_SKIN", wadnum, 0);
if (skin == INT16_MAX)
return false;
// valid kart skins can only have one sprname for all frames
const char *firstsprname = W_CheckNameForNumPwad(wadnum, ++skin);
int maxframe = 0;
while (true)
{
const char *sprname = W_CheckNameForNumPwad(wadnum, ++skin);
if (!sprname)
break;
if (memcmp(sprname, firstsprname, 4))
break;
maxframe = max(maxframe, sprname[4]);
}
// how many frames does this first sprite name have?
// if there's at least 19 frames, this is a valid kart skin,
// so we need compatmode to load skins from this file!
return (maxframe - 'A') >= 18;
#else
return false;
#endif
}
// try to figure out if a PK3 file needs compatmode enabled (palette remap)
static inline boolean CheckCompatZip(UINT16 wadnum)
{
if (CheckCompatFilename(wadfiles[wadnum]->filename))
if (CheckCompatFilename(wadfiles[wadnum]->filename) || CheckCompatSkins(wadnum))
return true;
// assume RR/2.2 for PK3s so basegame assets work
@ -311,7 +341,7 @@ static inline boolean CheckCompatZip(UINT16 wadnum)
// ditto, but for WADs
static inline boolean CheckCompatWad(UINT16 wadnum)
{
if (CheckCompatFilename(wadfiles[wadnum]->filename))
if (CheckCompatFilename(wadfiles[wadnum]->filename) || CheckCompatSkins(wadnum))
return true;
// assume Kart/2.1 for WADs so basegame assets work