diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0cb1d4497..dd1234f0a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -811,6 +811,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("writethings", Command_Writethings_f); CV_RegisterVar(&cv_speed); CV_RegisterVar(&cv_opflags); + CV_RegisterVar(&cv_ophoopflags); CV_RegisterVar(&cv_mapthingnum); // CV_RegisterVar(&cv_grid); // CV_RegisterVar(&cv_snapto); @@ -822,7 +823,6 @@ void D_RegisterClientCommands(void) COM_AddCommand("getallemeralds", Command_Getallemeralds_f); COM_AddCommand("resetemeralds", Command_Resetemeralds_f); COM_AddCommand("setrings", Command_Setrings_f); - COM_AddCommand("setspheres", Command_Setspheres_f); COM_AddCommand("setlives", Command_Setlives_f); COM_AddCommand("setcontinues", Command_Setcontinues_f); COM_AddCommand("devmode", Command_Devmode_f); diff --git a/src/d_player.h b/src/d_player.h index 59f9ba42a..dd0643bd4 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -456,16 +456,25 @@ typedef struct player_s boolean bonustime; // Capsule destroyed, now it's bonus time! mobj_t *capsule; // Go inside the capsule UINT8 mare; // Current mare + UINT8 marelap; // Current mare lap + UINT8 marebonuslap; // Current mare lap starting from bonus time // Statistical purposes. tic_t marebegunat; // Leveltime when mare begun tic_t startedtime; // Time which you started this mare with. tic_t finishedtime; // Time it took you to finish the mare (used for display) + tic_t lapbegunat; // Leveltime when lap begun + tic_t lapstartedtime; // Time which you started this lap with. INT16 finishedspheres; // The spheres you had left upon finishing the mare INT16 finishedrings; // The rings/stars you had left upon finishing the mare UINT32 marescore; // score for this nights stage UINT32 lastmarescore; // score for the last mare + UINT32 totalmarescore; // score for all mares UINT8 lastmare; // previous mare + UINT8 lastmarelap; // previous mare lap + UINT8 lastmarebonuslap; // previous mare bonus lap + UINT8 totalmarelap; // total mare lap + UINT8 totalmarebonuslap; // total mare bonus lap INT32 maxlink; // maximum link obtained UINT8 texttimer; // nights_texttime should not be local UINT8 textvar; // which line of NiGHTS text to show -- let's not use cheap hacks diff --git a/src/dehacked.c b/src/dehacked.c index 127b367c8..9b2cf7fc0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1203,6 +1203,8 @@ static void readlevelheader(MYFILE *f, INT32 num) deh_warning("Level header %d: invalid bonus type number %d", num, i); } + else if (fastcmp(word, "MAXBONUSLIVES")) + mapheaderinfo[num-1]->maxbonuslives = (SINT8)i; else if (fastcmp(word, "LEVELFLAGS")) mapheaderinfo[num-1]->levelflags = (UINT8)i; else if (fastcmp(word, "MENUFLAGS")) @@ -7316,6 +7318,8 @@ struct { {"CODEBASE",CODEBASE}, // or what release of SRB2 this is. {"VERSION",VERSION}, // Grab the game's version! {"SUBVERSION",SUBVERSION}, // more precise version number + {"NEWTICRATE",NEWTICRATE}, // TICRATE*NEWTICRATERATIO + {"NEWTICRATERATIO",NEWTICRATERATIO}, // Special linedef executor tag numbers! {"LE_PINCHPHASE",LE_PINCHPHASE}, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) diff --git a/src/doomstat.h b/src/doomstat.h index 24b9e5753..651540ecc 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -244,6 +244,7 @@ typedef struct SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) + SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.) UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus diff --git a/src/g_game.c b/src/g_game.c index 52358a8b9..819d5e938 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2230,6 +2230,8 @@ void G_PlayerReborn(INT32 player) if (p->mare == 255) p->mare = 0; + p->marelap = p->marebonuslap = 0; + // Check to make sure their color didn't change somehow... if (G_GametypeHasTeams()) { @@ -4664,6 +4666,7 @@ void G_GhostTicker(void) p->next = g->next; else ghosts = g->next; + Z_Free(g); continue; } p = g; @@ -5664,29 +5667,28 @@ void G_AddGhost(char *defdemoname) mthing = playerstarts[0]; I_Assert(mthing); { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. - fixed_t x,y,z; - sector_t *sector; - x = mthing->x << FRACBITS; - y = mthing->y << FRACBITS; - sector = R_PointInSubsector(x, y)->sector; + fixed_t z,f,c; + gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST); + gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT); + f = gh->mo->floorz; + c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) { - z = sector->ceilingheight - mobjinfo[MT_PLAYER].height; + z = c; if (mthing->options >> ZSHIFT) z -= ((mthing->options >> ZSHIFT) << FRACBITS); - if (z < sector->floorheight) - z = sector->floorheight; + if (z < f) + z = f; } else { - z = sector->floorheight; + z = f; if (mthing->options >> ZSHIFT) z += ((mthing->options >> ZSHIFT) << FRACBITS); - if (z > sector->ceilingheight - mobjinfo[MT_PLAYER].height) - z = sector->ceilingheight - mobjinfo[MT_PLAYER].height; + if (z > c) + z = c; } - gh->mo = P_SpawnMobj(x, y, z, MT_GHOST); - gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT); + gh->mo->z = z; } gh->oldmo.x = gh->mo->x; @@ -5885,8 +5887,14 @@ boolean G_CheckDemoStatus(void) { boolean saved; - if(ghosts) // ... ... ... - ghosts = NULL; // :) + while (ghosts) + { + demoghost *next = ghosts->next; + Z_Free(ghosts); + ghosts = next; + } + ghosts = NULL; + // DO NOT end metal sonic demos here diff --git a/src/lua_maplib.c b/src/lua_maplib.c index b929fc0bc..28fe8c75f 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1797,6 +1797,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->levelselect); else if (fastcmp(field,"bonustype")) lua_pushinteger(L, header->bonustype); + else if (fastcmp(field,"maxbonuslives")) + lua_pushinteger(L, header->maxbonuslives); else if (fastcmp(field,"levelflags")) lua_pushinteger(L, header->levelflags); else if (fastcmp(field,"menuflags")) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index ff62f2459..f973061f1 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -290,12 +290,20 @@ static int player_get(lua_State *L) LUA_PushUserdata(L, plr->capsule, META_MOBJ); else if (fastcmp(field,"mare")) lua_pushinteger(L, plr->mare); + else if (fastcmp(field,"marelap")) + lua_pushinteger(L, plr->marelap); + else if (fastcmp(field,"marebonuslap")) + lua_pushinteger(L, plr->marebonuslap); else if (fastcmp(field,"marebegunat")) lua_pushinteger(L, plr->marebegunat); else if (fastcmp(field,"startedtime")) lua_pushinteger(L, plr->startedtime); else if (fastcmp(field,"finishedtime")) lua_pushinteger(L, plr->finishedtime); + else if (fastcmp(field,"lapbegunat")) + lua_pushinteger(L, plr->lapbegunat); + else if (fastcmp(field,"lapstartedtime")) + lua_pushinteger(L, plr->lapstartedtime); else if (fastcmp(field,"finishedspheres")) lua_pushinteger(L, plr->finishedspheres); else if (fastcmp(field,"finishedrings")) @@ -304,8 +312,18 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->marescore); else if (fastcmp(field,"lastmarescore")) lua_pushinteger(L, plr->lastmarescore); + else if (fastcmp(field,"totalmarescore")) + lua_pushinteger(L, plr->totalmarescore); else if (fastcmp(field,"lastmare")) lua_pushinteger(L, plr->lastmare); + else if (fastcmp(field,"lastmarelap")) + lua_pushinteger(L, plr->lastmarelap); + else if (fastcmp(field,"lastmarebonuslap")) + lua_pushinteger(L, plr->lastmarebonuslap); + else if (fastcmp(field,"totalmarelap")) + lua_pushinteger(L, plr->totalmarelap); + else if (fastcmp(field,"totalmarebonuslap")) + lua_pushinteger(L, plr->totalmarebonuslap); else if (fastcmp(field,"maxlink")) lua_pushinteger(L, plr->maxlink); else if (fastcmp(field,"texttimer")) @@ -570,12 +588,20 @@ static int player_set(lua_State *L) } else if (fastcmp(field,"mare")) plr->mare = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"marelap")) + plr->marelap = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"marebonuslap")) + plr->marebonuslap = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"marebegunat")) plr->marebegunat = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"startedtime")) plr->startedtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"finishedtime")) plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"lapbegunat")) + plr->lapbegunat = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"lapstartedtime")) + plr->lapstartedtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"finishedspheres")) plr->finishedspheres = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"finishedrings")) @@ -584,8 +610,18 @@ static int player_set(lua_State *L) plr->marescore = (UINT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"lastmarescore")) plr->lastmarescore = (UINT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"totalmarescore")) + plr->totalmarescore = (UINT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"lastmare")) plr->lastmare = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastmarelap")) + plr->lastmarelap = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastmarebonuslap")) + plr->lastmarebonuslap = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"totalmarelap")) + plr->totalmarelap = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"totalmarebonuslap")) + plr->totalmarebonuslap = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"maxlink")) plr->maxlink = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"texttimer")) diff --git a/src/m_cheat.c b/src/m_cheat.c index 56bef02a3..9e64c9ab8 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -880,28 +880,19 @@ void Command_Setrings_f(void) if (COM_Argc() > 1) { - // P_GivePlayerRings does value clamping - players[consoleplayer].rings = 0; - P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); - if (!G_IsSpecialStage(gamemap) || !(maptol & TOL_NIGHTS)) + if (!(maptol & TOL_NIGHTS)) + { + // P_GivePlayerRings does value clamping + players[consoleplayer].rings = 0; + P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings - - G_SetGameModified(multiplayer); - } -} - -void Command_Setspheres_f(void) -{ - REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; - REQUIRE_NOULTIMATE; - REQUIRE_PANDORA; - - if (COM_Argc() > 1) - { - // P_GivePlayerRings does value clamping - players[consoleplayer].spheres = 0; - P_GivePlayerSpheres(&players[consoleplayer], atoi(COM_Argv(1))); + } + else + { + players[consoleplayer].spheres = 0; + P_GivePlayerSpheres(&player[consoleplayer], atoi(COM_Argv(1))); + // no totalsphere addition to revert + } G_SetGameModified(multiplayer); } @@ -957,10 +948,12 @@ void Command_Setcontinues_f(void) static CV_PossibleValue_t op_mapthing_t[] = {{0, "MIN"}, {4095, "MAX"}, {0, NULL}}; static CV_PossibleValue_t op_speed_t[] = {{1, "MIN"}, {128, "MAX"}, {0, NULL}}; static CV_PossibleValue_t op_flags_t[] = {{0, "MIN"}, {15, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t op_hoopflags_t[] = {{0, "MIN"}, {15, "MAX"}, {0, NULL}}; consvar_t cv_mapthingnum = {"op_mapthingnum", "0", CV_NOTINNET, op_mapthing_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_speed = {"op_speed", "16", CV_NOTINNET, op_speed_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_opflags = {"op_flags", "0", CV_NOTINNET, op_flags_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_ophoopflags = {"op_hoopflags", "4", CV_NOTINNET, op_hoopflags_t, NULL, 0, NULL, NULL, 0, 0, NULL}; boolean objectplacing = false; mobjtype_t op_currentthing = 0; // For the object placement mode @@ -1164,17 +1157,10 @@ void OP_NightsObjectplace(player_t *player) { UINT16 angle = (UINT16)(player->anotherflyangle % 360); INT16 temp = (INT16)FixedInt(AngleFixed(player->mo->angle)); // Traditional 2D Angle - sector_t *sec = player->mo->subsector->sector; -#ifdef ESLOPE - fixed_t fheight = sec->f_slope ? P_GetZAt(sec->f_slope, player->mo->x & 0xFFFF0000, player->mo->y & 0xFFFF0000) : sec->floorheight; -#else - fixed_t fheight = sec->floorheight; -#endif - player->pflags |= PF_ATTACKDOWN; - mt = OP_CreateNewMapThing(player, 1705, false); + mt = OP_CreateNewMapThing(player, 1713, false); // Tilt mt->angle = (INT16)FixedInt(FixedDiv(angle*FRACUNIT, 360*(FRACUNIT/256))); @@ -1185,7 +1171,7 @@ void OP_NightsObjectplace(player_t *player) temp += 90; temp %= 360; - mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS); + mt->options = (mt->options & ~(UINT16)cv_opflags.value) | (UINT16)cv_ophoopflags.value; mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8)); P_SpawnHoopsAndRings(mt, false); @@ -1194,11 +1180,52 @@ void OP_NightsObjectplace(player_t *player) // This places a bumper! if (cmd->buttons & BT_TOSSFLAG) { + UINT16 vertangle = (UINT16)(player->anotherflyangle % 360); + UINT16 newflags, newz; + player->pflags |= PF_ATTACKDOWN; if (!OP_HeightOkay(player, false)) return; mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_NIGHTSBUMPER].doomednum, false); + newz = min((mt->options >> ZSHIFT) - (mobjinfo[MT_NIGHTSBUMPER].height/4), 0); + // height offset: from P_TouchSpecialThing case MT_NIGHTSBUMPER + + // clockwise + if (vertangle >= 75 && vertangle < 105) // up + newflags = 3; + else if (vertangle >= 105 && vertangle < 135) // 60 upward tilt + newflags = 2; + else if (vertangle >= 135 && vertangle < 165) // 30 upward tilt + newflags = 1; + //else if (vertangle >= 165 && vertangle < 195) // forward, see else case + // newflags = 0; + else if (vertangle >= 195 && vertangle < 225) // 30 downward tilt + newflags = 11; + else if (vertangle >= 225 && vertangle < 255) // 60 downward tilt + newflags = 10; + else if (vertangle >= 255 && vertangle < 285) // down + newflags = 9; + else if (vertangle >= 285 && vertangle < 315) // 60 downward tilt backwards + newflags = 8; + else if (vertangle >= 315 && vertangle < 345) // 30 downward tilt backwards + newflags = 7; + else if (vertangle >= 345 || vertangle < 15) // backwards + newflags = 6; + else if (vertangle >= 15 && vertangle < 45) // 30 upward tilt backwards + newflags = 5; + else if (vertangle >= 45 && vertangle < 75) // 60 upward tilt backwards + newflags = 4; + else // forward + newflags = 0; + + mt->options = (newz << ZSHIFT) | newflags; + + // if NiGHTS is facing backwards, orient the Thing angle forwards so that the sprite angle + // displays correctly. Backwards movement via the Thing flags is unaffected. + if (vertangle < 90 || vertangle > 270) + mt->angle = (mt->angle + 180) % 360; + P_SpawnMapThing(mt); } diff --git a/src/m_cheat.h b/src/m_cheat.h index 31f650b3f..d50ddc119 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -28,7 +28,7 @@ void cht_Init(void); void Command_ObjectPlace_f(void); void Command_Writethings_f(void); -extern consvar_t cv_opflags, cv_mapthingnum, cv_speed; +extern consvar_t cv_opflags, cv_ophoopflags, cv_mapthingnum, cv_speed; //extern consvar_t cv_snapto, cv_grid; extern boolean objectplacing; @@ -51,7 +51,6 @@ void Command_Savecheckpoint_f(void); void Command_Getallemeralds_f(void); void Command_Resetemeralds_f(void); void Command_Setrings_f(void); -void Command_Setspheres_f(void); void Command_Setlives_f(void); void Command_Setcontinues_f(void); void Command_Devmode_f(void); diff --git a/src/p_inter.c b/src/p_inter.c index a4493c466..57b47f1c6 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1005,13 +1005,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->flyangle = special->threshold; player->speed = FixedMul(special->info->speed, special->scale); - // Potentially causes axis transfer failures. - // Also rarely worked properly anyway. - //P_UnsetThingPosition(player->mo); - //player->mo->x = special->x; - //player->mo->y = special->y; - //P_SetThingPosition(player->mo); - toucher->z = special->z+(special->height/4); + P_SetTarget(&player->mo->hnext, special); // Reference bumper for position correction on next tic } else // More like a spring { @@ -1134,6 +1128,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { player->nightstime += special->info->speed; player->startedtime += special->info->speed; + player->lapstartedtime += special->info->speed; P_RestoreMusic(player); } else @@ -1143,6 +1138,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { players[i].nightstime += special->info->speed; players[i].startedtime += special->info->speed; + players[i].lapstartedtime += special->info->speed; P_RestoreMusic(&players[i]); } if (special->info->deathsound != sfx_None) diff --git a/src/p_map.c b/src/p_map.c index c38f5471b..6e5e03a8d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1097,24 +1097,35 @@ static boolean PIT_CheckThing(mobj_t *thing) P_SetTarget(&thing->target, tmthing); } - // Respawn rings and items + // NiGHTS lap logic if ((tmthing->type == MT_NIGHTSDRONE || thing->type == MT_NIGHTSDRONE) && (tmthing->player || thing->player)) { mobj_t *droneobj = (tmthing->type == MT_NIGHTSDRONE) ? tmthing : thing; player_t *pl = (droneobj == thing) ? tmthing->player : thing->player; - // Must be in bonus time, and must be NiGHTS, must wait about a second + // Must be NiGHTS, must wait about a second // must be flying in the SAME DIRECTION as the last time you came through. // not (your direction) xor (stored direction) // In other words, you can't u-turn and respawn rings near the drone. - if (pl->bonustime && (pl->powers[pw_carry] == CR_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && ( + if ((pl->powers[pw_carry] == CR_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && ( !(pl->flyangle > 90 && pl->flyangle < 270) ^ (droneobj->extravalue1 > 90 && droneobj->extravalue1 < 270) )) { - // Reload all the fancy ring stuff! - P_ReloadRings(); + pl->marelap++; + pl->totalmarelap++; + pl->lapbegunat = leveltime; + pl->lapstartedtime = pl->nightstime; + + if (pl->bonustime) + { + pl->marebonuslap++; + pl->totalmarebonuslap++; + + // Respawn rings and items + P_ReloadRings(); + } } droneobj->extravalue1 = pl->flyangle; droneobj->extravalue2 = (INT32)leveltime + TICRATE; diff --git a/src/p_saveg.c b/src/p_saveg.c index 7cf437384..22d43f358 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -198,15 +198,24 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].drilldelay); WRITEUINT8(save_p, players[i].bonustime); WRITEUINT8(save_p, players[i].mare); + WRITEUINT8(save_p, players[i].marelap); + WRITEUINT8(save_p, players[i].marebonuslap); WRITEUINT32(save_p, players[i].marebegunat); WRITEUINT32(save_p, players[i].startedtime); WRITEUINT32(save_p, players[i].finishedtime); + WRITEUINT32(save_p, players[i].lapbegunat); + WRITEUINT32(save_p, players[i].lapstartedtime); WRITEINT16(save_p, players[i].finishedspheres); WRITEINT16(save_p, players[i].finishedrings); WRITEUINT32(save_p, players[i].marescore); WRITEUINT32(save_p, players[i].lastmarescore); + WRITEUINT32(save_p, players[i].totalmarescore); WRITEUINT8(save_p, players[i].lastmare); + WRITEUINT8(save_p, players[i].lastmarelap); + WRITEUINT8(save_p, players[i].lastmarebonuslap); + WRITEUINT8(save_p, players[i].totalmarelap); + WRITEUINT8(save_p, players[i].totalmarebonuslap); WRITEINT32(save_p, players[i].maxlink); WRITEUINT8(save_p, players[i].texttimer); WRITEUINT8(save_p, players[i].textvar); @@ -387,15 +396,24 @@ static void P_NetUnArchivePlayers(void) players[i].drilldelay = READUINT8(save_p); players[i].bonustime = (boolean)READUINT8(save_p); players[i].mare = READUINT8(save_p); + players[i].marelap = READUINT8(save_p); + players[i].marebonuslap = READUINT8(save_p); players[i].marebegunat = READUINT32(save_p); players[i].startedtime = READUINT32(save_p); players[i].finishedtime = READUINT32(save_p); + players[i].lapbegunat = READUINT32(save_p); + players[i].lapstartedtime = READUINT32(save_p); players[i].finishedspheres = READINT16(save_p); players[i].finishedrings = READINT16(save_p); players[i].marescore = READUINT32(save_p); players[i].lastmarescore = READUINT32(save_p); + players[i].totalmarescore = READUINT32(save_p); players[i].lastmare = READUINT8(save_p); + players[i].lastmarelap = READUINT8(save_p); + players[i].lastmarebonuslap = READUINT8(save_p); + players[i].totalmarelap = READUINT8(save_p); + players[i].totalmarebonuslap = READUINT8(save_p); players[i].maxlink = READINT32(save_p); players[i].texttimer = READUINT8(save_p); players[i].textvar = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index c62f281b3..2361d1efd 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -225,6 +225,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->unlockrequired = -1; mapheaderinfo[num]->levelselect = 0; mapheaderinfo[num]->bonustype = 0; + mapheaderinfo[num]->maxbonuslives = -1; mapheaderinfo[num]->levelflags = 0; mapheaderinfo[num]->menuflags = 0; #if 1 // equivalent to "FlickyList = DEMO" @@ -2381,12 +2382,16 @@ static void P_LevelInitStuff(void) players[i].maxlink = players[i].startedtime =\ players[i].finishedtime = players[i].finishedspheres =\ players[i].finishedrings = players[i].lastmare =\ + players[i].lastmarelap = players[i].lastmarebonuslap =\ + players[i].totalmarelap = players[i].totalmarebonuslap =\ players[i].marebegunat = players[i].textvar =\ players[i].texttimer = players[i].linkcount =\ players[i].linktimer = players[i].flyangle =\ players[i].anotherflyangle = players[i].nightstime =\ - players[i].mare = players[i].realtime =\ - players[i].exiting = 0; + players[i].mare = players[i].marelap =\ + players[i].marebonuslap = players[i].lapbegunat =\ + players[i].lapstartedtime = players[i].totalmarescore =\ + players[i].realtime = players[i].exiting = 0; // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting players[i].gotcontinue = false; diff --git a/src/p_spec.c b/src/p_spec.c index 103312b52..1d842a0bb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1493,10 +1493,10 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!playeringame[i] || players[i].spectator) continue; - if (!players[i].mo || players[i].rings <= 0) + if (!players[i].mo || ((maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings) <= 0) continue; - rings += players[i].rings; + rings += (maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings; } } else @@ -1504,7 +1504,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!(actor && actor->player)) return false; // no player to count rings from here, sorry - rings = actor->player->rings; + rings = (maptol & TOL_NIGHTS) ? actor->player->spheres : actor->player->rings; } if (triggerline->flags & ML_NOCLIMB) diff --git a/src/p_user.c b/src/p_user.c index 100663d91..e7f5f3248 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -387,6 +387,8 @@ boolean P_TransferToNextMare(player_t *player) CONS_Debug(DBG_NIGHTS, "Mare is %d\n", mare); player->mare = mare; + player->marelap = 0; + player->marebonuslap = 0; // scan the thinkers // to find the closest axis point @@ -574,6 +576,10 @@ static void P_DeNightserizePlayer(player_t *player) player->climbing = 0; player->mo->fuse = 0; player->speed = 0; + player->marelap = 0; + player->marebonuslap = 0; + player->flyangle = 0; + player->anotherflyangle = 0; P_SetTarget(&player->mo->target, NULL); P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL)); @@ -633,7 +639,7 @@ static void P_DeNightserizePlayer(player_t *player) // NiGHTS Time! void P_NightserizePlayer(player_t *player, INT32 nighttime) { - INT32 oldmare; + UINT8 oldmare, oldmarelap, oldmarebonuslap; // Bots can't be NiGHTSerized, silly!1 :P if (player->bot) @@ -648,6 +654,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->speed = 0; player->climbing = 0; player->secondjump = 0; + player->flyangle = 0; + player->anotherflyangle = 0; player->powers[pw_shield] = SH_NONE; player->powers[pw_super] = 0; @@ -662,7 +670,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->followitem = skins[DEFAULTNIGHTSSKIN].followitem; } - player->nightstime = player->startedtime = nighttime*TICRATE; + player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE; player->bonustime = false; P_RestoreMusic(player); @@ -680,6 +688,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) } oldmare = player->mare; + oldmarelap = player->marelap; + oldmarebonuslap = player->marebonuslap; if (!P_TransferToNextMare(player)) { @@ -707,6 +717,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) players[i].texttimer = (3 * TICRATE) - 10; players[i].textvar = 4; // Score and grades players[i].lastmare = players[i].mare; + players[i].lastmarelap = players[i].marelap; + players[i].lastmarebonuslap = players[i].marebonuslap; if (G_IsSpecialStage(gamemap)) { players[i].finishedspheres = (INT16)total_spheres; @@ -725,6 +737,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) G_AddTempNightsRecords(players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1); // transfer scores anyway + players[i].totalmarescore += players[i].marescore; players[i].lastmarescore = players[i].marescore; players[i].marescore = 0; @@ -738,19 +751,24 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) // Spheres bonus P_AddPlayerScore(player, (player->spheres) * 50); - player->lastmare = (UINT8)oldmare; + player->lastmare = oldmare; + player->lastmarelap = oldmarelap; + player->lastmarebonuslap = oldmarebonuslap; player->texttimer = 4*TICRATE; player->textvar = 4; // Score and grades player->finishedspheres = (INT16)(player->spheres); + player->finishedrings = (INT16)(player->rings); // Add score to temp leaderboards if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) G_AddTempNightsRecords(player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1)); // Starting a new mare, transfer scores + player->totalmarescore += player->marescore; player->lastmarescore = player->marescore; player->marescore = 0; player->marebegunat = leveltime; + player->lapbegunat = leveltime; player->spheres = player->rings = 0; } @@ -765,6 +783,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->texttimer = (UINT8)(110 - timeinmap); } + // force NiGHTS to face forward or backward + if (player->mo->target) + player->mo->angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y) // player->angle_pos, won't be set on first instance + + ((player->mo->target->flags2 & MF2_AMBUSH) ? // if axis is invert, take the opposite right angle + (player->flyangle > 90 && player->flyangle < 270 ? ANGLE_90 : -ANGLE_90) + : (player->flyangle > 90 && player->flyangle < 270 ? -ANGLE_90 : ANGLE_90)); + player->powers[pw_carry] = CR_NIGHTSMODE; } @@ -6174,7 +6199,6 @@ static void P_NiGHTSMovement(player_t *player) // S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false); - if (player->mo->z < player->mo->floorz) player->mo->z = player->mo->floorz; @@ -9808,7 +9832,19 @@ void P_PlayerThink(player_t *player) P_ResetScore(player); } else + { + if (player->bumpertime == TICRATE/2 && player->mo->hnext) + { + // Center player to NiGHTS bumper here because if you try to set player's position in + // P_TouchSpecialThing case MT_NIGHTSBUMPER, that position is fudged in the time + // between that routine in the previous tic + // and reaching here in the current tic + P_TeleportMove(player->mo, player->mo->hnext->x, player->mo->hnext->y + , player->mo->hnext->z + FixedMul(player->mo->hnext->height/4, player->mo->hnext->scale)); + P_SetTarget(&player->mo->hnext, NULL); + } P_MovePlayer(player); + } if (!player->mo) return; // P_MovePlayer removed player->mo. @@ -9932,7 +9968,8 @@ void P_PlayerThink(player_t *player) || player->panim == PA_PAIN || !player->mo->health || player->climbing - || player->pflags & (PF_SPINNING|PF_SLIDING)) + || player->pflags & (PF_SPINNING|PF_SLIDING) + || player->bumpertime) player->pflags &= ~PF_APPLYAUTOBRAKE; else if (currentlyonground || player->powers[pw_tailsfly]) player->pflags |= PF_APPLYAUTOBRAKE; diff --git a/src/r_data.c b/src/r_data.c index 169b04201..6aede0396 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1362,7 +1362,7 @@ INT32 R_ColormapNumForName(char *name) extra_colormaps[num_extra_colormaps].fadecolor = 0x0; extra_colormaps[num_extra_colormaps].maskamt = 0x0; extra_colormaps[num_extra_colormaps].fadestart = 0; - extra_colormaps[num_extra_colormaps].fadeend = 33; + extra_colormaps[num_extra_colormaps].fadeend = 31; extra_colormaps[num_extra_colormaps].fog = 0; num_extra_colormaps++; @@ -1390,7 +1390,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) size_t mapnum = num_extra_colormaps; size_t i; UINT32 cr, cg, cb, maskcolor, fadecolor; - UINT32 fadestart = 0, fadeend = 33, fadedist = 33; + UINT32 fadestart = 0, fadeend = 31, fadedist = 31; #define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) if (p1[0] == '#') @@ -1431,12 +1431,12 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) // Get parameters like fadestart, fadeend, and the fogflag fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10); fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10); - if (fadestart > 32) + if (fadestart > 30) fadestart = 0; - if (fadeend > 33 || fadeend < 1) - fadeend = 33; + if (fadeend > 31 || fadeend < 1) + fadeend = 31; fadedist = fadeend - fadestart; - fog = NUMFROMCHAR(p2[1]) ? 1 : 0; + fog = NUMFROMCHAR(p2[1]); } #undef getnum @@ -1537,7 +1537,7 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) size_t i; char *colormap_p; UINT32 cr, cg, cb, maskcolor, fadecolor; - UINT32 fadestart = 0, fadeend = 33, fadedist = 33; + UINT32 fadestart = 0, fadeend = 31, fadedist = 31; #define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) if (p1[0] == '#') @@ -1578,12 +1578,12 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) // Get parameters like fadestart, fadeend, and the fogflag fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10); fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10); - if (fadestart > 32) + if (fadestart > 30) fadestart = 0; - if (fadeend > 33 || fadeend < 1) - fadeend = 33; + if (fadeend > 31 || fadeend < 1) + fadeend = 31; fadedist = fadeend - fadestart; - fog = NUMFROMCHAR(p2[1]) ? 1 : 0; + fog = NUMFROMCHAR(p2[1]); } #undef getnum diff --git a/src/r_plane.c b/src/r_plane.c index bc510bbb5..620ef90d1 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -37,6 +37,9 @@ // Quincunx antialiasing of flats! //#define QUINCUNX +// good night sweet prince +#define SHITPLANESPARENCY + //SoM: 3/23/2000: Use Boom visplane hashing. #define MAXVISPLANES 512 @@ -813,7 +816,11 @@ void R_DrawSinglePlane(visplane_t *pl) else // Opaque, but allow transparent flat pixels spanfunc = splatfunc; - if (pl->extra_colormap && pl->extra_colormap->fog) +#ifdef SHITPLANESPARENCY + if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) +#else + if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = LIGHTLEVELS-1; @@ -867,7 +874,11 @@ void R_DrawSinglePlane(visplane_t *pl) else // Opaque, but allow transparent flat pixels spanfunc = splatfunc; - if (pl->extra_colormap && pl->extra_colormap->fog) +#ifdef SHITPLANESPARENCY + if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) +#else + if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = LIGHTLEVELS-1; diff --git a/src/r_things.c b/src/r_things.c index 9e858aba9..fb4664d90 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -983,7 +983,8 @@ static void R_SplitSprite(vissprite_t *sprite) newsprite->extra_colormap = sector->lightlist[i].extra_colormap; - if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !newsprite->extra_colormap->fog))) + if (!((newsprite->cut & SC_FULLBRIGHT) + && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) { lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT); @@ -1403,7 +1404,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->cut |= SC_FULLBRIGHT; if (vis->cut & SC_FULLBRIGHT - && (!vis->extra_colormap || !vis->extra_colormap->fog)) + && (!vis->extra_colormap || !(vis->extra_colormap->fog & 1))) { // full bright: goggles vis->colormap = colormaps; diff --git a/src/v_video.c b/src/v_video.c index d93109baf..765965ffd 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -622,7 +622,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t if (scrn & V_FLIP) { flip = true; - x -= FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<width) - SHORT(patch->leftoffset))<leftoffset)<= 0) && dest < deststop; dest += vid.width) - memset(dest, (UINT8)(c&255), w * vid.bpp); + memset(dest, c, w * vid.bpp); } // @@ -1642,6 +1642,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) dupx = dupy = 1; scrwidth = vid.width/vid.dupx; left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; } switch (option & V_SPACINGMASK) @@ -1701,7 +1702,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if (cx+left > scrwidth) + if (cx > scrwidth) break; if (cx+left + w < 0) //left boundary check { @@ -1754,6 +1755,7 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) dupx = dupy = 1; scrwidth = vid.width/vid.dupx; left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; } charflags = (option & V_CHARCOLORMASK); @@ -1813,7 +1815,8 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) } else w = SHORT(hu_font[c]->width) * dupx / 2; - if (cx+left > scrwidth) + + if (cx > scrwidth) break; if (cx+left + w < 0) //left boundary check { @@ -1860,6 +1863,7 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) dupx = dupy = 1; scrwidth = vid.width/vid.dupx; left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; } charflags = (option & V_CHARCOLORMASK); @@ -1917,7 +1921,7 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) else w = (SHORT(tny_font[c]->width) * dupx); - if (cx+left > scrwidth) + if (cx > scrwidth) break; if (cx+left + w < 0) //left boundary check { @@ -1960,6 +1964,7 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) dupx = dupy = 1; scrwidth = vid.width/vid.dupx; left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; } switch (option & V_SPACINGMASK) @@ -2014,9 +2019,9 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if ((cx>>FRACBITS)+left > scrwidth) + if ((cx>>FRACBITS) > scrwidth) break; - if (cx+left + w < 0) //left boundary check + if ((cx>>FRACBITS)+left + w < 0) //left boundary check { cx += w<width) * dupx; - if ((cx>>FRACBITS) + w > scrwidth) + if ((cx>>FRACBITS) > scrwidth) break; V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT); @@ -2178,6 +2183,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) dupx = dupy = 1; scrwidth = vid.width/vid.dupx; left = (scrwidth - BASEVIDWIDTH)/2; + scrwidth -= left; } for (;;ch++) @@ -2207,10 +2213,9 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(lt_font[c]->width) * dupx; - if (cx+left > scrwidth) + if (cx > scrwidth) break; - //left boundary check - if (cx+left + w < 0) + if (cx+left + w < 0) //left boundary check { cx += w; continue; diff --git a/src/y_inter.c b/src/y_inter.c index fff6d2ebf..598f3c8ab 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1874,7 +1874,9 @@ static void Y_AwardCoopBonuses(void) players[i].score = MAXSCORE; } - ptlives = (!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; + ptlives = min( + ((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0), + (mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives)); if (ptlives) P_GivePlayerLives(&players[i], ptlives); @@ -1918,7 +1920,9 @@ static void Y_AwardSpecialStageBonus(void) players[i].score = MAXSCORE; // grant extra lives right away since tally is faked - ptlives = (!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; + ptlives = min( + ((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0), + (mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives)); if (ptlives) P_GivePlayerLives(&players[i], ptlives);