diff --git a/src/d_netcmd.c b/src/d_netcmd.c index fdb4f44f0..3bb83716c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -195,6 +195,8 @@ static CV_PossibleValue_t matchboxes_cons_t[] = {{0, "Normal"}, {1, "Mystery"}, static CV_PossibleValue_t chances_cons_t[] = {{0, "MIN"}, {9, "MAX"}, {0, NULL}}; static CV_PossibleValue_t pause_cons_t[] = {{0, "Server"}, {1, "All"}, {0, NULL}}; +consvar_t cv_showinputjoy = {"showinputjoy", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + #ifdef NETGAME_DEVMODE static consvar_t cv_fishcake = {"fishcake", "Off", CV_CALL|CV_NOSHOWHELP|CV_RESTRICT, CV_OnOff, Fishcake_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif @@ -307,6 +309,7 @@ consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, N static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Tics"}, {2, "Centiseconds"}, {3, "Mania"}, {0, NULL}}; consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display + consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; @@ -669,6 +672,7 @@ void D_RegisterClientCommands(void) // HUD CV_RegisterVar(&cv_timetic); CV_RegisterVar(&cv_itemfinder); + CV_RegisterVar(&cv_showinputjoy); // time attack ghost options are also saved to config CV_RegisterVar(&cv_ghost_bestscore); @@ -1870,6 +1874,13 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (resetplayer && !FLS) emeralds = 0; + if (modeattacking) + { + SetPlayerSkinByNum(0, cv_chooseskin.value-1); + players[0].skincolor = skins[players[0].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor, players[0].skincolor); + } + #ifdef HAVE_BLUA LUAh_MapChange(); #endif @@ -1881,16 +1892,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (timingdemo) G_DoneLevelLoad(); - if (modeattacking) - { - SetPlayerSkinByNum(0, cv_chooseskin.value-1); - players[0].skincolor = skins[players[0].skin].prefcolor; - CV_StealthSetValue(&cv_playercolor, players[0].skincolor); - - // a copy of color - if (players[0].mo) - players[0].mo->color = players[0].skincolor; - } if (metalrecording) G_BeginMetal(); if (demorecording) // Okay, level loaded, character spawned and skinned, diff --git a/src/doomstat.h b/src/doomstat.h index 18fe92086..de260ef06 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -498,6 +498,7 @@ extern boolean singletics; #include "d_clisrv.h" extern consvar_t cv_timetic; // display high resolution timer +extern consvar_t cv_showinputjoy; // display joystick in time attack extern consvar_t cv_forceskin; // force clients to use the server's skin extern consvar_t cv_downloading; // allow clients to downloading WADs. extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; diff --git a/src/g_game.c b/src/g_game.c index a6d5fd1eb..a9446714d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -248,7 +248,7 @@ static UINT8 demoflags; static UINT16 demoversion; boolean singledemo; // quit after playing a demo from cmdline boolean demo_start; // don't start playing demo right away -static boolean demosynced = true; // console warning message +boolean demosynced = true; // console warning message boolean metalrecording; // recording as metal sonic mobj_t *metalplayback; @@ -1598,6 +1598,7 @@ void G_DoLoadLevel(boolean resetplayer) // Make sure objectplace is OFF when you first start the level! OP_ResetObjectplace(); + demosynced = true; levelstarttic = gametic; // for time calculation @@ -3898,7 +3899,7 @@ char *G_BuildMapTitle(INT32 mapnum) // DEMO RECORDING // -#define DEMOVERSION 0x0009 +#define DEMOVERSION 0x000a #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -3923,10 +3924,10 @@ static ticcmd_t oldcmd; #define GZT_MOMZ 0x04 #define GZT_ANGLE 0x08 // Not used for Metal Sonic -#define GZT_SPRITE 0x10 // Animation frame -#define GZT_EXTRA 0x20 -#define GZT_NIGHTS 0x40 // NiGHTS Mode stuff! -#define GZT_SPR2 0x80 // Player animations +#define GZT_FRAME 0x10 // Animation frame +#define GZT_SPR2 0x20 // Player animations +#define GZT_EXTRA 0x40 +#define GZT_FOLLOW 0x80 // Followmobj // GZT_EXTRA flags #define EZT_THOK 0x01 // Spawned a thok object @@ -3938,6 +3939,7 @@ static ticcmd_t oldcmd; #define EZT_SCALE 0x10 // Changed size #define EZT_HIT 0x20 // Damaged a mobj #define EZT_SPRITE 0x40 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) +// spare EZT slot 0x80 static mobj_t oldmetal, oldghost; @@ -4136,9 +4138,6 @@ void G_WriteGhostTic(mobj_t *ghost) if (!(demoflags & DF_GHOST)) return; // No ghost data to write. - if (ghost->player && ghost->player->powers[pw_carry] == CR_NIGHTSMODE) // We're talking about the NiGHTS thing, not the normal platforming thing! - ziptic |= GZT_NIGHTS; - ziptic_p = demo_p++; // the ziptic, written at the end of this function #define MAXMOM (0xFFFF<<8) @@ -4192,18 +4191,18 @@ void G_WriteGhostTic(mobj_t *ghost) // Only store the 8 most relevant bits of angle // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites // and it does not affect this mode of movement at all anyway. - if (ghost->angle>>24 != oldghost.angle) + if (ghost->player && ghost->player->drawangle>>24 != oldghost.angle) { - oldghost.angle = ghost->angle>>24; + oldghost.angle = ghost->player->drawangle>>24; ziptic |= GZT_ANGLE; WRITEUINT8(demo_p,oldghost.angle); } // Store the sprite frame. - if ((ghost->frame & 0xFF) != oldghost.frame) + if ((ghost->frame & FF_FRAMEMASK) != oldghost.frame) { - oldghost.frame = (ghost->frame & 0xFF); - ziptic |= GZT_SPRITE; + oldghost.frame = (ghost->frame & FF_FRAMEMASK); + ziptic |= GZT_FRAME; WRITEUINT8(demo_p,oldghost.frame); } @@ -4248,7 +4247,7 @@ void G_WriteGhostTic(mobj_t *ghost) for (i = 0; i < ghostext.hits; i++) { mobj_t *mo = ghostext.hitlist[i]; - WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) + //WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) WRITEUINT32(demo_p,mo->type); WRITEUINT16(demo_p,(UINT16)mo->health); WRITEFIXED(demo_p,mo->x); @@ -4265,11 +4264,28 @@ void G_WriteGhostTic(mobj_t *ghost) ghostext.flags = 0; } + if (ghost->player && ghost->player->followmobj) + { + INT16 temp; + + ziptic |= GZT_FOLLOW; + + temp = (INT16)((ghost->player->followmobj->x-ghost->x)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((ghost->player->followmobj->y-ghost->y)>>8); + WRITEINT16(demo_p,temp); + temp = (INT16)((ghost->player->followmobj->z-ghost->z)>>8); + WRITEINT16(demo_p,temp); + WRITEUINT8(demo_p,ghost->player->followmobj->sprite); + WRITEUINT8(demo_p,ghost->player->followmobj->sprite2); + WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK)); + } + *ziptic_p = ziptic; // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - (13 + 9)) + if (demo_p >= demoend - (13 + 9 + 9)) { G_CheckDemoStatus(); // no more space return; @@ -4283,7 +4299,6 @@ void G_ConsGhostTic(void) UINT8 ziptic; UINT16 px,py,pz,gx,gy,gz; mobj_t *testmo; - boolean nightsfail = false; if (!demo_p || !demo_start) return; @@ -4315,23 +4330,19 @@ void G_ConsGhostTic(void) } if (ziptic & GZT_ANGLE) demo_p++; - if (ziptic & GZT_SPRITE) + if (ziptic & GZT_FRAME) demo_p++; if (ziptic & GZT_SPR2) demo_p++; - if (ziptic & GZT_NIGHTS) { - if (!testmo->player || !(testmo->player->powers[pw_carry] == CR_NIGHTSMODE)) - nightsfail = true; - } if (ziptic & GZT_EXTRA) { // But wait, there's more! - ziptic = READUINT8(demo_p); - if (ziptic & EZT_COLOR) + UINT8 xziptic = READUINT8(demo_p); + if (xziptic & EZT_COLOR) demo_p++; - if (ziptic & EZT_SCALE) + if (xziptic & EZT_SCALE) demo_p += sizeof(fixed_t); - if (ziptic & EZT_HIT) + if (xziptic & EZT_HIT) { // Resync mob damage. UINT16 i, count = READUINT16(demo_p); thinker_t *th; @@ -4345,7 +4356,7 @@ void G_ConsGhostTic(void) for (i = 0; i < count; i++) { - demo_p += 4; // reserved. + //demo_p += 4; // reserved. type = READUINT32(demo_p); health = READUINT16(demo_p); x = READFIXED(demo_p); @@ -4372,10 +4383,20 @@ void G_ConsGhostTic(void) } } } - if (ziptic & EZT_SPRITE) + if (xziptic & EZT_SPRITE) demo_p++; } + if (ziptic & GZT_FOLLOW) + { // Even more... + demo_p += sizeof(INT16); + demo_p += sizeof(INT16); + demo_p += sizeof(INT16); + demo_p++; + demo_p++; + demo_p++; + } + // Re-synchronise px = testmo->x>>FRACBITS; py = testmo->y>>FRACBITS; @@ -4384,7 +4405,7 @@ void G_ConsGhostTic(void) gy = oldghost.y>>FRACBITS; gz = oldghost.z>>FRACBITS; - if (nightsfail || px != gx || py != gy || pz != gz) + if (px != gx || py != gy || pz != gz) { if (demosynced) CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); @@ -4412,6 +4433,7 @@ void G_GhostTicker(void) { // Skip normal demo data. UINT8 ziptic = READUINT8(g->p); + UINT8 xziptic = 0; if (ziptic & ZT_FWD) g->p++; if (ziptic & ZT_SIDE) @@ -4445,8 +4467,8 @@ void G_GhostTicker(void) g->oldmo.z += g->oldmo.momz; } if (ziptic & GZT_ANGLE) - g->oldmo.angle = READUINT8(g->p)<<24; - if (ziptic & GZT_SPRITE) + g->mo->angle = READUINT8(g->p)<<24; + if (ziptic & GZT_FRAME) g->oldmo.frame = READUINT8(g->p); if (ziptic & GZT_SPR2) g->oldmo.sprite2 = READUINT8(g->p); @@ -4457,14 +4479,13 @@ void G_GhostTicker(void) g->mo->y = g->oldmo.y; g->mo->z = g->oldmo.z; P_SetThingPosition(g->mo); - g->mo->angle = g->oldmo.angle; g->mo->frame = g->oldmo.frame | tr_trans30<mo->sprite2 = g->oldmo.sprite2; if (ziptic & GZT_EXTRA) { // But wait, there's more! - ziptic = READUINT8(g->p); - if (ziptic & EZT_COLOR) + xziptic = READUINT8(g->p); + if (xziptic & EZT_COLOR) { g->color = READUINT8(g->p); switch(g->color) @@ -4482,22 +4503,22 @@ void G_GhostTicker(void) break; } } - if (ziptic & EZT_FLIP) + if (xziptic & EZT_FLIP) g->mo->eflags ^= MFE_VERTICALFLIP; - if (ziptic & EZT_SCALE) + if (xziptic & EZT_SCALE) { g->mo->destscale = READFIXED(g->p); if (g->mo->destscale != g->mo->scale) P_SetScale(g->mo, g->mo->destscale); } - if (ziptic & EZT_THOKMASK) + if (xziptic & EZT_THOKMASK) { // Let's only spawn ONE of these per frame, thanks. mobj_t *mobj; INT32 type = -1; if (g->mo->skin) { skin_t *skin = (skin_t *)g->mo->skin; - switch (ziptic & EZT_THOKMASK) + switch (xziptic & EZT_THOKMASK) { case EZT_THOK: type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; @@ -4538,7 +4559,7 @@ void G_GhostTicker(void) mobj->fuse = 8; P_SetTarget(&mobj->target, g->mo); } - if (ziptic & EZT_HIT) + if (xziptic & EZT_HIT) { // Spawn hit poofs for killing things! UINT16 i, count = READUINT16(g->p), health; UINT32 type; @@ -4547,7 +4568,7 @@ void G_GhostTicker(void) mobj_t *poof; for (i = 0; i < count; i++) { - g->p += 4; // reserved + //g->p += 4; // reserved type = READUINT32(g->p); health = READUINT16(g->p); x = READFIXED(g->p); @@ -4565,7 +4586,7 @@ void G_GhostTicker(void) P_SetMobjStateNF(poof, S_XPLD1); } } - if (ziptic & EZT_SPRITE) + if (xziptic & EZT_SPRITE) g->mo->sprite = READUINT8(g->p); } @@ -4589,6 +4610,54 @@ void G_GhostTicker(void) break; } +#define follow g->mo->tracer + if (ziptic & GZT_FOLLOW) + { // Even more... + if (!follow) + { + mobj_t *newmo = P_SpawnMobj(g->mo->x, g->mo->y, g->mo->z, MT_GHOST); + P_SetTarget(&g->mo->tracer, newmo); + P_SetTarget(&newmo->tracer, g->mo); + newmo->skin = g->mo->skin; + newmo->tics = -1; + newmo->flags2 |= MF2_LINKDRAW; + + follow->eflags = (follow->eflags & ~MFE_VERTICALFLIP)|(g->mo->eflags & MFE_VERTICALFLIP); + follow->destscale = g->mo->destscale; + if (follow->destscale != follow->scale) + P_SetScale(follow, follow->destscale); + } + else + { + if (xziptic & EZT_FLIP) + g->mo->eflags ^= MFE_VERTICALFLIP; + if (xziptic & EZT_SCALE) + { + follow->destscale = g->mo->destscale; + if (follow->destscale != follow->scale) + P_SetScale(follow, follow->destscale); + } + } + + P_UnsetThingPosition(follow); + follow->x = g->mo->x + (READINT16(g->p)<<8); + follow->y = g->mo->y + (READINT16(g->p)<<8); + follow->z = g->mo->z + (READINT16(g->p)<<8); + P_SetThingPosition(follow); + follow->sprite = READUINT8(g->p); + follow->sprite2 = READUINT8(g->p); + follow->frame = (READUINT8(g->p)) | tr_trans30<angle = g->mo->angle; + follow->color = g->mo->color; + } + else if (follow) + { + P_RemoveMobj(follow); + P_SetTarget(&follow, NULL); + } +#undef follow + // Demo ends after ghost data. if (*g->p == DEMOMARKER) { @@ -4635,8 +4704,8 @@ void G_ReadMetalTic(mobj_t *metal) oldmetal.z += oldmetal.momz; } if (ziptic & GZT_ANGLE) - oldmetal.angle = READUINT8(metal_p)<<24; - if (ziptic & GZT_SPRITE) + metal->angle = READUINT8(metal_p)<<24; + if (ziptic & GZT_FRAME) metal_p++; // Currently unused. (Metal Sonic figures out what he's doing his own damn self.) if (ziptic & GZT_SPR2) metal_p++; @@ -4651,7 +4720,6 @@ void G_ReadMetalTic(mobj_t *metal) metal->y = oldmetal.y; metal->z = oldmetal.z; P_SetThingPosition(metal); - metal->angle = oldmetal.angle; if (ziptic & GZT_EXTRA) { // But wait, there's more! @@ -4766,11 +4834,11 @@ void G_WriteMetalTic(mobj_t *metal) // Only store the 8 most relevant bits of angle // because exact values aren't too easy to discern to begin with when only 8 angles have different sprites // and it does not affect movement at all anyway. - if (metal->angle>>24 != oldmetal.angle) + if (metal->player && metal->player->drawangle>>24 != oldmetal.angle) { - oldmetal.angle = metal->angle>>24; - WRITEUINT8(demo_p,oldmetal.angle); + oldmetal.angle = metal->player->drawangle>>24; ziptic |= GZT_ANGLE; + WRITEUINT8(demo_p,oldmetal.angle); } // Metal Sonic does not need our state changes. @@ -4919,8 +4987,6 @@ void G_BeginRecording(void) demo_p += 16; // Stats - WRITEUINT8(demo_p,player->camerascale>>FRACBITS); - WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); WRITEUINT8(demo_p,player->charability); WRITEUINT8(demo_p,player->charability2); WRITEUINT8(demo_p,player->actionspd>>FRACBITS); @@ -4933,11 +4999,34 @@ void G_BeginRecording(void) WRITEUINT8(demo_p,player->acceleration); WRITEUINT8(demo_p,player->height>>FRACBITS); WRITEUINT8(demo_p,player->spinheight>>FRACBITS); + WRITEUINT8(demo_p,player->camerascale>>FRACBITS); + WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); // Trying to convert it back to % causes demo desync due to precision loss. // Don't do it. WRITEFIXED(demo_p, player->jumpfactor); + // And mobjtype_t is best with UINT32 too... + WRITEUINT32(demo_p, player->followitem); + + // Save pflag data + { + UINT8 buf = 0; + if (player->pflags & PF_FLIPCAM) + buf |= 0x01; + if (player->pflags & PF_ANALOGMODE) + buf |= 0x02; + if (player->pflags & PF_DIRECTIONCHAR) + buf |= 0x04; + if (player->pflags & PF_AUTOBRAKE) + buf |= 0x08; + if (cv_usejoystick.value) + buf |= 0x10; + CV_SetValue(&cv_showinputjoy, !!(cv_usejoystick.value)); + + WRITEUINT8(demo_p,buf); + } + // Save netvar data CV_SaveNetVars(&demo_p); @@ -4952,7 +5041,7 @@ void G_BeginRecording(void) oldghost.x = player->mo->x; oldghost.y = player->mo->y; oldghost.z = player->mo->z; - oldghost.angle = player->mo->angle; + oldghost.angle = player->mo->angle>>24; // preticker started us gravity flipped if (player->mo->eflags & MFE_VERTICALFLIP) @@ -4985,7 +5074,7 @@ void G_BeginMetal(void) oldmetal.x = mo->x; oldmetal.y = mo->y; oldmetal.z = mo->z; - oldmetal.angle = mo->angle; + oldmetal.angle = mo->angle>>24; } void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings) @@ -5085,8 +5174,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) switch(oldversion) // demoversion { case DEMOVERSION: // latest always supported - // compatibility available? - case 0x0008: break; // too old, cannot support. default: @@ -5162,7 +5249,8 @@ void G_DoPlayDemo(char *defdemoname) lumpnum_t l; char skin[17],color[17],*n,*pdemoname; UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration; - UINT32 randseed; + pflags_t pflags; + UINT32 randseed, followitem; fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; char msg[1024]; @@ -5225,8 +5313,6 @@ void G_DoPlayDemo(char *defdemoname) switch(demoversion) { case DEMOVERSION: // latest always supported - // compatibility available? - case 0x0008: break; // too old, cannot support. default: @@ -5252,10 +5338,7 @@ void G_DoPlayDemo(char *defdemoname) return; } demo_p += 4; // "PLAY" - if (demoversion <= 0x0008) - gamemap = READUINT8(demo_p); - else - gamemap = READINT16(demo_p); + gamemap = READINT16(demo_p); demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); @@ -5299,8 +5382,6 @@ void G_DoPlayDemo(char *defdemoname) M_Memcpy(color,demo_p,16); demo_p += 16; - camerascale = (fixed_t)READUINT8(demo_p)<mo = P_SpawnMobj(x, y, z, MT_GHOST); gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT); } - gh->mo->state = states+S_PLAY_STND; - gh->mo->sprite = gh->mo->state->sprite; - gh->mo->frame = (gh->mo->state->frame & FF_FRAMEMASK) | tr_trans20<mo->tics = -1; gh->oldmo.x = gh->mo->x; gh->oldmo.y = gh->mo->y; @@ -5616,6 +5715,12 @@ void G_AddGhost(char *defdemoname) } gh->oldmo.color = gh->mo->color; + gh->mo->state = states+S_PLAY_STND; + gh->mo->sprite = gh->mo->state->sprite; + gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK); + gh->mo->frame = tr_trans20<mo->tics = -1; + CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); Z_Free(pdemoname); } @@ -5662,8 +5767,10 @@ void G_DoPlayMetal(void) continue; mo = (mobj_t *)th; - if (mo->type == MT_METALSONIC_RACE) - break; + if (mo->type != MT_METALSONIC_RACE) + continue; + + break; } if (!mo) { @@ -5680,8 +5787,6 @@ void G_DoPlayMetal(void) switch(metalversion) { case DEMOVERSION: // latest always supported - // compatibility available? - case 0x0008: break; // too old, cannot support. default: @@ -5702,7 +5807,6 @@ void G_DoPlayMetal(void) oldmetal.x = mo->x; oldmetal.y = mo->y; oldmetal.z = mo->z; - oldmetal.angle = mo->angle; metalplayback = mo; } diff --git a/src/g_game.h b/src/g_game.h index 8715bd299..d6b41830e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -41,6 +41,7 @@ extern boolean demoplayback, titledemo, demorecording, timingdemo; // Quit after playing a demo from cmdline. extern boolean singledemo; extern boolean demo_start; +extern boolean demosynced; extern mobj_t *metalplayback; diff --git a/src/m_menu.c b/src/m_menu.c index 37574843b..419968e3c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1972,7 +1972,7 @@ void Nextmap_OnChange(void) SP_TimeAttackMenu[taghost].status = IT_DISABLED; // Check if file exists, if not, disable REPLAY option - sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string); + sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name); for (i = 0; i < 5; i++) { SP_ReplayMenu[i].status = IT_DISABLED; SP_GuestReplayMenu[i].status = IT_DISABLED; @@ -7701,7 +7701,7 @@ static void M_ChooseTimeAttack(INT32 choice) I_Error("Out of memory for replay filepath\n"); sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); - snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, cv_chooseskin.string); + snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name); if (!cv_autorecord.value) remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); @@ -7740,7 +7740,7 @@ static void M_ReplayTimeAttack(INT32 choice) return; } // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); + G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which)); } else if (currentMenu == &SP_NightsReplayDef) { @@ -7784,7 +7784,7 @@ static void M_OverwriteGuest(const char *which, boolean nights) UINT8 *buf; size_t len; if (!nights) - len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); + len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf); else len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which), &buf); if (!len) { diff --git a/src/p_inter.c b/src/p_inter.c index 707abf4c3..4c9e231fe 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -581,18 +581,21 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_AddPlayerScore(player, 1000); - if (ALL7EMERALDS(emeralds)) // Got all 7 + if (!modeattacking) // score only there... { - if (!(netgame || multiplayer)) + if (ALL7EMERALDS(emeralds)) // Got all 7 { - player->continues += 1; - players->gotcontinue = true; - if (P_IsLocalPlayer(player)) - S_StartSound(NULL, sfx_s3kac); + if (!(netgame || multiplayer)) + { + player->continues += 1; + players->gotcontinue = true; + if (P_IsLocalPlayer(player)) + S_StartSound(NULL, sfx_s3kac); + } } + else + token++; } - else - token++; break; // Emerald Hunt diff --git a/src/p_mobj.c b/src/p_mobj.c index fffee7c8b..a39f76d5d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8587,6 +8587,12 @@ void P_RemoveMobj(mobj_t *mobj) if (mobj->type == MT_OVERLAY) P_RemoveOverlay(mobj); + if (mobj->player && mobj->player->followmobj) + { + P_RemoveMobj(mobj->player->followmobj); + mobj->player->followmobj = NULL; + } + mobj->health = 0; // Just because // unlink from sector and block lists @@ -9497,10 +9503,6 @@ void P_SpawnMapThing(mapthing_t *mthing) if (i == MT_STARPOST) return; - // Emerald Tokens -->> Score Tokens - else if (i == MT_TOKEN) - return; /// \todo - // 1UPs -->> Score TVs else if (i == MT_1UP_BOX) // 1UP { diff --git a/src/p_user.c b/src/p_user.c index c7c217e85..27e0f8bcf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -594,6 +594,7 @@ static void P_DeNightserizePlayer(player_t *player) player->mo->skin = &skins[player->skin]; player->followitem = skins[player->skin].followitem; player->mo->color = player->skincolor; + G_GhostAddColor(GHC_NORMAL); // Restore aiming angle if (player == &players[consoleplayer]) @@ -6917,6 +6918,8 @@ static void P_MovePlayer(player_t *player) && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) { skin_t *skin = ((skin_t *)(player->mo->skin)); + if (skin->flags & SF_SUPER && player->mo->color < MAXSKINCOLORS) + G_GhostAddColor(GHC_SUPER); player->mo->color = (skin->flags & SF_SUPER) ? skin->supercolor + abs((((signed)(player->startedtime - player->nightstime) >> 1) % 9) - 4) : player->mo->color; // This is where super flashing is handled. } @@ -9841,7 +9844,7 @@ void P_PlayerThink(player_t *player) } } - // Autobrake! + // Autobrake! check ST_drawInput if you modify this { boolean currentlyonground = P_IsObjectOnGround(player->mo); @@ -10599,7 +10602,7 @@ void P_PlayerAfterThink(player_t *player) chosenstate = S_TAILSOVERLAY_RUN; else if (player->panim == PA_WALK) { - if (!smilesonground) + if (!smilesonground || player->mo->state-states == S_PLAY_SKID) chosenstate = S_TAILSOVERLAY_PLUS30DEGREES; else if (player->speed >= FixedMul(player->runspeed/2, player->mo->scale)) chosenstate = S_TAILSOVERLAY_0DEGREES; diff --git a/src/st_stuff.c b/src/st_stuff.c index 92f75e463..2a5fb7ea7 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -785,6 +785,196 @@ static void ST_drawLives(void) } } +static void ST_drawInput(void) +{ + //const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); -- no splitscreen support - record attack only for base game + const UINT8 accent = (stplyr->skincolor ? Color_Index[stplyr->skincolor-1][4] : 0); + UINT8 col, offs; + + INT32 x = hudinfo[HUD_LIVESPIC].x, y = hudinfo[HUD_LIVESPIC].y; + + if (stplyr->powers[pw_carry] == CR_NIGHTSMODE) + y -= 16; + + // O backing + V_DrawFill(x, y-1, 16, 16, 20); + V_DrawFill(x, y+15, 16, 1, 29); + + if (cv_showinputjoy.value) // joystick render! + { + /*V_DrawFill(x , y , 16, 1, 16); + V_DrawFill(x , y+15, 16, 1, 16); + V_DrawFill(x , y+ 1, 1, 14, 16); + V_DrawFill(x+15, y+ 1, 1, 14, 16); -- red's outline*/ + if (stplyr->cmd.sidemove || stplyr->cmd.forwardmove) + { + // joystick hole + V_DrawFill(x+5, y+4, 6, 6, 29); + // joystick top + V_DrawFill(x+3+stplyr->cmd.sidemove/12, + y+2-stplyr->cmd.forwardmove/12, + 10, 10, 29); + V_DrawFill(x+3+stplyr->cmd.sidemove/9, + y+1-stplyr->cmd.forwardmove/9, + 10, 10, accent); + } + else + { + // just a limited, greyed out joystick top + V_DrawFill(x+3, y+11, 10, 1, 29); + V_DrawFill(x+3, + y+1, + 10, 10, 16); + } + } + else // arrows! + { + // < + if (stplyr->cmd.sidemove < 0) + { + offs = 0; + col = accent; + } + else + { + offs = 1; + col = 16; + V_DrawFill(x- 2, y+10, 6, 1, 29); + V_DrawFill(x+ 4, y+ 9, 1, 1, 29); + V_DrawFill(x+ 5, y+ 8, 1, 1, 29); + } + V_DrawFill(x- 2, y+ 5-offs, 6, 6, col); + V_DrawFill(x+ 4, y+ 6-offs, 1, 4, col); + V_DrawFill(x+ 5, y+ 7-offs, 1, 2, col); + + // ^ + if (stplyr->cmd.forwardmove > 0) + { + offs = 0; + col = accent; + } + else + { + offs = 1; + col = 16; + V_DrawFill(x+ 5, y+ 3, 1, 1, 29); + V_DrawFill(x+ 6, y+ 4, 1, 1, 29); + V_DrawFill(x+ 7, y+ 5, 2, 1, 29); + V_DrawFill(x+ 9, y+ 4, 1, 1, 29); + V_DrawFill(x+10, y+ 3, 1, 1, 29); + } + V_DrawFill(x+ 5, y- 2-offs, 6, 6, col); + V_DrawFill(x+ 6, y+ 4-offs, 4, 1, col); + V_DrawFill(x+ 7, y+ 5-offs, 2, 1, col); + + // > + if (stplyr->cmd.sidemove > 0) + { + offs = 0; + col = accent; + } + else + { + offs = 1; + col = 16; + V_DrawFill(x+12, y+10, 6, 1, 29); + V_DrawFill(x+11, y+ 9, 1, 1, 29); + V_DrawFill(x+10, y+ 8, 1, 1, 29); + } + V_DrawFill(x+12, y+ 5-offs, 6, 6, col); + V_DrawFill(x+11, y+ 6-offs, 1, 4, col); + V_DrawFill(x+10, y+ 7-offs, 1, 2, col); + + // v + if (stplyr->cmd.forwardmove < 0) + { + offs = 0; + col = accent; + } + else + { + offs = 1; + col = 16; + V_DrawFill(x+ 5, y+17, 6, 1, 29); + } + V_DrawFill(x+ 5, y+12-offs, 6, 6, col); + V_DrawFill(x+ 6, y+11-offs, 4, 1, col); + V_DrawFill(x+ 7, y+10-offs, 2, 1, col); + } + +#define drawbutt(xoffs, yoffs, butt, symb)\ + if (stplyr->cmd.buttons & butt)\ + {\ + offs = 0;\ + col = accent;\ + }\ + else\ + {\ + offs = 1;\ + col = 16;\ + V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, 29);\ + }\ + V_DrawFill(x+16+(xoffs), y+(yoffs)-offs, 10, 10, col);\ + V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, symb, false) + + drawbutt( 4,-3, BT_JUMP, 'J'); + drawbutt(15,-3, BT_USE, 'S'); + + V_DrawFill(x+16+4, y+8, 21, 10, 20); // sundial backing + if (stplyr->mo) + { + UINT8 i, precision; + angle_t ang = (stplyr->powers[pw_carry] == CR_NIGHTSMODE) + ? (FixedAngle((stplyr->flyangle-90)<>ANGLETOFINESHIFT) + : (stplyr->mo->angle - R_PointToAngle(stplyr->mo->x, stplyr->mo->y))>>ANGLETOFINESHIFT; + fixed_t xcomp = FINESINE(ang)>>13; + fixed_t ycomp = FINECOSINE(ang)>>14; + if (ycomp == 4) + ycomp = 3; + + if (ycomp > 0) + V_DrawFill(x+16+13-xcomp, y+11-ycomp, 3, 3, accent); // point (behind) + + precision = max(3, abs(xcomp)); + for (i = 0; i < precision; i++) // line + { + V_DrawFill(x+16+14-(i*xcomp)/precision, + y+12-(i*ycomp)/precision, + 1, 1, 16); + } + + if (ycomp <= 0) + V_DrawFill(x+16+13-xcomp, y+11-ycomp, 3, 3, accent); // point (in front) + } + +#undef drawbutt + + // text above + x -= 2; + y -= 13; + if (stplyr->powers[pw_carry] != CR_NIGHTSMODE) + { + if (stplyr->pflags & PF_AUTOBRAKE) + { + V_DrawThinString(x, y, + ((!stplyr->powers[pw_carry] + && (stplyr->pflags & PF_APPLYAUTOBRAKE) + && !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove) + && (stplyr->rmomx || stplyr->rmomy)) + ? 0 : V_GRAYMAP), + "AUTOBRAKE"); + y -= 8; + } + if (stplyr->pflags & PF_ANALOGMODE) + { + V_DrawThinString(x, y, 0, "ANALOG"); + y -= 8; + } + } + if (!demosynced) // should always be last, so it doesn't push anything else around + V_DrawThinString(x, y, ((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); +} + static void ST_drawLevelTitle(void) { char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; @@ -2095,6 +2285,9 @@ static void ST_overlayDrawer(void) } } + if (modeattacking) + ST_drawInput(); + ST_drawDebugInfo(); } diff --git a/src/y_inter.c b/src/y_inter.c index 0812ba80f..8a93b3eab 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -917,14 +917,14 @@ static void Y_UpdateRecordReplays(void) I_Error("Out of memory for replay filepath\n"); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); - snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string); + snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); if (FIL_FileExists(lastdemo)) { UINT8 *buf; size_t len = FIL_ReadFile(lastdemo, &buf); - snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_chooseskin.string); + snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) { // Better time, save this demo. if (FIL_FileExists(bestdemo)) @@ -933,7 +933,7 @@ static void Y_UpdateRecordReplays(void) CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); } - snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, cv_chooseskin.string); + snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) { // Better score, save this demo. if (FIL_FileExists(bestdemo)) @@ -942,7 +942,7 @@ static void Y_UpdateRecordReplays(void) CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); } - snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, cv_chooseskin.string); + snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) { // Better rings, save this demo. if (FIL_FileExists(bestdemo))