diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5beca1173..5b4141328 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1338,7 +1338,7 @@ static void CL_ReloadReceivedSavegame(void) neededtic = gametic; maketic = neededtic; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { P_ForceLocalAngle(&players[displayplayers[i]], players[displayplayers[i]].angleturn); } @@ -2375,7 +2375,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting // don't look through someone's view who isn't there - if (playernum == displayplayers[0]) + if (playernum == displayplayers[0] && !demo.playback) { // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. @@ -2404,9 +2404,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayers[0] && !demo.playback) - displayplayers[0] = consoleplayer; // don't look through someone's view who isn't there - LUA_InvalidatePlayer(&players[playernum]); K_CheckBumpers(); diff --git a/src/d_main.c b/src/d_main.c index 57dcdefea..5ded2bf14 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -615,16 +615,6 @@ static void D_Display(void) { F_WipeEndScreen(); - // Funny. - if (WipeStageTitle && st_overlay) - { - lt_ticker--; - lt_lasttic = lt_ticker; - ST_preLevelTitleCardDrawer(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - F_WipeStartScreen(); - } - F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN, "FADEMAP0", true, false); } @@ -1057,15 +1047,6 @@ static void IdentifyVersion(void) D_AddFile(startupiwads, va(pandf,srb2waddir,"patch.pk3")); #endif -#if 0 - // TODO: pk3 doesn't support music replacement IIRC - // music barely benefits from the compression anyway - // would be nice for the folders, though - D_AddFile(startupiwads, va(pandf,srb2waddir,"sounds.pk3")); - D_AddFile(startupiwads, va(pandf,srb2waddir,"music.pk3")); - -#else - #if !defined (HAVE_SDL) || defined (HAVE_MIXER) #define MUSICTEST(str) \ @@ -1078,12 +1059,11 @@ static void IdentifyVersion(void) I_Error("File "str" has been modified with non-music/sound lumps"); \ } - MUSICTEST("sounds.wad") + MUSICTEST("sounds.pk3") MUSICTEST("music.pk3") #undef MUSICTEST -#endif #endif } diff --git a/src/d_netfil.c b/src/d_netfil.c index d3058681b..5714c39cd 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1299,16 +1299,18 @@ void PT_FileFragment(void) filename = va("%s", file->filename); nameonly(filename); - if (!(strcmp(filename, "main.kart") - && strcmp(filename, "gfx.pk3") - && strcmp(filename, "textures.pk3") - && strcmp(filename, "chars.pk3") - && strcmp(filename, "maps.wad") - && strcmp(filename, "patch.pk3") - && strcmp(filename, "sounds.wad") - && strcmp(filename, "music.wad") - )) + if (!strcmp(filename, "main.kart") + || !strcmp(filename, "gfx.pk3") + || !strcmp(filename, "textures.pk3") + || !strcmp(filename, "chars.pk3") + || !strcmp(filename, "maps.pk3") + || !strcmp(filename, "patch.pk3") + || !strcmp(filename, "sounds.pk3") + || !strcmp(filename, "music.pk3") + ) + { I_Error("Tried to download \"%s\"", filename); + } filename = file->filename; diff --git a/src/d_player.h b/src/d_player.h index 8bd2f3fa8..7848e5b87 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -526,6 +526,8 @@ typedef struct player_s UINT8 kickstartaccel; + UINT8 stairjank; + #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index 75b667e66..891f681bf 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4649,6 +4649,12 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_DEBTSPIKEC", "S_DEBTSPIKED", "S_DEBTSPIKEE", + + // Sparks when driving on stairs + "S_JANKSPARK1", + "S_JANKSPARK2", + "S_JANKSPARK3", + "S_JANKSPARK4", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5452,6 +5458,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_DRIFTDUST", "MT_DRIFTELECTRICITY", "MT_DRIFTELECTRICSPARK", + "MT_JANKSPARK", "MT_ROCKETSNEAKER", // Rocket sneakers diff --git a/src/doomstat.h b/src/doomstat.h index d44ec24b0..19359df3b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -420,7 +420,7 @@ typedef struct extern mapheader_t* mapheaderinfo[NUMMAPS]; // This could support more, but is that a good idea? -// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. +// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. #define MAXLEVELLIST 5 typedef struct cupheader_s diff --git a/src/f_finale.h b/src/f_finale.h index cc731f7f3..a45de5734 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -143,7 +143,7 @@ extern INT32 lastwipetic; // Don't know where else to place this constant // But this file seems appropriate -#define PRELEVELTIME 24 // frames in tics +#define PRELEVELTIME TICRATE // frames in tics void F_WipeStartScreen(void); void F_WipeEndScreen(void); diff --git a/src/f_wipe.c b/src/f_wipe.c index 9399598f5..ddc719e6d 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -415,7 +415,7 @@ void F_WipeStageTitle(void) if ((WipeStageTitle) && G_IsTitleCardAvailable()) { ST_runTitleCard(); - ST_drawWipeTitleCard(); + ST_drawTitleCard(); } } diff --git a/src/g_demo.c b/src/g_demo.c index 56f98cf73..a30d78878 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -347,6 +347,7 @@ void G_ReadDemoExtraData(void) players[p].pflags &= ~(PF_KICKSTARTACCEL); if (extradata & 1) players[p].pflags |= PF_KICKSTARTACCEL; + //CONS_Printf("weaponpref is %d for player %d\n", extradata, p); } p = READUINT8(demo_p); @@ -2656,7 +2657,7 @@ void G_DoPlayDemo(char *defdemoname) UINT32 randseed; char msg[1024]; - boolean spectator; + boolean spectator, kickstart; UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], numslots = 0; #if defined(SKIPERRORS) && !defined(DEVELOP) @@ -2925,16 +2926,8 @@ void G_DoPlayDemo(char *defdemoname) while (p != 0xFF) { - players[p].pflags &= ~PF_KICKSTARTACCEL; - if (p & DEMO_KICKSTART) + if ((spectator = (p & DEMO_SPECTATOR))) { - players[p].pflags |= PF_KICKSTARTACCEL; - p &= ~DEMO_KICKSTART; - } - spectator = false; - if (p & DEMO_SPECTATOR) - { - spectator = true; p &= ~DEMO_SPECTATOR; if (modeattacking) @@ -2949,6 +2942,10 @@ void G_DoPlayDemo(char *defdemoname) return; } } + + if ((kickstart = (p & DEMO_KICKSTART))) + p &= ~DEMO_KICKSTART; + slots[numslots] = p; numslots++; if (modeattacking && numslots > 1) @@ -2968,6 +2965,10 @@ void G_DoPlayDemo(char *defdemoname) playeringame[p] = true; players[p].spectator = spectator; + if (kickstart) + players[p].pflags |= PF_KICKSTARTACCEL; + else + players[p].pflags &= ~PF_KICKSTARTACCEL; // Name M_Memcpy(player_names[p],demo_p,16); diff --git a/src/g_game.c b/src/g_game.c index 50b759c70..580b3bf0d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1139,7 +1139,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // Send leveltime when this tic was generated to the server for control lag calculations. // Only do this when in a level. Also do this after the hook, so that it can't overwrite this. - cmd->latency = (leveltime & 0xFF); + cmd->latency = (leveltime & 0xFF); } if (cmd->forwardmove > MAXPLMOVE) @@ -1263,7 +1263,7 @@ void G_DoLoadLevel(boolean resetplayer) for (i = 0; i <= r_splitscreen; i++) { if (camera[i].chase) - P_ResetCamera(&players[g_localplayers[i]], &camera[i]); + P_ResetCamera(&players[displayplayers[i]], &camera[i]); } // clear cmd building stuff @@ -1301,7 +1301,7 @@ void G_StartTitleCard(void) ST_startTitleCard(); // start the title card - WipeStageTitle = false; //(!titlemapinaction); -- temporary until titlecards are reworked + WipeStageTitle = (!titlemapinaction); } // @@ -1310,26 +1310,27 @@ void G_StartTitleCard(void) void G_PreLevelTitleCard(void) { #ifndef NOWIPE - tic_t strtime = I_GetTime(); - tic_t endtime = strtime + (PRELEVELTIME*NEWTICRATERATIO); - tic_t nowtime = strtime; - tic_t lasttime = strtime; - while (nowtime < endtime) - { - // draw loop - while (!((nowtime = I_GetTime()) - lasttime)) - I_Sleep(); - lasttime = nowtime; + tic_t strtime = I_GetTime(); + tic_t endtime = strtime + (PRELEVELTIME*NEWTICRATERATIO); + tic_t nowtime = strtime; + tic_t lasttime = strtime; + while (nowtime < endtime) + { + // draw loop + ST_runTitleCard(); + ST_preLevelTitleCardDrawer(); + I_FinishUpdate(); // page flip or blit buffer + NetKeepAlive(); // Prevent timeouts - ST_runTitleCard(); - ST_preLevelTitleCardDrawer(); - I_FinishUpdate(); // page flip or blit buffer + if (moviemode) + M_SaveFrame(); + if (takescreenshot) // Only take screenshots after drawing. + M_DoScreenShot(); - if (moviemode) - M_SaveFrame(); - if (takescreenshot) // Only take screenshots after drawing. - M_DoScreenShot(); - } + while (!((nowtime = I_GetTime()) - lasttime)) + I_Sleep(); + lasttime = nowtime; + } #endif } diff --git a/src/g_splitscreen.c b/src/g_splitscreen.c index 0354c0d10..e510a474c 100644 --- a/src/g_splitscreen.c +++ b/src/g_splitscreen.c @@ -50,10 +50,10 @@ G_ResetSplitscreen (INT32 playernum) displayplayers[i] = g_localplayers[i]; P_ResetCamera(&players[displayplayers[i]], &camera[i]); } + while (i < MAXSPLITSCREENPLAYERS) { displayplayers[i] = consoleplayer; - i++; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 3358f2fd3..7afc7d531 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -73,6 +73,8 @@ patch_t *pinggfx[5]; // small ping graphic patch_t *mping[5]; // smaller ping graphic +patch_t *tc_font[2][LT_FONTSIZE]; // Special font stuff for titlecard + patch_t *framecounter; patch_t *frameslash; // framerate stuff. Used in screen.c @@ -178,7 +180,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum); void HU_LoadGraphics(void) { - INT32 i; + char buffer[9]; + INT32 i, j; if (dedicated) return; @@ -191,6 +194,27 @@ void HU_LoadGraphics(void) emblemicon = HU_CachePatch("EMBLICON"); songcreditbg = HU_CachePatch("K_SONGCR"); + // Cache titlecard font + j = LT_FONTSTART; + for (i = 0; i < LT_FONTSIZE; i++, j++) + { + // cache the titlecard font + + // Bottom layer + sprintf(buffer, "GTOL%.3d", j); + if (W_CheckNumForName(buffer) == LUMPERROR) + tc_font[0][i] = NULL; + else + tc_font[0][i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + + // Top layer + sprintf(buffer, "GTFN%.3d", j); + if (W_CheckNumForName(buffer) == LUMPERROR) + tc_font[1][i] = NULL; + else + tc_font[1][i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + } + // cache ping gfx: for (i = 0; i < 5; i++) { @@ -704,7 +728,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) } else if (target == -1) // say team { - if (players[playernum].ctfteam == 1) + if (players[playernum].ctfteam == 1) { // red text cstart = textcolor = "\x85"; diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 6a425926b..4d686516e 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -39,6 +39,11 @@ #define LT_FONTEND 'z' // the last font characters #define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1) +// Under regular circumstances, we'd use the built in font stuff, however this font is a bit messy because of how we're gonna draw shit. +// tc_font[0][n] is used for the "bottom" layer +// tc_font[1][n] is used for the "top" layer +extern patch_t *tc_font[2][LT_FONTSIZE]; + #define CRED_FONTSTART '!' // the first font character #define CRED_FONTEND 'Z' // the last font character #define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1) diff --git a/src/info.c b/src/info.c index ff982d6de..9e4c70dc9 100644 --- a/src/info.c +++ b/src/info.c @@ -543,6 +543,7 @@ char sprnames[NUMSPRITES + 1][5] = "DRWS", // Drift dust sparks "DREL", // Drift electricity "DRES", // Drift electric sparks + "JANK", // Stair janking sparks // Kart Items "RSHE", // Rocket sneaker @@ -5234,6 +5235,12 @@ state_t states[NUMSTATES] = {SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKED}, // S_DEBTSPIKEC {SPR_DEBT, 6|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKEE}, // S_DEBTSPIKED {SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE1}, // S_DEBTSPIKEE + + // Sparks when driving on stairs + {SPR_JANK, 0, 1, {NULL}, 0, 0, S_JANKSPARK2}, // S_JANKSPARK1 + {SPR_JANK, FF_PAPERSPRITE|FF_FULLBRIGHT|FF_ANIMATE, 4, {NULL}, 3, 1, S_JANKSPARK3}, // S_JANKSPARK2 + {SPR_JANK, 0, 0, {A_SetCustomValue}, -1, 5, S_JANKSPARK4}, // S_JANKSPARK3 + {SPR_JANK, 0, 0, {A_ChangeAngleRelative}, 180, 180, S_JANKSPARK2}, // S_JANKSPARK4 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -23534,6 +23541,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_JANKSPARK + -1, // doomednum + S_JANKSPARK1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_FLOAT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_ROCKETSNEAKER -1, // doomednum S_ROCKETSNEAKER_L, // spawnstate diff --git a/src/info.h b/src/info.h index f012df8a0..ce77a2a68 100644 --- a/src/info.h +++ b/src/info.h @@ -1085,6 +1085,7 @@ typedef enum sprite SPR_DRWS, // Drift dust sparks SPR_DREL, // Drift electricity SPR_DRES, // Drift electric sparks + SPR_JANK, // Stair janking sparks // Kart Items SPR_RSHE, // Rocket sneaker @@ -5640,6 +5641,11 @@ typedef enum state S_DEBTSPIKED, S_DEBTSPIKEE, + S_JANKSPARK1, + S_JANKSPARK2, + S_JANKSPARK3, + S_JANKSPARK4, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -6462,6 +6468,7 @@ typedef enum mobj_type MT_DRIFTDUST, MT_DRIFTELECTRICITY, MT_DRIFTELECTRICSPARK, + MT_JANKSPARK, MT_ROCKETSNEAKER, diff --git a/src/k_collide.c b/src/k_collide.c index 7413804d9..96fe30182 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -46,7 +46,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) { // Player Damage P_DamageMobj(t2, t1, t1->target, 1, DMG_WIPEOUT); - K_KartBouncing(t2, t1, false, false); + K_KartBouncing(t2, t1); S_StartSound(t2, sfx_s3k7b); } @@ -430,7 +430,7 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2) { if (t2->player || t2->type == MT_FALLINGROCK) - K_KartBouncing(t2, t1, false, false); + K_KartBouncing(t2, t1); return true; } @@ -457,8 +457,8 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) return true; */ - K_KartBouncing(t2, t1, false, true); - return false; + K_KartSolidBounce(t1, t2); + return true; } boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) @@ -537,25 +537,24 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) if (t1Condition == true) { + P_PlayerRingBurst(t2->player, 1); + if (t2->player->rings <= 0) { P_DamageMobj(t2, t1, t1, 1, DMG_STING); stung = true; } - - P_PlayerRingBurst(t2->player, 1); - stung = true; } if (t2Condition == true) { + P_PlayerRingBurst(t1->player, 1); + if (t1->player->rings <= 0) { P_DamageMobj(t1, t2, t2, 1, DMG_STING); stung = true; } - - P_PlayerRingBurst(t2->player, 1); } return stung; diff --git a/src/k_kart.c b/src/k_kart.c index 2bf32f71e..d659851b5 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1123,16 +1123,137 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return FixedMul(weight, mobj->scale); } -boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) +static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2) { - mobj_t *fx; + mobj_t *fx = P_SpawnMobj( + mobj1->x/2 + mobj2->x/2, + mobj1->y/2 + mobj2->y/2, + mobj1->z/2 + mobj2->z/2, + MT_BUMP + ); + fixed_t avgScale = (mobj1->scale + mobj2->scale) / 2; + + if (mobj1->eflags & MFE_VERTICALFLIP) + { + fx->eflags |= MFE_VERTICALFLIP; + } + else + { + fx->eflags &= ~MFE_VERTICALFLIP; + } + + P_SetScale(fx, (fx->destscale = avgScale)); + + if ((mobj1->player && mobj1->player->itemtype == KITEM_BUBBLESHIELD) + || (mobj2->player && mobj2->player->itemtype == KITEM_BUBBLESHIELD)) + { + S_StartSound(mobj1, sfx_s3k44); + } + else + { + S_StartSound(mobj1, sfx_s3k49); + } +} + +static void K_PlayerJustBumped(player_t *player) +{ + mobj_t *playerMobj = NULL; + + if (player == NULL) + { + return; + } + + playerMobj = player->mo; + + if (playerMobj == NULL || P_MobjWasRemoved(playerMobj)) + { + return; + } + + if (abs(player->rmomx) < playerMobj->scale && abs(player->rmomy) < playerMobj->scale) + { + // Because this is done during collision now, rmomx and rmomy need to be recalculated + // so that friction doesn't immediately decide to stop the player if they're at a standstill + player->rmomx = playerMobj->momx - player->cmomx; + player->rmomy = playerMobj->momy - player->cmomy; + } + + player->justbumped = bumptime; + player->spindash = 0; + + if (player->spinouttimer) + { + player->wipeoutslow = wipeoutslowtime+1; + player->spinouttimer = max(wipeoutslowtime+1, player->spinouttimer); + //player->spinouttype = KSPIN_WIPEOUT; // Enforce type + } +} + +static fixed_t K_GetBounceForce(mobj_t *mobj1, mobj_t *mobj2, fixed_t distx, fixed_t disty) +{ + const fixed_t forceMul = (4 * FRACUNIT) / 10; // Multiply by this value to make it feel like old bumps. + fixed_t momdifx, momdify; - fixed_t distx, disty; - fixed_t dot, force; + fixed_t dot; + fixed_t force = 0; + + momdifx = mobj1->momx - mobj2->momx; + momdify = mobj1->momy - mobj2->momy; + + if (distx == 0 && disty == 0) + { + // if there's no distance between the 2, they're directly on top of each other, don't run this + return 0; + } + + { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... + fixed_t dist = P_AproxDistance(distx, disty); + fixed_t nx, ny; + + dist = dist ? dist : 1; + + nx = FixedDiv(distx, dist); + ny = FixedDiv(disty, dist); + + distx = FixedMul(mobj1->radius + mobj2->radius, nx); + disty = FixedMul(mobj1->radius + mobj2->radius, ny); + + if (momdifx == 0 && momdify == 0) + { + // If there's no momentum difference, they're moving at exactly the same rate. Pretend they moved into each other. + momdifx = -nx; + momdify = -ny; + } + } + + dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty); + + if (dot >= 0) + { + // They're moving away from each other + return 0; + } + + // Return the push force! + force = FixedDiv(dot, FixedMul(distx, distx) + FixedMul(disty, disty)); + + return FixedMul(force, forceMul); +} + +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) +{ + const fixed_t minBump = 25*mapobjectscale; + mobj_t *goombaBounce = NULL; + fixed_t distx, disty, dist; + fixed_t force; fixed_t mass1, mass2; - if (!mobj1 || !mobj2) + if ((!mobj1 || P_MobjWasRemoved(mobj1)) + || (!mobj2 || P_MobjWasRemoved(mobj2))) + { return false; + } // Don't bump when you're being reborn if ((mobj1->player && mobj1->player->playerstate != PST_LIVE) @@ -1176,135 +1297,145 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol return false; } - mass1 = K_GetMobjWeight(mobj1, mobj2); + // Adds the OTHER object's momentum times a bunch, for the best chance of getting the correct direction + distx = (mobj1->x + mobj2->momx) - (mobj2->x + mobj1->momx); + disty = (mobj1->y + mobj2->momy) - (mobj2->y + mobj1->momy); - if (solid == true && mass1 > 0) - mass2 = mass1; - else - mass2 = K_GetMobjWeight(mobj2, mobj1); + force = K_GetBounceForce(mobj1, mobj2, distx, disty); - momdifx = mobj1->momx - mobj2->momx; - momdify = mobj1->momy - mobj2->momy; - - // Adds the OTHER player's momentum times a bunch, for the best chance of getting the correct direction - distx = (mobj1->x + mobj2->momx*3) - (mobj2->x + mobj1->momx*3); - disty = (mobj1->y + mobj2->momy*3) - (mobj2->y + mobj1->momy*3); - - if (distx == 0 && disty == 0) + if (force == 0) { - // if there's no distance between the 2, they're directly on top of each other, don't run this return false; } - { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... - fixed_t dist = P_AproxDistance(distx, disty); - fixed_t nx, ny; + mass1 = K_GetMobjWeight(mobj1, mobj2); + mass2 = K_GetMobjWeight(mobj2, mobj1); - dist = dist ? dist : 1; - - nx = FixedDiv(distx, dist); - ny = FixedDiv(disty, dist); - - distx = FixedMul(mobj1->radius+mobj2->radius, nx); - disty = FixedMul(mobj1->radius+mobj2->radius, ny); - - if (momdifx == 0 && momdify == 0) - { - // If there's no momentum difference, they're moving at exactly the same rate. Pretend they moved into each other. - momdifx = -nx; - momdify = -ny; - } + if ((P_IsObjectOnGround(mobj1) && mobj2->momz < 0) // Grounded + || (mass2 == 0 && mass1 > 0)) // The other party is immovable + { + goombaBounce = mobj2; } + else if ((P_IsObjectOnGround(mobj2) && mobj1->momz < 0) // Grounded + || (mass1 == 0 && mass2 > 0)) // The other party is immovable + { + goombaBounce = mobj1; + } + + if (goombaBounce != NULL) + { + // Perform a Goomba Bounce by reversing your z momentum. + goombaBounce->momz = -goombaBounce->momz; + } + else + { + // Trade z momentum values. + fixed_t newz = mobj1->momz; + mobj1->momz = mobj2->momz; + mobj2->momz = newz; + } + + // Multiply by force + distx = FixedMul(force, distx); + disty = FixedMul(force, disty); + dist = FixedHypot(distx, disty); // if the speed difference is less than this let's assume they're going proportionately faster from each other - if (P_AproxDistance(momdifx, momdify) < (25*mapobjectscale)) + if (dist < minBump) { - fixed_t momdiflength = P_AproxDistance(momdifx, momdify); - fixed_t normalisedx = FixedDiv(momdifx, momdiflength); - fixed_t normalisedy = FixedDiv(momdify, momdiflength); - momdifx = FixedMul((25*mapobjectscale), normalisedx); - momdify = FixedMul((25*mapobjectscale), normalisedy); - } + fixed_t normalisedx = FixedDiv(distx, dist); + fixed_t normalisedy = FixedDiv(disty, dist); - dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty); - - if (dot >= 0) - { - // They're moving away from each other - return false; - } - - force = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty)); - - if (bounce == true && mass2 > 0) // Perform a Goomba Bounce. - mobj1->momz = -mobj1->momz; - else - { - fixed_t newz = mobj1->momz; - if (mass2 > 0) - mobj1->momz = mobj2->momz; - if (mass1 > 0 && solid == false) - mobj2->momz = newz; + distx = FixedMul(minBump, normalisedx); + disty = FixedMul(minBump, normalisedy); } if (mass2 > 0) { - mobj1->momx = mobj1->momx - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), distx); - mobj1->momy = mobj1->momy - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), disty); + mobj1->momx = mobj1->momx - FixedMul(FixedDiv(2*mass2, mass1 + mass2), distx); + mobj1->momy = mobj1->momy - FixedMul(FixedDiv(2*mass2, mass1 + mass2), disty); } - if (mass1 > 0 && solid == false) + if (mass1 > 0) { - mobj2->momx = mobj2->momx - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -distx); - mobj2->momy = mobj2->momy - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -disty); + mobj2->momx = mobj2->momx - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -distx); + mobj2->momy = mobj2->momy - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -disty); } - // Do the bump fx when we've CONFIRMED we can bump. - if ((mobj1->player && mobj1->player->itemtype == KITEM_BUBBLESHIELD) || (mobj2->player && mobj2->player->itemtype == KITEM_BUBBLESHIELD)) - S_StartSound(mobj1, sfx_s3k44); - else - S_StartSound(mobj1, sfx_s3k49); + K_SpawnBumpForObjs(mobj1, mobj2); - fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP); - if (mobj1->eflags & MFE_VERTICALFLIP) - fx->eflags |= MFE_VERTICALFLIP; - else - fx->eflags &= ~MFE_VERTICALFLIP; - P_SetScale(fx, mobj1->scale); + K_PlayerJustBumped(mobj1->player); + K_PlayerJustBumped(mobj2->player); - // Because this is done during collision now, rmomx and rmomy need to be recalculated - // so that friction doesn't immediately decide to stop the player if they're at a standstill - // Also set justbumped here - if (mobj1->player) + return true; +} + +// K_KartBouncing, but simplified to act like P_BouncePlayerMove +boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj) +{ + const fixed_t minBump = 25*mapobjectscale; + fixed_t distx, disty, dist; + fixed_t force; + + if ((!bounceMobj || P_MobjWasRemoved(bounceMobj)) + || (!solidMobj || P_MobjWasRemoved(solidMobj))) { - mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx; - mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy; - mobj1->player->justbumped = bumptime; - mobj1->player->spindash = 0; - - if (mobj1->player->spinouttimer) - { - mobj1->player->wipeoutslow = wipeoutslowtime+1; - mobj1->player->spinouttimer = max(wipeoutslowtime+1, mobj1->player->spinouttimer); - //mobj1->player->spinouttype = KSPIN_WIPEOUT; // Enforce type - } + return false; } - if (mobj2->player) + // Don't bump when you're being reborn + if (bounceMobj->player && bounceMobj->player->playerstate != PST_LIVE) + return false; + + if (bounceMobj->player && bounceMobj->player->respawn.state != RESPAWNST_NONE) + return false; + + // Don't bump if you've recently bumped + if (bounceMobj->player && bounceMobj->player->justbumped) { - mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx; - mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy; - mobj2->player->justbumped = bumptime; - mobj2->player->spindash = 0; - - if (mobj2->player->spinouttimer) - { - mobj2->player->wipeoutslow = wipeoutslowtime+1; - mobj2->player->spinouttimer = max(wipeoutslowtime+1, mobj2->player->spinouttimer); - //mobj2->player->spinouttype = KSPIN_WIPEOUT; // Enforce type - } + bounceMobj->player->justbumped = bumptime; + return false; } + // Adds the OTHER object's momentum times a bunch, for the best chance of getting the correct direction + { + distx = (bounceMobj->x + solidMobj->momx) - (solidMobj->x + bounceMobj->momx); + disty = (bounceMobj->y + solidMobj->momy) - (solidMobj->y + bounceMobj->momy); + } + + force = K_GetBounceForce(bounceMobj, solidMobj, distx, disty); + + if (force == 0) + { + return false; + } + + // Multiply by force + distx = FixedMul(force, distx); + disty = FixedMul(force, disty); + dist = FixedHypot(distx, disty); + + { + // Normalize to the desired push value. + fixed_t normalisedx = FixedDiv(distx, dist); + fixed_t normalisedy = FixedDiv(disty, dist); + fixed_t bounceSpeed; + + bounceSpeed = FixedHypot(bounceMobj->momx, bounceMobj->momy); + bounceSpeed = FixedMul(bounceSpeed, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + bounceSpeed += minBump; + + distx = FixedMul(bounceSpeed, normalisedx); + disty = FixedMul(bounceSpeed, normalisedy); + } + + bounceMobj->momx = bounceMobj->momx - distx; + bounceMobj->momy = bounceMobj->momy - disty; + bounceMobj->momz = -bounceMobj->momz; + + K_SpawnBumpForObjs(bounceMobj, solidMobj); + K_PlayerJustBumped(bounceMobj->player); + return true; } @@ -1760,11 +1891,6 @@ static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the m sparks->renderflags |= RF_DONTDRAW; } -static fixed_t K_RandomFlip(fixed_t f) -{ - return ( ( leveltime & 1 ) ? f : -f ); -} - void K_SpawnDriftBoostClip(player_t *player) { mobj_t *clip; @@ -1789,7 +1915,7 @@ void K_SpawnDriftBoostClip(player_t *player) clip->momz += player->mo->momz; P_InstaThrust(clip, player->mo->angle + - K_RandomFlip(P_RandomRange(FRACUNIT/2, FRACUNIT)), + P_RandomFlip(P_RandomRange(FRACUNIT/2, FRACUNIT)), FixedMul(scale, player->speed)); } @@ -6310,7 +6436,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) ghost->extravalue1 = player->numboosts+1; ghost->extravalue2 = (leveltime % ghost->extravalue1); ghost->fuse = ghost->extravalue1; - ghost->frame |= FF_FULLBRIGHT; + ghost->renderflags |= RF_FULLBRIGHT; ghost->colorized = true; //ghost->color = player->skincolor; //ghost->momx = (3*player->mo->momx)/4; @@ -7870,6 +7996,11 @@ SINT8 K_Sliptiding(player_t *player) return player->drift ? 0 : player->aizdriftstrat; } +INT32 K_StairJankFlip(INT32 value) +{ + return P_AltFlip(value, 2); +} + static void K_KartSpindashDust(mobj_t *parent) { fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); diff --git a/src/k_kart.h b/src/k_kart.h index ad254822c..d0668450e 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,7 +37,8 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival); INT32 K_GetShieldFromItem(INT32 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); -boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); +boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); @@ -85,6 +86,7 @@ boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); void K_UpdateSteeringValue(player_t *player, INT16 destSteering); INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); INT32 K_GetKartDriftSparkValue(player_t *player); +INT32 K_StairJankFlip(INT32 value); INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage); void K_SpawnDriftBoostExplosion(player_t *player, int stage); void K_SpawnDriftElectricSparks(player_t *player); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9e1c909f5..0ce78b6f9 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3391,14 +3391,12 @@ static int lib_kKartBouncing(lua_State *L) { mobj_t *mobj1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *mobj2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - boolean bounce = lua_optboolean(L, 3); - boolean solid = lua_optboolean(L, 4); NOHUD if (!mobj1) return LUA_ErrInvalid(L, "mobj_t"); if (!mobj2) return LUA_ErrInvalid(L, "mobj_t"); - K_KartBouncing(mobj1, mobj2, bounce, solid); + K_KartBouncing(mobj1, mobj2); return 0; } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 926df78ca..75a84ed18 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -946,6 +946,24 @@ static int libd_drawString(lua_State *L) return 0; } +static int libd_drawTitleCardString(lua_State *L) +{ + + fixed_t x = luaL_checkinteger(L, 1); + fixed_t y = luaL_checkinteger(L, 2); + const char *str = luaL_checkstring(L, 3); + INT32 flags = luaL_optinteger(L, 4, V_ALLOWLOWERCASE); + boolean rightalign = lua_optboolean(L, 5); + INT32 timer = luaL_optinteger(L, 6, 0); + INT32 threshold = luaL_optinteger(L, 7, 0); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + HUDONLY + V_DrawTitleCardString(x, y, str, flags, rightalign, timer, threshold); + return 0; +} + static int libd_drawKartString(lua_State *L) { fixed_t x = luaL_checkinteger(L, 1); @@ -960,6 +978,15 @@ static int libd_drawKartString(lua_State *L) return 0; } +static int libd_titleCardStringWidth(lua_State *L) +{ + const char *str = luaL_checkstring(L, 1); + HUDONLY + + lua_pushinteger(L, V_TitleCardStringWidth(str)); + return 1; +} + static int libd_stringWidth(lua_State *L) { const char *str = luaL_checkstring(L, 1); @@ -1163,9 +1190,11 @@ static luaL_Reg lib_draw[] = { {"drawFill", libd_drawFill}, {"fadeScreen", libd_fadeScreen}, {"drawString", libd_drawString}, + {"drawTitleCardString", libd_drawTitleCardString}, {"drawKartString", libd_drawKartString}, // misc {"stringWidth", libd_stringWidth}, + {"titleCardStringWidth", libd_titleCardStringWidth}, // m_random {"RandomFixed",libd_RandomFixed}, {"RandomByte",libd_RandomByte}, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index a9e193543..d628b7016 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -128,7 +128,7 @@ static int lib_iterateDisplayplayers(lua_State *L) for (i++; i < MAXSPLITSCREENPLAYERS; i++) { - if (i > splitscreen || !playeringame[displayplayers[i]]) + if (i > r_splitscreen || !playeringame[displayplayers[i]]) return 0; // Stop! There are no more players for us to go through. There will never be a player gap in displayplayers. LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); @@ -147,7 +147,7 @@ static int lib_getDisplayplayers(lua_State *L) lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXSPLITSCREENPLAYERS) return luaL_error(L, "displayplayers[] index %d out of range (0 - %d)", i, MAXSPLITSCREENPLAYERS-1); - if (i > splitscreen) + if (i > r_splitscreen) return 0; if (!playeringame[displayplayers[i]]) return 0; diff --git a/src/lua_script.c b/src/lua_script.c index 6ef32daf9..94ba64767 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -178,7 +178,7 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushboolean(L, modeattacking); return 1; } else if (fastcmp(word,"splitscreen")) { - lua_pushboolean(L, splitscreen); + lua_pushinteger(L, splitscreen); return 1; } else if (fastcmp(word,"gamecomplete")) { lua_pushboolean(L, (gamecomplete != 0)); diff --git a/src/p_enemy.c b/src/p_enemy.c index 44d656cf0..9dbeb8f5b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -11044,7 +11044,7 @@ void A_FadeOverlay(mobj_t *actor) return; fade = P_SpawnGhostMobj(actor); - fade->frame = actor->frame; + fade->renderflags = actor->renderflags; if (!(locvar1 & 1)) { @@ -14650,4 +14650,4 @@ void A_InvincSparkleRotate(mobj_t *actor) actor->momz = actor->target->momz; // Give momentum for eventual interp builds idk. actor->angle += ANG1*10*(actor->extravalue2); // Arbitrary value, change this if you want, I suppose. -} \ No newline at end of file +} diff --git a/src/p_map.c b/src/p_map.c index 4a34ed7f0..829393d32 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1247,33 +1247,19 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // The bump has to happen last + if (P_IsObjectOnGround(thing) && tmthing->momz < 0 && tmthing->player->trickpanel) { - // The bump has to happen last - mobj_t *mo1 = tmthing; - mobj_t *mo2 = thing; - boolean zbounce = false; + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); + } + else if (P_IsObjectOnGround(tmthing) && thing->momz < 0 && thing->player->trickpanel) + { + P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); + } - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - { - zbounce = true; - mo1 = thing; - mo2 = tmthing; - - if (tmthing->player->trickpanel) - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); - } - else if (P_IsObjectOnGround(tmthing) && thing->momz < 0) - { - zbounce = true; - - if (thing->player->trickpanel) - P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); - } - - if (K_KartBouncing(mo1, mo2, zbounce, false)) - { - K_PvPTouchDamage(mo1, mo2); - } + if (K_KartBouncing(tmthing, thing) == true) + { + K_PvPTouchDamage(tmthing, thing); } return true; @@ -1300,8 +1286,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } else { - K_KartBouncing(tmthing, thing, false, true); - return false; + K_KartSolidBounce(tmthing, thing); + return true; } } else if (thing->type == MT_SMK_PIPE) @@ -1322,8 +1308,8 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // kill } - K_KartBouncing(tmthing, thing, false, true); - return false; + K_KartSolidBounce(tmthing, thing); + return true; } else if (thing->type == MT_SMK_THWOMP) { @@ -1362,12 +1348,13 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(tmthing, thing, thing, 1, DMG_TUMBLE); else { - if (thing->flags2 & MF2_AMBUSH) + if ((K_KartSolidBounce(tmthing, thing) == true) && (thing->flags2 & MF2_AMBUSH)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); - K_KartBouncing(tmthing, thing, false, true); + } } - return false; + return true; } else if (thing->type == MT_KART_LEFTOVER) { @@ -1377,12 +1364,8 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - K_KartBouncing(tmthing, thing, true, false); - else - K_KartBouncing(tmthing, thing, false, false); - - return false; + K_KartBouncing(tmthing, thing); + return true; } else if (thing->flags & MF_SOLID) { @@ -1392,12 +1375,8 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - K_KartBouncing(tmthing, thing, true, true); - else - K_KartBouncing(tmthing, thing, false, true); - - return false; + K_KartSolidBounce(tmthing, thing); + return true; } } @@ -2417,6 +2396,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t radius = thing->radius; fixed_t thingtop; fixed_t startingonground = P_IsObjectOnGround(thing); + fixed_t stairjank = 0; + pslope_t *oldslope = thing->standingslope; floatok = false; // reset this to 0 at the start of each trymove call as it's only used here @@ -2488,6 +2469,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (maxstep > 0) { + const boolean flipped = + (thing->eflags & MFE_VERTICALFLIP) != 0; + thingtop = thing->z + thing->height; // Step up @@ -2495,6 +2479,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { if (tmfloorstep <= maxstep) { + if (!flipped) + stairjank = tmfloorstep; + thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; @@ -2508,6 +2495,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { if (tmceilingstep <= maxstep) { + if (flipped) + stairjank = tmceilingstep; + thing->z = ( thing->ceilingz = tmceilingz ) - thing->height; thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; @@ -2524,6 +2514,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep) { + if (flipped) + stairjank = (tmceilingz - thingtop); + thing->z = (thing->ceilingz = tmceilingz) - thing->height; thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; @@ -2531,6 +2524,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep) { + if (!flipped) + stairjank = (thing->z - tmfloorz); + thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; @@ -2617,6 +2613,28 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) else // don't set standingslope if you're not going to clip against it thing->standingslope = NULL; + /* FIXME: slope step down (even up) has some false + positives, so just ignore them entirely. */ + if (stairjank && !oldslope && !thing->standingslope && + thing->player && !thing->player->spectator) + { + /* use a shorter sound if not two tics have passed + * since the last step */ + S_StartSound(thing, thing->player->stairjank + >= 16 ? sfx_s23b : sfx_s268); + + if (!thing->player->stairjank) + { + mobj_t * spark = P_SpawnMobjFromMobj(thing, + 0, 0, 0, MT_JANKSPARK); + spark->fuse = 9; + spark->cusval = K_StairJankFlip(ANGLE_90); + P_SetTarget(&spark->target, thing); + } + + thing->player->stairjank = 17; + } + thing->x = x; thing->y = y; diff --git a/src/p_mobj.c b/src/p_mobj.c index 8cccc7963..a63200f7f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4284,8 +4284,8 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) angle_t prevfa = (prevrot + mobj->friction) & FINEMASK; fa = (rot + mobj->friction) & FINEMASK; - if (!(prevfa > (FINEMASK/2)) && (fa > (FINEMASK/2))) // completed a full swing - dosound = true; + // completed a half-spin + dosound = ((prevfa > (FINEMASK/2)) != (fa > (FINEMASK/2))); unit_lengthways[0] = FixedMul(FINECOSINE(fa), radius); unit_lengthways[2] = FixedMul(FINESINE(fa), radius); @@ -6626,6 +6626,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->renderflags |= RF_DONTDRAW; } break; + case MT_JANKSPARK: + if (!mobj->target) + { + P_RemoveMobj(mobj); + return false; + } + if (mobj->fuse == 1 && mobj->target->player && + mobj->target->player->stairjank >= 8) + { + mobj->fuse = 9; + } + P_TeleportMove(mobj, mobj->target->x, + mobj->target->y, mobj->target->z); + mobj->angle = mobj->target->angle + mobj->cusval; + break; case MT_PLAYERRETICULE: if (!mobj->target || !mobj->target->health) { @@ -8477,17 +8492,29 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->type == MT_GHOST && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY! { - if (mobj->flags2 & MF2_BOSSNOTRAP) // "fast" flag + if (mobj->extravalue1 > 0) // Sonic Advance 2 mode { - if ((signed)((mobj->renderflags & RF_TRANSMASK) >> RF_TRANSSHIFT) < (NUMTRANSMAPS-1) - (2*mobj->fuse)/3) - // fade out when nearing the end of fuse... - mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK) | (((NUMTRANSMAPS-1) - (2*mobj->fuse)/3) << RF_TRANSSHIFT); + if (mobj->extravalue2 >= 2) + { + if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this. + mobj->renderflags ^= RF_DONTDRAW; + else + { + if (mobj->fuse == mobj->extravalue2) + mobj->renderflags &= ~RF_DONTDRAW; + else + mobj->renderflags |= RF_DONTDRAW; + } + } } else { - if ((signed)((mobj->renderflags & RF_TRANSMASK) >> RF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2) + INT32 dur = (mobj->flags2 & MF2_BOSSNOTRAP) + ? (2*mobj->fuse)/3 + : mobj->fuse/2; + if (((mobj->renderflags & RF_TRANSMASK) >> RF_TRANSSHIFT) < ((NUMTRANSMAPS-1) - dur)) // fade out when nearing the end of fuse... - mobj->renderflags = (mobj->frame & ~RF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << RF_TRANSSHIFT); + mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK) | (((NUMTRANSMAPS-1) - dur) << RF_TRANSSHIFT); } } @@ -8815,21 +8842,6 @@ void P_SceneryThinker(mobj_t *mobj) } } - // Sonic Advance 2 flashing afterimages - if (mobj->type == MT_GHOST && mobj->fuse > 0 - && mobj->extravalue1 > 0 && mobj->extravalue2 >= 2) - { - if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this. - mobj->renderflags ^= RF_DONTDRAW; - else - { - if (mobj->fuse == mobj->extravalue2) - mobj->renderflags &= ~RF_DONTDRAW; - else - mobj->renderflags |= RF_DONTDRAW; - } - } - // momentum movement if (mobj->momx || mobj->momy) { diff --git a/src/p_setup.c b/src/p_setup.c index 87bcc9595..654eb6eb1 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -659,9 +659,7 @@ flatfound: levelflat->u.flat.baselumpnum = LUMPERROR; } -#ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); -#endif return ( numlevelflats++ ); } @@ -3729,10 +3727,10 @@ static void P_InitCamera(void) { UINT8 i; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { - P_SetupCamera(i, &camera[i]); - displayplayers[i] = g_localplayers[i]; // Start with your OWN view, please! + //displayplayers[i] = g_localplayers[i]; // Start with your OWN view, please! + P_SetupCamera(displayplayers[i], &camera[i]); } } } @@ -3981,8 +3979,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) F_RunWipe(wipedefs[wipe_level_toblack], false, ((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), false, false); } - if (!titlemapinaction) - wipegamestate = GS_LEVEL; + /*if (!titlemapinaction) + wipegamestate = GS_LEVEL;*/ // Close text prompt before freeing the old level F_EndTextPrompt(false, true); diff --git a/src/p_slopes.c b/src/p_slopes.c index 1749e2369..d1e8f5f54 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -848,6 +848,11 @@ void P_SlopeLaunch(mobj_t *mo) //CONS_Printf("Launched off of slope.\n"); mo->standingslope = NULL; + + if (mo->player) + { + mo->player->stairjank = 0; // fuck you + } } // diff --git a/src/p_tick.c b/src/p_tick.c index 6157d0bda..5e92649cb 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -36,6 +36,11 @@ tic_t leveltime; +INT32 P_AltFlip(INT32 n, tic_t tics) +{ + return leveltime % (2 * tics) < tics ? n : -(n); +} + // // THINKERS // All thinkers should be allocated by Z_Calloc diff --git a/src/p_tick.h b/src/p_tick.h index 1fb88f3f2..e90f1be31 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -30,4 +30,8 @@ void P_DoTeamscrambling(void); void P_RemoveThinkerDelayed(thinker_t *thinker); //killed mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98 +// Negate the value for tics +INT32 P_AltFlip(INT32 value, tic_t tics); +#define P_RandomFlip(value) P_AltFlip(value, 1) + #endif diff --git a/src/p_user.c b/src/p_user.c index 18afb0337..fc04f5af8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1677,12 +1677,22 @@ static void P_3dMovement(player_t *player) // Get the old momentum; this will be needed at the end of the function! -SH oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); - if (player->drift != 0) - movepushangle = player->mo->angle-(ANGLE_45/5)*player->drift; - else if (player->spinouttimer || player->wipeoutslow) // if spun out, use the boost angle + if (player->stairjank > 8 && leveltime & 3) + { + movepushangle = K_MomentumAngle(player->mo); + } + else if (player->drift != 0) + { + movepushangle = player->mo->angle - (ANGLE_45/5) * player->drift; + } + else if (player->spinouttimer || player->wipeoutslow) // if spun out, use the boost angle + { movepushangle = (angle_t)player->boostangle; + } else + { movepushangle = player->mo->angle; + } // cmomx/cmomy stands for the conveyor belt speed. if (player->onconveyor == 2) // Wind/Current @@ -4486,14 +4496,19 @@ void P_PlayerThink(player_t *player) player->typing_duration = 0; } + if (player->stairjank > 0) + { + player->stairjank--; + } + K_KartPlayerThink(player, cmd); // SRB2kart DoABarrelRoll(player); - LUAh_PlayerThink(player); - if (player->carry == CR_SLIDING) player->carry = CR_NONE; + + LUAh_PlayerThink(player); } // diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index ad401d91d..096b678ea 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -15,6 +15,7 @@ #include "w_wad.h" #include "r_main.h" // R_PointToAngle #include "k_kart.h" // K_Sliptiding +#include "p_tick.h" #ifdef ROTSPRITE fixed_t rollcosang[ROTANGLES]; @@ -32,16 +33,14 @@ angle_t R_GetPitchRollAngle(mobj_t *mobj) return rollOrPitch; } -angle_t R_SpriteRotationAngle(mobj_t *mobj) +static angle_t R_PlayerSpriteRotation(player_t *player) { - angle_t viewingAngle = R_PointToAngle(mobj->x, mobj->y); - angle_t angleDelta = (viewingAngle - mobj->angle); + angle_t viewingAngle = R_PointToAngle(player->mo->x, player->mo->y); + angle_t angleDelta = (viewingAngle - player->mo->angle); - angle_t sliptideLift = mobj->player - ? mobj->player->aizdrifttilt : 0; + angle_t sliptideLift = player->aizdrifttilt; - angle_t rollOrPitch = R_GetPitchRollAngle(mobj); - angle_t rollAngle = (rollOrPitch + mobj->rollangle); + angle_t rollAngle = 0; if (sliptideLift) { @@ -52,6 +51,25 @@ angle_t R_SpriteRotationAngle(mobj_t *mobj) FixedMul(sliptideLift, FINECOSINE(angleDelta >> ANGLETOFINESHIFT)); } + if (player->stairjank) + { + rollAngle += K_StairJankFlip(ANGLE_11hh / 2 / + (17 / player->stairjank)); + } + + return rollAngle; +} + +angle_t R_SpriteRotationAngle(mobj_t *mobj) +{ + angle_t rollOrPitch = R_GetPitchRollAngle(mobj); + angle_t rollAngle = (rollOrPitch + mobj->rollangle); + + if (mobj->player) + { + rollAngle += R_PlayerSpriteRotation(mobj->player); + } + return rollAngle; } diff --git a/src/r_textures.c b/src/r_textures.c index e8d79981a..9716724b5 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -1611,9 +1611,7 @@ INT32 R_CheckTextureNumForName(const char *name) Z_Realloc(tidcache, tidcachelen * sizeof(*tidcache), PU_STATIC, &tidcache); strncpy(tidcache[tidcachelen-1].name, name, 8); tidcache[tidcachelen-1].name[8] = '\0'; -#ifndef ZDEBUG CONS_Debug(DBG_SETUP, "texture #%s: %s\n", sizeu1(tidcachelen), tidcache[tidcachelen-1].name); -#endif tidcache[tidcachelen-1].id = i; return i; } diff --git a/src/r_things.c b/src/r_things.c index bb848a679..ce62b0ad6 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -484,9 +484,7 @@ void R_AddSpriteDefs(UINT16 wadnum) #endif // if a new sprite was added (not just replaced) addsprites++; -#ifndef ZDEBUG CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum); -#endif } } diff --git a/src/sounds.c b/src/sounds.c index dc777a088..636b53a8c 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -87,7 +87,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"fire", false, 8, 32, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"grind", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic grinding"}, {"laser", true, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Laser hum"}, - {"mswing", false, 16, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging mace"}, + {"mswing", false, 16, 65, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging mace"}, {"pstart", false, 100, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, {"pstop", false, 100, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"}, {"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 @@ -630,8 +630,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kc7l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, // ditto {"s3kc8s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"}, {"s3kc8l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"}, // ditto - {"s3kc9s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"}, - {"s3kc9l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"}, // ditto + {"s3kc9s", false, 64, 65, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"}, + {"s3kc9l", false, 64, 65, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"}, // ditto {"s3kcas", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, {"s3kcal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, // ditto {"s3kcbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, @@ -837,6 +837,77 @@ sfxinfo_t S_sfx[NUMSFX] = {"kc6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // Mean Bean Machine sounds + {"mbs41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs6a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs70", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbs72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv81", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv82", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv83", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv84", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv85", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv86", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv87", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv88", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"mbv97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // SRB2kart {"slip", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Spinout {"screec", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Tight turning screech diff --git a/src/sounds.h b/src/sounds.h index 51155c7c3..ac7d5b9cf 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -901,6 +901,77 @@ typedef enum sfx_kc6d, sfx_kc6e, + // Mean Bean Machine sounds + sfx_mbs41, + sfx_mbs42, + sfx_mbs43, + sfx_mbs44, + sfx_mbs45, + sfx_mbs46, + sfx_mbs47, + sfx_mbs48, + sfx_mbs49, + sfx_mbs4a, + sfx_mbs4b, + sfx_mbs4c, + sfx_mbs4d, + sfx_mbs4e, + sfx_mbs4f, + sfx_mbs50, + sfx_mbs51, + sfx_mbs52, + sfx_mbs53, + sfx_mbs54, + sfx_mbs55, + sfx_mbs56, + sfx_mbs57, + sfx_mbs58, + sfx_mbs59, + sfx_mbs5a, + sfx_mbs5b, + sfx_mbs5c, + sfx_mbs5d, + sfx_mbs5e, + sfx_mbs5f, + sfx_mbs60, + sfx_mbs61, + sfx_mbs62, + sfx_mbs63, + sfx_mbs64, + sfx_mbs67, + sfx_mbs68, + sfx_mbs69, + sfx_mbs6a, + sfx_mbs6b, + sfx_mbs6d, + sfx_mbs6e, + sfx_mbs70, + sfx_mbs71, + sfx_mbs72, + sfx_mbv81, + sfx_mbv82, + sfx_mbv83, + sfx_mbv84, + sfx_mbv85, + sfx_mbv86, + sfx_mbv87, + sfx_mbv88, + sfx_mbv89, + sfx_mbv8a, + sfx_mbv8b, + sfx_mbv8c, + sfx_mbv8d, + sfx_mbv8e, + sfx_mbv8f, + sfx_mbv90, + sfx_mbv91, + sfx_mbv92, + sfx_mbv93, + sfx_mbv94, + sfx_mbv95, + sfx_mbv96, + sfx_mbv97, + // SRB2kart sfx_slip, sfx_screec, diff --git a/src/st_stuff.c b/src/st_stuff.c index 16118cbee..ee03a07a4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -31,6 +31,7 @@ #include "m_misc.h" // moviemode #include "m_anigif.h" // cv_gif_downscale #include "p_setup.h" // NiGHTS grading +#include "k_grandprix.h" // we need to know grandprix status for titlecards //random index #include "m_random.h" @@ -622,23 +623,97 @@ static void ST_drawDebugInfo(void) V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } -static patch_t *lt_patches[3]; -static INT32 lt_scroll = 0; -static INT32 lt_mom = 0; -static INT32 lt_zigzag = 0; - tic_t lt_ticker = 0, lt_lasttic = 0; tic_t lt_exitticker = 0, lt_endtime = 0; +// SRB2KART: HUD shit for new titlecards: +static patch_t *tcchev1; +static patch_t *tcchev2; + +static patch_t *tcol1; +static patch_t *tcol2; + +static patch_t *tcroundbar; +static patch_t *tcround; + +static patch_t *tccircletop; +static patch_t *tccirclebottom; +static patch_t *tccirclebg; + +static patch_t *tcbanner; +static patch_t *tcbanner2; + +static patch_t *tcroundnum[10]; +static patch_t *tcactnum[10]; +static patch_t *tcact; + +// some coordinates define to make my life easier.... +#define FINAL_ROUNDX (24) +#define FINAL_EGGY (160) +#define FINAL_ROUNDY (16) +#define FINAL_BANNERY (160) + +INT32 chev1x, chev1y, chev2x, chev2y, chevtflag; +INT32 roundx, roundy; +INT32 bannerx, bannery; + +INT32 roundnumx, roundnumy; +INT32 eggx1, eggx2, eggy1, eggy2; + +// These are all arbitrary values found by trial and error trying to align the hud lmao. +// But they'll work. +#define BASE_CHEV1X (252) +#define BASE_CHEV1Y (60) +#define BASE_CHEV2X (65) +#define BASE_CHEV2Y (135) + +#define TTANIMTHRESHOLD (TICRATE) +#define TTANIMSTART (TTANIMTHRESHOLD-16) +#define TTANIMENDTHRESHOLD (TICRATE*3) +#define TTANIMEND (TICRATE*4) + // // Load the graphics for the title card. // Don't let LJ see this // static void ST_cacheLevelTitle(void) { - lt_patches[0] = (patch_t *)W_CachePatchName("LTACTBLU", PU_HUDGFX); - lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGZAG", PU_HUDGFX); - lt_patches[2] = (patch_t *)W_CachePatchName("LTZZTEXT", PU_HUDGFX); + UINT8 i; + char buf[9]; + + // SRB2KART + tcchev1 = (patch_t *)W_CachePatchName("TCCHEV1W", PU_HUDGFX); + tcchev2 = (patch_t *)W_CachePatchName("TCCHEV2W", PU_HUDGFX); + + tcol1 = (patch_t *)W_CachePatchName("TCCHOL1", PU_HUDGFX); + tcol2 = (patch_t *)W_CachePatchName("TCCHOL2", PU_HUDGFX); + + tcroundbar = (patch_t *)W_CachePatchName("TCBB0", PU_HUDGFX); + tcround = (patch_t *)W_CachePatchName("TCROUND", PU_HUDGFX); + + tccircletop = (patch_t *)W_CachePatchName("TCSN1", PU_HUDGFX); + tccirclebottom =(patch_t *)W_CachePatchName("TCSN2", PU_HUDGFX); + tccirclebg = (patch_t *)W_CachePatchName("TCEG3", PU_HUDGFX); + + tcbanner = (patch_t *)W_CachePatchName("TCBSKA0", PU_HUDGFX); + tcbanner2 = (patch_t *)W_CachePatchName("TCBC0", PU_HUDGFX); + + tcact = (patch_t *)W_CachePatchName("TT_ACT", PU_HUDGFX); + + // Cache round # + for (i=1; i < 11; i++) + { + sprintf(buf, "TT_RND%d", i); + tcroundnum[i-1] = (patch_t *)W_CachePatchName(buf, PU_HUDGFX); + } + + // Cache act # + for (i=0; i < 10; i++) + { + sprintf(buf, "TT_ACT%d", i); + tcactnum[i] = (patch_t *)W_CachePatchName(buf, PU_HUDGFX); + } + } // @@ -649,12 +724,28 @@ void ST_startTitleCard(void) // cache every HUD patch used ST_cacheLevelTitle(); + // Set most elements to start off-screen, ST_runTitleCard will have them slide in afterwards + chev1x = BASE_CHEV1X +350; // start off-screen + chev1y = BASE_CHEV1Y; + chev2x = BASE_CHEV2X -350; // start off-screen + chev2y = BASE_CHEV2Y; + chevtflag = 0; + + roundx = -999; + roundy = -999; + + roundnumx = -999; + roundnumy = -999; + eggx1 = -999; + eggx2 = -999; + eggy1 = -999; + eggy2 = -999; + + bannery = 300; + // initialize HUD variables lt_ticker = lt_exitticker = lt_lasttic = 0; - lt_endtime = 2*TICRATE + (10*NEWTICRATERATIO); - lt_scroll = BASEVIDWIDTH * FRACUNIT; - lt_zigzag = -((lt_patches[1])->width * FRACUNIT); - lt_mom = 0; + lt_endtime = 4*TICRATE; // + (10*NEWTICRATERATIO); } // @@ -679,6 +770,8 @@ void ST_preDrawTitleCard(void) void ST_runTitleCard(void) { boolean run = !(paused || P_AutoPause()); + INT32 auxticker; + boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum); // check whether we're in grandprix if (!G_IsTitleCardAvailable()) return; @@ -690,35 +783,137 @@ void ST_runTitleCard(void) { // tick lt_ticker++; + + // SRB2KART + // side Zig-Zag positions... + + // TITLECARD START + if (lt_ticker < TTANIMSTART) + { + chev1x = max(BASE_CHEV1X, (BASE_CHEV1X +350) - (INT32)(lt_ticker)*50); + chev2x = min(BASE_CHEV2X, (BASE_CHEV2X -350) + (INT32)(lt_ticker)*50); + } + + // OPEN ZIG-ZAGS 1 SECOND IN + if (lt_ticker > TTANIMTHRESHOLD) + { + auxticker = (INT32)(lt_ticker) - TTANIMTHRESHOLD; + + chev1x = min(320, BASE_CHEV1X + auxticker*16); + chev1y = max(0, BASE_CHEV1Y - auxticker*16); + + chev2x = max(0, BASE_CHEV2X - auxticker*16); + chev2y = min(200, BASE_CHEV2Y + auxticker*16); + + // translucent fade after opening up. + chevtflag = min(5, ((auxticker)/5)) << V_ALPHASHIFT; + + + // OPEN ZIG-ZAG: END OF ANIMATION (they leave the screen borders) + if (lt_ticker > TTANIMENDTHRESHOLD) + { + auxticker = (INT32)lt_ticker - TTANIMENDTHRESHOLD; + + chev1x += auxticker*16; + chev1y -= auxticker*16; + + chev2x -= auxticker*16; + chev2y += auxticker*16; + } + } + + // ROUND BAR + EGG + + eggy1 = FINAL_EGGY; // Make sure to reset that each call so that Y position doesn't go bonkers + + // SLIDE BAR IN, SLIDE "ROUND" DOWNWARDS + if (lt_ticker <= TTANIMTHRESHOLD) + { + INT32 interptimer = (INT32)lt_ticker - TTANIMSTART; + // INT32 because tic_t is unsigned and we want this to be potentially negative + + if (interptimer >= 0) + { + INT32 interpdiff = ((TTANIMTHRESHOLD-TTANIMSTART) - interptimer); + interpdiff *= interpdiff; // interpdiff^2 + + roundx = FINAL_ROUNDX - interpdiff; + roundy = FINAL_ROUNDY - interpdiff; + eggy1 = FINAL_EGGY + interpdiff; + + } + } + // SLIDE BAR OUT, SLIDE "ROUND" DOWNWARDS FASTER + else if (lt_ticker >= TTANIMENDTHRESHOLD) + { + auxticker = (INT32)lt_ticker - TTANIMENDTHRESHOLD; + + roundx = FINAL_ROUNDX - auxticker*24; + roundy = FINAL_ROUNDY + auxticker*48; + eggy1 = FINAL_EGGY + auxticker*48; + } + + // follow the round bar. + eggx1 = roundx + tcroundbar->width/2; + + // initially, both halves are on the same coordinates. + eggx2 = eggx1; + eggy2 = eggy1; + // same for the background (duh) + roundnumx = eggx1; + roundnumy = eggy1; + + // split both halves of the egg, but only do that in grand prix! + if (gp && lt_ticker > TTANIMTHRESHOLD + TICRATE/2) + { + auxticker = (INT32)lt_ticker - (TTANIMTHRESHOLD + TICRATE/2); + + eggx1 -= auxticker*12; + eggy1 -= auxticker*12; + + eggx2 += auxticker*12; + eggy2 += auxticker*12; + + } + + + // SCROLLING BOTTOM BANNER + + // SLIDE BANNER UPWARDS WITH A FUNNY BOUNCE (this requires trig :death:) + if (lt_ticker < TTANIMTHRESHOLD) + { + INT32 costimer = (INT32)lt_ticker - TTANIMSTART; + // INT32 because tic_t is unsigned and we want this to be potentially negative + + if (costimer > 0) + { + // For this animation, we're going to do a tiny bit of stupid trigonometry. + // Admittedly all of this is going to look like magic numbers, and honestly? They are. + + // start at angle 355 (where y = ~230 with our params) + // and go to angle 131 (where y = ~160 with our params) + + UINT8 basey = 190; + UINT8 amplitude = 45; + fixed_t ang = (355 - costimer*14)*FRACUNIT; + + bannery = basey + (amplitude * FINECOSINE(FixedAngle(ang)>>ANGLETOFINESHIFT)) / FRACUNIT; + } + } + // SLIDE BANNER DOWNWARDS OUT OF THE SCREEN AT THE END + else if (lt_ticker >= TTANIMENDTHRESHOLD) + { + auxticker = (INT32)lt_ticker - TTANIMENDTHRESHOLD; + bannery = FINAL_BANNERY + auxticker*16; + } + + // No matter the circumstances, scroll the banner... + bannerx = -(lt_ticker%(tcbanner->width)); + + + // used for hud slidein if (lt_ticker >= lt_endtime) lt_exitticker++; - - // scroll to screen (level title) - if (!lt_exitticker) - { - if (abs(lt_scroll) > FRACUNIT) - lt_scroll -= (lt_scroll>>2); - else - lt_scroll = 0; - } - // scroll away from screen (level title) - else - { - lt_mom -= FRACUNIT*6; - lt_scroll += lt_mom; - } - - // scroll to screen (zigzag) - if (!lt_exitticker) - { - if (abs(lt_zigzag) > FRACUNIT) - lt_zigzag -= (lt_zigzag>>2); - else - lt_zigzag = 0; - } - // scroll away from screen (zigzag) - else - lt_zigzag += lt_mom; } } @@ -729,25 +924,17 @@ void ST_runTitleCard(void) void ST_drawTitleCard(void) { char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; - char *subttl = mapheaderinfo[gamemap-1]->subttl; char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; - INT32 lvlttlxpos, ttlnumxpos, zonexpos; - INT32 subttlxpos = BASEVIDWIDTH/2; - INT32 ttlscroll = FixedInt(lt_scroll); -#ifdef TITLEPATCHES - INT32 zzticker; - patch_t *actpat, *zigzag, *zztext; - UINT8 colornum; - const UINT8 *colormap; + boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum); - if (players[g_localplayers[0]].skincolor) - colornum = players[g_localplayers[0]].skincolor; - else - colornum = cv_playercolor[0].value; + INT32 acttimer; + fixed_t actscale; + angle_t fakeangle; - colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); -#endif + INT32 bx = bannerx; // We need to make a copy of that otherwise pausing will cause problems. + + UINT8 i; if (!G_IsTitleCardAvailable()) return; @@ -761,95 +948,118 @@ void ST_drawTitleCard(void) if ((lt_ticker-lt_lasttic) > 1) lt_ticker = lt_lasttic+1; - ST_cacheLevelTitle(); + // Avoid HOMs while drawing the start of the titlecard + if (lt_ticker < TTANIMSTART) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); -#ifdef TITLEPATCHES - actpat = lt_patches[0]; - zigzag = lt_patches[1]; - zztext = lt_patches[2]; -#endif + // Background zig-zags + V_DrawFixedPatch((chev1x)*FRACUNIT, (chev1y)*FRACUNIT, FRACUNIT, chevtflag, tcchev1, NULL); + V_DrawFixedPatch((chev2x)*FRACUNIT, (chev2y)*FRACUNIT, FRACUNIT, chevtflag, tcchev2, NULL); - lvlttlxpos = ((BASEVIDWIDTH/2) - (V_LevelNameWidth(lvlttl)/2)); - if (actnum > 0) - lvlttlxpos -= V_LevelNameWidth(va("%d", actnum)); + // Draw ROUND bar, scroll it downwards. + V_DrawFixedPatch(roundx*FRACUNIT, ((-32) + (lt_ticker%32))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcroundbar, NULL); + // Draw ROUND text + if (gp) + V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcround, NULL); - zonexpos = ttlnumxpos = lvlttlxpos + V_LevelNameWidth(lvlttl); - if (zonttl[0]) - zonexpos -= V_LevelNameWidth(zonttl); // SRB2kart - else - zonexpos -= V_LevelNameWidth(M_GetText("Zone")); + // round num background + V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccirclebg, NULL); - ttlnumxpos++; - - if (lvlttlxpos < 0) - lvlttlxpos = 0; - -#ifdef TITLEPATCHES - if (!splitscreen || (splitscreen && stplyr == &players[displayplayers[0]])) + // Scrolling banner, we'll draw 3 of those back to back. + for (i=0; i < 3; i++) { - zzticker = lt_ticker; - V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (-zigzag->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); + V_DrawFixedPatch((bannerx + bx)*FRACUNIT, (bannery)*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tcbanner, NULL); + bx += tcbanner->width; } -#endif - if (actnum) + // If possible, draw round number + if (gp && grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE. + V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tcroundnum[grandprixinfo.roundnum-1], NULL); + + // Draw both halves of the egg + V_DrawFixedPatch(eggx1*FRACUNIT, eggy1*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccircletop, NULL); + V_DrawFixedPatch(eggx2*FRACUNIT, eggy2*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccirclebottom, NULL); + + // Now the level name. + V_DrawTitleCardString((actnum) ? 265 : 280, 60, lvlttl, V_SNAPTORIGHT, true, lt_ticker, TTANIMENDTHRESHOLD); + + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + V_DrawTitleCardString((actnum) ? 265 : 280, 60+32, strlen(zonttl) ? zonttl : "ZONE", V_SNAPTORIGHT, true, lt_ticker - strlen(lvlttl), TTANIMENDTHRESHOLD); + + // the act has a similar graphic animation, but we'll handle it here since it's only like 2 graphics lmfao. + if (actnum && actnum < 10) { -#ifdef TITLEPATCHES - if (!splitscreen) + + // compute delay before the act should appear. + acttimer = lt_ticker - strlen(lvlttl); + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + acttimer -= strlen((strlen(zonttl)) ? (zonttl) : ("ZONE")); + + actscale = 0; + fakeangle = 0; + + if (acttimer >= 0) { - if (actnum > 9) // slightly offset the act diamond for two-digit act numbers - V_DrawMappedPatch(ttlnumxpos + (V_LevelNameWidth(va("%d", actnum))/4) + ttlscroll, 104 - ttlscroll, 0, actpat, colormap); - else - V_DrawMappedPatch(ttlnumxpos + ttlscroll, 104 - ttlscroll, 0, actpat, colormap); - } -#endif - V_DrawLevelTitle(ttlnumxpos + ttlscroll, 104, 0, va("%d", actnum)); - } - V_DrawLevelTitle(lvlttlxpos - ttlscroll, 80, 0, lvlttl); - if (zonttl[0]) - V_DrawLevelTitle(zonexpos + ttlscroll, 104, 0, zonttl); - else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - V_DrawLevelTitle(zonexpos + ttlscroll, 104, 0, M_GetText("Zone")); - V_DrawCenteredString(subttlxpos - ttlscroll, 135, 0|V_ALLOWLOWERCASE, subttl); + if (acttimer < TTANIMENDTHRESHOLD) // spin in + { + fakeangle = min(360 + 90, acttimer*41) * ANG1; + actscale = FINESINE(fakeangle>>ANGLETOFINESHIFT); + } + else // spin out + { + // Make letters disappear... + acttimer -= TTANIMENDTHRESHOLD; + + fakeangle = max(0, (360+90) - acttimer*41)*ANG1; + actscale = FINESINE(fakeangle>>ANGLETOFINESHIFT); + } + + if (actscale) + { + // draw the top: + V_DrawStretchyFixedPatch(286*FRACUNIT, 76*FRACUNIT, abs(actscale), FRACUNIT, V_SNAPTORIGHT|(actscale < 0 ? V_FLIP : 0), tcact, NULL); + V_DrawStretchyFixedPatch(286*FRACUNIT, 123*FRACUNIT, abs(actscale), FRACUNIT, V_SNAPTORIGHT|(actscale < 0 ? V_FLIP : 0), tcactnum[actnum], NULL); + } + } + } lt_lasttic = lt_ticker; luahook: LUAh_TitleCardHUD(stplyr); + } +// Clear defined coordinates, we don't need them anymore +#undef FINAL_ROUNDX +#undef FINAL_EGGY +#undef FINAL_ROUNDY +#undef FINAL_BANNERY + +#undef BASE_CHEV1X +#undef BASE_CHEV1Y +#undef BASE_CHEV2X +#undef BASE_CHEV2Y + +#undef TTANIMTHRESHOLD +#undef TTANIMSTART +#undef TTANIMENDTHRESHOLD +#undef TTANIMEND + // // Drawer for G_PreLevelTitleCard. // void ST_preLevelTitleCardDrawer(void) { V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - ST_drawWipeTitleCard(); + + ST_drawTitleCard(); I_OsPolling(); I_UpdateNoBlit(); } -// -// Draw the title card while on a wipe. -// Also used in G_PreLevelTitleCard. -// -void ST_drawWipeTitleCard(void) -{ - UINT8 i; - - for (i = 0; i <= r_splitscreen; i++) - { - stplyr = &players[displayplayers[i]]; - ST_preDrawTitleCard(); - ST_drawTitleCard(); - } -} - // // Draw the status bar overlay, customisable: the user chooses which // kind of information to overlay diff --git a/src/st_stuff.h b/src/st_stuff.h index cc771c053..a17f72c1f 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -64,7 +64,6 @@ void ST_runTitleCard(void); void ST_drawTitleCard(void); void ST_preDrawTitleCard(void); void ST_preLevelTitleCardDrawer(void); -void ST_drawWipeTitleCard(void); extern tic_t lt_ticker, lt_lasttic; extern tic_t lt_exitticker, lt_endtime; diff --git a/src/v_video.c b/src/v_video.c index 85adeb4eb..5bd7ba733 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1676,6 +1676,149 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/2, flags, fontv[HU_FONT].font[c], colormap); } +// V_TitleCardStringWidth +// Get the string's width using the titlecard font. +INT32 V_TitleCardStringWidth(const char *str) +{ + INT32 xoffs = 0; + const char *ch = str; + char c; + patch_t *pp; + + for (;;ch++) + { + if (!*ch) + break; + + if (*ch == '\n') + { + xoffs = 0; + continue; + } + + c = *ch; + c = toupper(c); + c -= LT_FONTSTART; + + // check if character exists, if not, it's a space. + if (c < 0 || c >= LT_FONTSIZE || !tc_font[0][(INT32)c]) + { + xoffs += 10; + continue; + } + + pp = tc_font[1][(INT32)c]; + + xoffs += pp->width-5; + } + + return xoffs; +} + +// V_DrawTitleCardScreen. +// see v_video.h's prototype for more information. +// +void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean alignright, INT32 timer, INT32 threshold) +{ + + INT32 xoffs = 0; + INT32 yoffs = 0; + INT32 i = 0; + + // per-letter variables + fixed_t scalex; + fixed_t offs; + INT32 let_time; + INT32 flipflag; + angle_t fakeang; + + const char *ch = str; + char c; + patch_t *pp; + patch_t *ol; + + x -= 2; // Account for patch width... + + if (alignright) + x -= V_TitleCardStringWidth(str); + + + for (;;ch++, i++) + { + + scalex = FRACUNIT; + offs = 0; + let_time = timer - i; + flipflag = 0; + + if (!*ch) + break; + + if (*ch == '\n') + { + xoffs = x; + yoffs += 32; + + continue; + } + + c = *ch; + + c = toupper(c); + c -= LT_FONTSTART; + + // check if character exists, if not, it's a space. + if (c < 0 || c >= LT_FONTSIZE || !tc_font[1][(INT32)c]) + { + xoffs += 10; + continue; + } + + ol = tc_font[0][(INT32)c]; + pp = tc_font[1][(INT32)c]; + + if (timer) + { + + // make letters appear + if (!threshold || let_time < threshold) + { + if (let_time <= 0) + return; // No reason to continue drawing, none of the next letters will be drawn either. + + // otherwise; scalex must start at 0 + // let's have each letter do 4 spins (360*4 + 90 = 1530 "degrees") + fakeang = min(360 + 90, let_time*41) * ANG1; + scalex = FINESINE(fakeang>>ANGLETOFINESHIFT); + } + else if (let_time > threshold) + { + // Make letters disappear... + let_time -= threshold; + + fakeang = max(0, (360+90) - let_time*41)*ANG1; + scalex = FINESINE(fakeang>>ANGLETOFINESHIFT); + } + + // Because of how our patches are offset, we need to counter the displacement caused by changing the scale with an offset of our own. + offs = ((FRACUNIT-scalex)*pp->width)/2; + } + + // And now, we just need to draw the stuff. + flipflag = (scalex < 0) ? V_FLIP : 0; + + if (scalex && ol && pp) + { + //CONS_Printf("%d\n", (INT32)c); + V_DrawStretchyFixedPatch((x + xoffs)*FRACUNIT + offs, (y+yoffs)*FRACUNIT, abs(scalex), FRACUNIT, flags|flipflag, ol, NULL); + V_DrawStretchyFixedPatch((x + xoffs)*FRACUNIT + offs, (y+yoffs)*FRACUNIT, abs(scalex), FRACUNIT, flags|flipflag, pp, NULL); + } + + xoffs += pp->width -5; + } +} + + // Precompile a wordwrapped string to any given width. // This is a muuuch better method than V_WORDWRAP. char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) diff --git a/src/v_video.h b/src/v_video.h index 08a279fd0..da4506c9a 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -262,6 +262,16 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st #define V_DrawThinStringAtFixed( x,y,option,string ) \ V__DrawOneScaleString (x,y,FRACUNIT,option,TINY_FONT,string) +// Draws a titlecard font string. +// timer: when the letters start appearing (leave to 0 to disable) +// threshold: when the letters start disappearing (leave to 0 to disable) (both are INT32 in case you supply negative values...) +// NOTE: This function ignores most conventional string flags (V_RETURN8, V_ALLOWLOWERCASE ...) +// NOTE: This font only works with uppercase letters. +void V_DrawTitleCardString(INT32 x, INT32 y, const char *str, INT32 flags, boolean alignright, INT32 timer, INT32 threshold); + +// returns thr width of a string drawn using the above function. +INT32 V_TitleCardStringWidth(const char *str); + // Draw tall nums, used for menu, HUD, intermission void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num); void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits); diff --git a/src/z_zone.c b/src/z_zone.c index d7da17e51..3a541f3a6 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -47,10 +47,6 @@ static boolean Z_calloc = false; #define ZONEID 0xa441d13d -#ifdef ZDEBUG -//#define ZDEBUG2 -#endif - struct memblock_s; typedef struct @@ -76,10 +72,8 @@ typedef struct memblock_s size_t size; // including the header and blocks size_t realsize; // size of real data only -#ifdef ZDEBUG const char *ownerfile; INT32 ownerline; -#endif struct memblock_s *next, *prev; } ATTRPACK memblock_t; @@ -91,9 +85,7 @@ static memblock_t head; // Function prototypes // static void Command_Memfree_f(void); -#ifdef ZDEBUG static void Command_Memdump_f(void); -#endif // -------------------------- // Zone memory initialisation @@ -117,10 +109,7 @@ void Z_Init(void) // Note: This allocates memory. Watch out. COM_AddCommand("memfree", Command_Memfree_f); - -#ifdef ZDEBUG COM_AddCommand("memdump", Command_Memdump_f); -#endif } @@ -137,12 +126,8 @@ void Z_Init(void) * \return A pointer to the memblock_t for the given memory. * \sa Z_Free, Z_ReallocAlign */ -#ifdef ZDEBUG #define Ptr2Memblock(s, f) Ptr2Memblock2(s, f, __FILE__, __LINE__) static memblock_t *Ptr2Memblock2(void *ptr, const char* func, const char *file, INT32 line) -#else -static memblock_t *Ptr2Memblock(void *ptr, const char* func) -#endif { memhdr_t *hdr; memblock_t *block; @@ -150,8 +135,8 @@ static memblock_t *Ptr2Memblock(void *ptr, const char* func) if (ptr == NULL) return NULL; -#ifdef ZDEBUG2 - CONS_Printf("%s %s:%d\n", func, file, line); +#ifdef ZDEBUG + CONS_Debug(DBG_MEMORY, "%s %s:%d\n", func, file, line); #endif hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); @@ -163,20 +148,12 @@ static memblock_t *Ptr2Memblock(void *ptr, const char* func) #ifdef VALGRIND_MEMPOOL_EXISTS if (!VALGRIND_MEMPOOL_EXISTS(hdr->block)) { -#ifdef ZDEBUG I_Error("%s: bad memblock from %s:%d", func, file, line); -#else - I_Error("%s: bad memblock", func); -#endif } #endif if (hdr->id != ZONEID) { -#ifdef ZDEBUG I_Error("%s: wrong id from %s:%d", func, file, line); -#else - I_Error("%s: wrong id", func); -#endif } block = hdr->block; #ifdef VALGRIND_MAKE_MEM_NOACCESS @@ -192,31 +169,24 @@ static memblock_t *Ptr2Memblock(void *ptr, const char* func) * assumed to have been allocated with Z_Malloc/Z_Calloc. * \sa Z_FreeTags */ -#ifdef ZDEBUG void Z_Free2(void *ptr, const char *file, INT32 line) -#else -void Z_Free(void *ptr) -#endif { memblock_t *block; if (ptr == NULL) return; -#ifdef ZDEBUG2 +/* +// Sal: There's a print exactly like this just below? +#ifdef ZDEBUG CONS_Debug(DBG_MEMORY, "Z_Free %s:%d\n", file, line); #endif +*/ -#ifdef ZDEBUG block = Ptr2Memblock2(ptr, "Z_Free", file, line); -#else - block = Ptr2Memblock(ptr, "Z_Free"); -#endif -#ifdef ZDEBUG // Write every Z_Free call to a debug file. CONS_Debug(DBG_MEMORY, "Z_Free at %s:%d\n", file, line); -#endif // anything that isn't by lua gets passed to lua just in case. if (block->tag != PU_LUA) @@ -280,12 +250,8 @@ static void *xm(size_t size) * \note You can pass Z_Malloc() a NULL user if the tag is less than PU_PURGELEVEL. * \sa Z_CallocAlign, Z_ReallocAlign */ -#ifdef ZDEBUG void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) -#else -void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) -#endif { size_t extrabytes = (1<hdr = hdr; block->tag = tag; block->user = NULL; -#ifdef ZDEBUG block->ownerline = line; block->ownerfile = file; -#endif block->size = blocksize; block->realsize = size; @@ -375,20 +339,12 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) * \note You can pass Z_Calloc() a NULL user if the tag is less than PU_PURGELEVEL. * \sa Z_MallocAlign, Z_ReallocAlign */ -#ifdef ZDEBUG void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) -#else -void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) -#endif { #ifdef VALGRIND_MEMPOOL_ALLOC Z_calloc = true; #endif -#ifdef ZDEBUG return memset(Z_Malloc2 (size, tag, user, alignbits, file, line), 0, size); -#else - return memset(Z_MallocAlign(size, tag, user, alignbits ), 0, size); -#endif } /** The Z_ReallocAlign function. @@ -407,17 +363,13 @@ void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) * \note You can pass Z_Realloc() a NULL user if the tag is less than PU_PURGELEVEL. * \sa Z_MallocAlign, Z_CallocAlign */ -#ifdef ZDEBUG void *Z_Realloc2(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) -#else -void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits) -#endif { void *rez; memblock_t *block; size_t copysize; -#ifdef ZDEBUG2 +#ifdef ZDEBUG CONS_Debug(DBG_MEMORY, "Z_Realloc %s:%d\n", file, line); #endif @@ -429,29 +381,17 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb if (!ptr) { -#ifdef ZDEBUG return Z_Calloc2(size, tag, user, alignbits, file , line); -#else - return Z_CallocAlign(size, tag, user, alignbits); -#endif } -#ifdef ZDEBUG block = Ptr2Memblock2(ptr, "Z_Realloc", file, line); -#else - block = Ptr2Memblock(ptr, "Z_Realloc"); -#endif if (block == NULL) return NULL; -#ifdef ZDEBUG // Write every Z_Realloc call to a debug file. DEBFILE(va("Z_Realloc at %s:%d\n", file, line)); rez = Z_Malloc2(size, tag, user, alignbits, file, line); -#else - rez = Z_MallocAlign(size, tag, user, alignbits); -#endif if (size < block->realsize) copysize = size; @@ -460,11 +400,7 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb M_Memcpy(rez, ptr, copysize); -#ifdef ZDEBUG Z_Free2(ptr, file, line); -#else - Z_Free(ptr); -#endif // Need to set the user in case the old block had the same one, in // which case the Z_Free will just have NULLed it out. @@ -569,7 +505,7 @@ void Z_CheckHeap(INT32 i) blocknumon++; hdr = block->hdr; given = (UINT8 *)hdr + sizeof *hdr; -#ifdef ZDEBUG2 +#ifdef ZDEBUG CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n", blocknumon, block->ownerfile, block->ownerline); #endif @@ -577,51 +513,35 @@ void Z_CheckHeap(INT32 i) if (!VALGRIND_MEMPOOL_EXISTS(block)) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif - " should not exist", i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + " should not exist", i, blocknumon, + block->ownerfile, block->ownerline + ); } #endif if (block->user != NULL && *(block->user) != given) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif - " doesn't have a proper user", i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + " doesn't have a proper user", i, blocknumon, + block->ownerfile, block->ownerline + ); } if (block->next->prev != block) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif - " lacks proper backlink", i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + " lacks proper backlink", i, blocknumon, + block->ownerfile, block->ownerline + ); } if (block->prev->next != block) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif - " lacks proper forward link", i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + " lacks proper forward link", i, blocknumon, + block->ownerfile, block->ownerline + ); } #ifdef VALGRIND_MAKE_MEM_DEFINED VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); @@ -629,27 +549,19 @@ void Z_CheckHeap(INT32 i) if (hdr->block != block) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif " doesn't have linkback from allocated memory", - i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + i, blocknumon, + block->ownerfile, block->ownerline + ); } if (hdr->id != ZONEID) { I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG "(owned by %s:%d)" -#endif - " have the wrong ID", i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); + " have the wrong ID", i, blocknumon, + block->ownerfile, block->ownerline + ); } #ifdef VALGRIND_MAKE_MEM_NOACCESS VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); @@ -828,11 +740,9 @@ static void Command_Memfree_f(void) CONS_Printf(M_GetText("Available physical memory: %7u KB\n"), freebytes>>10); } -#ifdef ZDEBUG /** The function called by the "memdump" console command. * Prints zone memory debugging information (i.e. tag, size, location in code allocated). * Can be all memory allocated in game, or between a set of tags (if -min/-max args used). - * This command is available only if ZDEBUG is enabled. */ static void Command_Memdump_f(void) { @@ -853,7 +763,6 @@ static void Command_Memdump_f(void) CONS_Printf("[%3d] %s (%s) bytes @ %s:%d\n", block->tag, sizeu1(block->size), sizeu2(block->realsize), filename ? filename + 1 : block->ownerfile, block->ownerline); } } -#endif /** Creates a copy of a string. * diff --git a/src/z_zone.h b/src/z_zone.h index 049a39475..94cf244cf 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -79,12 +79,8 @@ void Z_Init(void); // // Zone memory allocation // -// enable ZDEBUG to get the file + line the functions were called from -// for ZZ_Alloc, see doomdef.h -// // Z_Free and alloc with alignment -#ifdef ZDEBUG #define Z_Free(p) Z_Free2(p, __FILE__, __LINE__) #define Z_MallocAlign(s,t,u,a) Z_Malloc2(s, t, u, a, __FILE__, __LINE__) #define Z_CallocAlign(s,t,u,a) Z_Calloc2(s, t, u, a, __FILE__, __LINE__) @@ -93,12 +89,6 @@ void Z_Free2(void *ptr, const char *file, INT32 line); void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(1); void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(1); void *Z_Realloc2(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(2); -#else -void Z_Free(void *ptr); -void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(1); -void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(1); -void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(2); -#endif // Alloc with no alignment #define Z_Malloc(s,t,u) Z_MallocAlign(s, t, u, 0) @@ -106,7 +96,7 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb #define Z_Realloc(p,s,t,u) Z_ReallocAlign(p, s, t, u, 0) // Free all memory by tag -// these don't give line numbers for ZDEBUG currently though +// these don't give line numbers currently though // (perhaps this should be changed in future?) #define Z_FreeTag(tagnum) Z_FreeTags(tagnum, tagnum) void Z_FreeTags(INT32 lowtag, INT32 hightag);