Merge branch 'master' into tutorial-time

This commit is contained in:
Monster Iestyn 2018-09-04 15:54:50 +01:00
commit bcc9e58d0e
26 changed files with 777 additions and 254 deletions

View file

@ -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);
@ -2766,6 +2766,12 @@ static void Command_Login_f(void)
UINT8 finalmd5[16];
const char *pw;
if (!netgame)
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
// If the server uses login, it will effectively just remove admin privileges
// from whoever has them. This is good.
if (COM_Argc() != 2)
@ -2833,6 +2839,12 @@ static void Command_Verify_f(void)
return;
}
if (!netgame)
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("verify <node>: give admin privileges to a node\n"));
@ -3144,7 +3156,7 @@ static void Command_Addfile(void)
WRITEMEM(buf_p, md5sum, 16);
}
if (adminplayer == consoleplayer) // Request to add file
if (adminplayer == consoleplayer && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf);
else
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);

View file

@ -382,7 +382,7 @@ typedef struct player_s
fixed_t height; // Bounding box changes.
fixed_t spinheight;
SINT8 lives;
SINT8 lives; // number of lives - if == INFLIVES, the player has infinite lives
SINT8 continues; // continues that player has acquired
SINT8 xtralife; // Ring Extra Life counter
@ -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
@ -491,4 +500,7 @@ typedef struct player_s
#endif
} player_t;
// Value for infinite lives
#define INFLIVES 0x7F
#endif

View file

@ -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"))
@ -2730,11 +2732,14 @@ static void readmaincfg(MYFILE *f)
{
extralifetics = (UINT16)get_number(word2);
}
else if (fastcmp(word, "NIGHTSLINKTICS"))
{
nightslinktics = (UINT16)get_number(word2);
}
else if (fastcmp(word, "GAMEOVERTICS"))
{
gameovertics = get_number(word2);
}
else if (fastcmp(word, "INTROTOPLAY"))
{
introtoplay = (UINT8)get_number(word2);
@ -7329,6 +7334,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!)
@ -7623,6 +7630,9 @@ struct {
{"WEP_RAIL",WEP_RAIL},
{"NUM_WEAPONS",NUM_WEAPONS},
// Value for infinite lives
{"INFLIVES", INFLIVES},
// Got Flags, for player->gotflag!
// Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags
{"GF_REDFLAG",GF_REDFLAG},

View file

@ -246,6 +246,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
@ -415,6 +416,7 @@ extern UINT16 tailsflytics;
extern UINT16 underwatertics;
extern UINT16 spacetimetics;
extern UINT16 extralifetics;
extern UINT16 nightslinktics;
extern UINT8 introtoplay;
extern UINT8 creditscutscene;

View file

@ -203,6 +203,7 @@ UINT16 tailsflytics = 8*TICRATE;
UINT16 underwatertics = 30*TICRATE;
UINT16 spacetimetics = 11*TICRATE + (TICRATE/2);
UINT16 extralifetics = 4*TICRATE;
UINT16 nightslinktics = 2*TICRATE;
INT32 gameovertics = 15*TICRATE;
@ -2232,6 +2233,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())
{
@ -4666,6 +4669,7 @@ void G_GhostTicker(void)
p->next = g->next;
else
ghosts = g->next;
Z_Free(g);
continue;
}
p = g;
@ -5666,29 +5670,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;
@ -5887,8 +5890,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

View file

@ -1275,7 +1275,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
}
}
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
{
@ -1413,7 +1413,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
| (greycheck ? V_TRANSLUCENT : 0)
| V_ALLOWLOWERCASE, name);
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);

View file

@ -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"))

View file

@ -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"))

View file

@ -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(&players[consoleplayer], atoi(COM_Argv(1)));
// no totalsphere addition to revert
}
G_SetGameModified(multiplayer);
}
@ -918,7 +909,7 @@ void Command_Setlives_f(void)
{
SINT8 lives = atoi(COM_Argv(1));
if (lives == -1)
players[consoleplayer].lives = 0x7f; // infinity!
players[consoleplayer].lives = INFLIVES; // infinity!
else
{
// P_GivePlayerLives does value clamping
@ -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);
}

View file

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

View file

@ -5291,7 +5291,7 @@ static void M_PandorasBox(INT32 choice)
CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].spheres, 0));
else
CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0));
if (players[consoleplayer].lives == 0x7f)
if (players[consoleplayer].lives == INFLIVES)
CV_StealthSetValue(&cv_dummylives, -1);
else
CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives);
@ -6362,7 +6362,7 @@ skipsign:
y += 25;
tempx = x + 10;
if (savegameinfo[savetodraw].lives != 0x7f
if (savegameinfo[savetodraw].lives != INFLIVES
&& savegameinfo[savetodraw].lives > 9)
tempx -= 4;
@ -6389,7 +6389,7 @@ skiplife:
V_DrawScaledPatch(tempx + 9, y + 2, 0, patch);
tempx += 16;
if (savegameinfo[savetodraw].lives == 0x7f)
if (savegameinfo[savetodraw].lives == INFLIVES)
V_DrawCharacter(tempx, y + 1, '\x16', false);
else
V_DrawString(tempx, y, 0, va("%d", savegameinfo[savetodraw].lives));

View file

@ -182,14 +182,14 @@ void P_DoNightsScore(player_t *player)
{
if (++players[i].linkcount > players[i].maxlink)
players[i].maxlink = players[i].linkcount;
players[i].linktimer = 2*TICRATE;
players[i].linktimer = nightslinktics;
}
}
else // Individual link counts
{
if (++player->linkcount > player->maxlink)
player->maxlink = player->linkcount;
player->linktimer = 2*TICRATE;
player->linktimer = nightslinktics;
}
if (player->linkcount < 10)
@ -946,6 +946,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Yay! The thing's in reach! Pull it in!
mo2->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
mo2->flags2 |= MF2_NIGHTSPULL;
// New NiGHTS attract speed dummied out because the older behavior
// is exploited as a mechanic. Uncomment to enable.
mo2->movefactor = 0; // 32*FRACUNIT; // initialize the NightsItemChase timer
P_SetTarget(&mo2->tracer, toucher);
}
}
@ -1005,13 +1008,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 +1131,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 +1141,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)
@ -1163,7 +1162,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!G_IsSpecialStage(gamemap))
{
player->powers[pw_nights_linkfreeze] = (UINT16)special->info->speed;
player->linktimer = 2*TICRATE;
player->linktimer = nightslinktics;
}
else
{
@ -1171,7 +1170,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
{
players[i].powers[pw_nights_linkfreeze] += (UINT16)special->info->speed;
players[i].linktimer = 2*TICRATE;
players[i].linktimer = nightslinktics;
}
if (special->info->deathsound != sfx_None)
S_StartSound(NULL, special->info->deathsound);
@ -2124,7 +2123,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->flags |= MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT; // Don't drop Tails 03-08-2000
if (target->flags2 & MF2_NIGHTSPULL)
{
P_SetTarget(&target->tracer, NULL);
target->movefactor = 0; // reset NightsItemChase timer
}
// dead target is no more shootable
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SPECIAL);
@ -2183,7 +2185,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
// to make people want to actually dash towards/paraloop enemies
if (++source->player->linkcount > source->player->maxlink)
source->player->maxlink = source->player->linkcount;
source->player->linktimer = 2*TICRATE;
source->player->linktimer = nightslinktics;
}
}
else
@ -2253,7 +2255,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0))
;
else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != 0x7f)
else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != INFLIVES)
&& G_GametypeUsesLives())
{
target->player->lives -= 1; // Lose a life Tails 03-11-2000

View file

@ -1097,24 +1097,37 @@ 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();
}
P_RunNightsLapExecutors(pl->mo);
}
droneobj->extravalue1 = pl->flyangle;
droneobj->extravalue2 = (INT32)leveltime + TICRATE;

View file

@ -6102,9 +6102,11 @@ void P_SetScale(mobj_t *mobj, fixed_t newscale)
void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on your target
{
fixed_t dist, ndist, speedmul;
angle_t vangle;
fixed_t tx = dest->x;
fixed_t ty = dest->y;
fixed_t tz = dest->z + (dest->height/2); // Aim for center
fixed_t xydist = P_AproxDistance(tx - source->x, ty - source->y);
if (!dest || dest->health <= 0 || !dest->player || !source->tracer)
return;
@ -6113,19 +6115,40 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y
source->angle = R_PointToAngle2(source->x, source->y, tx, ty);
// change slope
dist = P_AproxDistance(P_AproxDistance(tx - source->x, ty - source->y), tz - source->z);
dist = P_AproxDistance(xydist, tz - source->z);
if (dist < 1)
dist = 1;
if (nightsgrab)
speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(8*FRACUNIT, source->scale);
else
speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(source->info->speed, source->scale);
if (nightsgrab && source->movefactor)
{
source->movefactor += FRACUNIT/2;
source->momx = FixedMul(FixedDiv(tx - source->x, dist), speedmul);
source->momy = FixedMul(FixedDiv(ty - source->y, dist), speedmul);
source->momz = FixedMul(FixedDiv(tz - source->z, dist), speedmul);
if (dist < source->movefactor)
{
source->momx = source->momy = source->momz = 0;
P_TeleportMove(source, tx, ty, tz);
}
else
{
vangle = R_PointToAngle2(source->z, 0, tz, xydist);
source->momx = FixedMul(FINESINE(vangle >> ANGLETOFINESHIFT), FixedMul(FINECOSINE(source->angle >> ANGLETOFINESHIFT), source->movefactor));
source->momy = FixedMul(FINESINE(vangle >> ANGLETOFINESHIFT), FixedMul(FINESINE(source->angle >> ANGLETOFINESHIFT), source->movefactor));
source->momz = FixedMul(FINECOSINE(vangle >> ANGLETOFINESHIFT), source->movefactor);
}
}
else
{
if (nightsgrab)
speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(8*FRACUNIT, source->scale);
else
speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(source->info->speed, source->scale);
source->momx = FixedMul(FixedDiv(tx - source->x, dist), speedmul);
source->momy = FixedMul(FixedDiv(ty - source->y, dist), speedmul);
source->momz = FixedMul(FixedDiv(tz - source->z, dist), speedmul);
}
// Instead of just unsetting NOCLIP like an idiot, let's check the distance to our target.
ndist = P_AproxDistance(P_AproxDistance(tx - (source->x+source->momx),
@ -6150,6 +6173,7 @@ static void P_NightsItemChase(mobj_t *thing)
{
P_SetTarget(&thing->tracer, NULL);
thing->flags2 &= ~MF2_NIGHTSPULL;
thing->movefactor = 0;
return;
}
@ -8751,7 +8775,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
nummaprings = -1; // no perfect bonus, rings are free
break;
case MT_EGGCAPSULE:
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
mobj->extravalue1 = -1; // sphere timer for how long a player has been at the capsule
mobj->extravalue2 = -1; // tic timer for how long a player has been at the capsule
break;
case MT_REDTEAMRING:
mobj->color = skincolor_redteam;

View file

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

View file

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

View file

@ -1375,6 +1375,67 @@ void P_ChangeSectorTag(UINT32 sector, INT16 newtag)
}
}
//
// P_RunNightserizeExecutors
//
void P_RunNightserizeExecutors(mobj_t *actor)
{
size_t i;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == 323 || lines[i].special == 324)
P_RunTriggerLinedef(&lines[i], actor, NULL);
}
}
//
// P_RunDeNightserizeExecutors
//
void P_RunDeNightserizeExecutors(mobj_t *actor)
{
size_t i;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == 325 || lines[i].special == 326)
P_RunTriggerLinedef(&lines[i], actor, NULL);
}
}
//
// P_RunNightsLapExecutors
//
void P_RunNightsLapExecutors(mobj_t *actor)
{
size_t i;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == 327 || lines[i].special == 328)
P_RunTriggerLinedef(&lines[i], actor, NULL);
}
}
//
// P_RunNightsCapsuleTouchExecutors
//
void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean enoughspheres)
{
size_t i;
for (i = 0; i < numlines; i++)
{
if ((lines[i].special == 329 || lines[i].special == 330)
&& ((entering && (lines[i].flags & ML_TFERLINE))
|| (!entering && !(lines[i].flags & ML_TFERLINE)))
&& ((lines[i].flags & ML_DONTPEGTOP)
|| (enoughspheres && !(lines[i].flags & ML_BOUNCY))
|| (!enoughspheres && (lines[i].flags & ML_BOUNCY))))
P_RunTriggerLinedef(&lines[i], actor, NULL);
}
}
/** Hashes the sector tags across the sectors and linedefs.
*
* \sa P_FindSectorFromTag, P_ChangeSectorTag
@ -1458,6 +1519,145 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector)
P_AddThinker(&e->thinker);
}
/** Used by P_RunTriggerLinedef to check a NiGHTS trigger linedef's conditions
*
* \param triggerline Trigger linedef to check conditions for; should NEVER be NULL.
* \param actor Object initiating the action; should not be NULL.
* \sa P_RunTriggerLinedef
*/
static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor)
{
INT16 specialtype = triggerline->special;
size_t i;
UINT8 inputmare = max(0, min(255, sides[triggerline->sidenum[0]].textureoffset>>FRACBITS));
UINT8 inputlap = max(0, min(255, sides[triggerline->sidenum[0]].rowoffset>>FRACBITS));
boolean ltemare = triggerline->flags & ML_NOCLIMB;
boolean gtemare = triggerline->flags & ML_BLOCKMONSTERS;
boolean ltelap = triggerline->flags & ML_EFFECT1;
boolean gtelap = triggerline->flags & ML_EFFECT2;
boolean lapfrombonustime = triggerline->flags & ML_EFFECT3;
boolean perglobalinverse = triggerline->flags & ML_DONTPEGBOTTOM;
boolean perglobal = !(triggerline->flags & ML_EFFECT4) && !perglobalinverse;
boolean donomares = triggerline->flags & ML_BOUNCY; // nightserize: run at end of level (no mares)
boolean fromnonights = triggerline->flags & ML_TFERLINE; // nightserize: from non-nights // denightserize: all players no nights
boolean fromnights = triggerline->flags & ML_DONTPEGTOP; // nightserize: from nights // denightserize: >0 players are nights
UINT8 currentmare = UINT8_MAX;
UINT8 currentlap = UINT8_MAX;
// Do early returns for Nightserize
if (specialtype >= 323 && specialtype <= 324)
{
// run only when no mares are found
if (donomares && P_FindLowestMare() != UINT8_MAX)
return false;
// run only if there is a mare present
if (!donomares && P_FindLowestMare() == UINT8_MAX)
return false;
// run only if player is nightserizing from non-nights
if (fromnonights)
{
if (!actor->player)
return false;
else if (actor->player->powers[pw_carry] == CR_NIGHTSMODE)
return false;
}
// run only if player is nightserizing from nights
else if (fromnights)
{
if (!actor->player)
return false;
else if (actor->player->powers[pw_carry] != CR_NIGHTSMODE)
return false;
}
}
// Get current mare and lap (and check early return for DeNightserize)
if (perglobal || perglobalinverse
|| (specialtype >= 325 && specialtype <= 326 && (fromnonights || fromnights)))
{
UINT8 playersarenights = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
// denightserize: run only if all players are not nights
if (specialtype >= 325 && specialtype <= 326 && fromnonights
&& players[i].powers[pw_carry] == CR_NIGHTSMODE)
return false;
// count number of nights players for denightserize return
if (specialtype >= 325 && specialtype <= 326 && fromnights
&& players[i].powers[pw_carry] == CR_NIGHTSMODE)
playersarenights++;
UINT8 lap = lapfrombonustime ? players[i].marebonuslap : players[i].marelap;
// get highest mare/lap of players
if (perglobal)
{
if (players[i].mare > currentmare || currentmare == UINT8_MAX)
{
currentmare = players[i].mare;
currentlap = UINT8_MAX;
}
if (players[i].mare == currentmare
&& (lap > currentlap || currentlap == UINT8_MAX))
currentlap = lap;
}
// get lowest mare/lap of players
else if (perglobalinverse)
{
if (players[i].mare < currentmare || currentmare == UINT8_MAX)
{
currentmare = players[i].mare;
currentlap = UINT8_MAX;
}
if (players[i].mare == currentmare
&& (lap < currentlap || currentlap == UINT8_MAX))
currentlap = lap;
}
}
// denightserize: run only if >0 players are nights
if (specialtype >= 325 && specialtype <= 326 && fromnights
&& playersarenights < 1)
return false;
}
// get current mare/lap from triggering player
else if (!perglobal && !perglobalinverse)
{
if (!actor->player)
return false;
currentmare = actor->player->mare;
currentlap = lapfrombonustime ? actor->player->marebonuslap : actor->player->marelap;
}
if (lapfrombonustime && !currentlap)
return false; // special case: player->marebonuslap is 0 until passing through on bonus time. Don't trigger lines looking for inputlap 0.
// Compare current mare/lap to input mare/lap based on rules
if (!(specialtype >= 323 && specialtype <= 324 && donomares) // don't return false if donomares and we got this far
&& ((ltemare && currentmare > inputmare)
|| (gtemare && currentmare < inputmare)
|| (!ltemare && !gtemare && currentmare != inputmare)
|| (ltelap && currentlap > inputlap)
|| (gtelap && currentlap < inputlap)
|| (!ltelap && !gtelap && currentlap != inputlap))
)
return false;
return true;
}
/** Used by P_LinedefExecute to check a trigger linedef's conditions
* The linedef executor specials in the trigger linedef's sector are run if all conditions are met.
* Return false cancels P_LinedefExecute, this happens if a condition is not met.
@ -1493,10 +1693,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 +1704,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)
@ -1668,6 +1868,18 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
return false;
}
break;
case 323: // nightserize - each time
case 324: // nightserize - once
case 325: // denightserize - each time
case 326: // denightserize - once
case 327: // nights lap - each time
case 328: // nights lap - once
case 329: // nights egg capsule touch - each time
case 330: // nights egg capsule touch - once
if (!P_CheckNightsTriggerLine(triggerline, actor))
return false;
break;
default:
break;
}
@ -1796,6 +2008,10 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|| specialtype == 318 // Unlockable trigger - Once
|| specialtype == 320 // Unlockable - Once
|| specialtype == 321 || specialtype == 322 // Trigger on X calls - Continuous + Each Time
|| specialtype == 324 // Nightserize - Once
|| specialtype == 326 // DeNightserize - Once
|| specialtype == 328 // Nights lap - Once
|| specialtype == 330 // Nights Bonus Time - Once
|| specialtype == 399) // Level Load
triggerline->special = 0; // Clear it out
@ -6419,6 +6635,17 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
break;
// NiGHTS trigger executors
case 323:
case 324:
case 325:
case 326:
case 327:
case 328:
case 329:
case 330:
break;
case 399: // Linedef execute on map load
// This is handled in P_RunLevelLoadExecutors.
break;

View file

@ -66,6 +66,10 @@ void P_SwitchWeather(INT32 weathernum);
boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller);
void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller);
void P_ChangeSectorTag(UINT32 sector, INT16 newtag);
void P_RunNightserizeExecutors(mobj_t *actor);
void P_RunDeNightserizeExecutors(mobj_t *actor);
void P_RunNightsLapExecutors(mobj_t *actor);
void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean enoughspheres);
ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id);

View file

@ -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));
@ -625,6 +631,8 @@ static void P_DeNightserizePlayer(player_t *player)
// Restore from drowning music
P_RestoreMusic(player);
P_RunDeNightserizeExecutors(player->mo);
}
//
@ -633,7 +641,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 +656,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 +672,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 +690,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
}
oldmare = player->mare;
oldmarelap = player->marelap;
oldmarebonuslap = player->marebonuslap;
if (!P_TransferToNextMare(player))
{
@ -707,6 +719,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 +739,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 +753,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 +785,16 @@ 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));
// Do this before setting CR_NIGHTSMODE so we can tell if player was non-NiGHTS
P_RunNightserizeExecutors(player->mo);
player->powers[pw_carry] = CR_NIGHTSMODE;
}
@ -927,7 +957,7 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings)
player->rings = 0;
// Now extra life bonuses are handled here instead of in P_MovePlayer, since why not?
if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives() && player->lives != 0x7f)
if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives() && player->lives != INFLIVES)
{
INT32 gainlives = 0;
@ -986,7 +1016,7 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
if (gamestate == GS_LEVEL)
{
if (player->lives == 0x7f || (gametype != GT_COOP && gametype != GT_COMPETITION))
if (player->lives == INFLIVES || (gametype != GT_COOP && gametype != GT_COMPETITION))
{
P_GivePlayerRings(player, 100*numlives);
return;
@ -5927,6 +5957,8 @@ static void P_DoNiGHTSCapsule(player_t *player)
{
INT32 i;
player->capsule->extravalue2++; // tic counter
if (abs(player->mo->x-player->capsule->x) <= 2*FRACUNIT)
{
P_UnsetThingPosition(player->mo);
@ -5988,6 +6020,9 @@ static void P_DoNiGHTSCapsule(player_t *player)
}
}
if (player->capsule->extravalue2 <= 0 && player->capsule->health > 0)
P_RunNightsCapsuleTouchExecutors(player->mo, true, player->spheres >= player->capsule->health); // run capsule entrance executors
// Time to blow it up!
if (player->mo->x == player->capsule->x
&& player->mo->y == player->capsule->y
@ -6011,7 +6046,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
player->capsule->flags &= ~MF_NOGRAVITY;
player->capsule->momz = 5*FRACUNIT;
player->capsule->reactiontime = 0;
player->capsule->extravalue1 = -1;
player->capsule->extravalue1 = player->capsule->extravalue2 = -1;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && !player->exiting && players[i].mare == player->mare)
@ -6080,6 +6115,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
P_SetTarget(&players[i].capsule, NULL); // Remove capsule from everyone now that it is dead!
S_StartScreamSound(player->mo, sfx_ngdone);
P_SwitchSpheresBonusMode(true);
P_RunNightsCapsuleTouchExecutors(player->mo, false, true); // run capsule exit executors, and we destroyed it
}
}
else
@ -6088,7 +6124,8 @@ static void P_DoNiGHTSCapsule(player_t *player)
player->texttimer = 4*TICRATE;
player->textvar = 3; // Get more rings!
player->capsule->reactiontime = 0;
player->capsule->extravalue1 = -1;
player->capsule->extravalue1 = player->capsule->extravalue2 = -1;
P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked rings
}
}
else
@ -6174,7 +6211,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;
@ -6642,7 +6678,18 @@ static void P_NiGHTSMovement(player_t *player)
S_StartSound(player->mo, sfx_drill1);
player->drilltimer = 32;
}
else if (--player->drilltimer <= 0)
else if (player->drilltimer == 32)
{
// drill mash penalty
player->drilltimer = 31;
player->drillmeter -= TICRATE/2;
if (player->drillmeter <= 0)
player->drillmeter = TICRATE/10;
}
else if (--player->drilltimer == 11)
// give that drill mash penalty back (after 0.6 seconds)
player->drillmeter += TICRATE/2;
else if (player->drilltimer <= 0)
{
player->drilltimer = 10;
S_StartSound(player->mo, sfx_drill2);
@ -8377,7 +8424,7 @@ boolean P_GetLives(player_t *player)
if (!(netgame || multiplayer)
|| (gametype != GT_COOP)
|| (cv_cooplives.value == 1)
|| (player->lives == 0x7f))
|| (player->lives == INFLIVES))
return true;
if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0)
@ -8404,7 +8451,7 @@ boolean P_GetLives(player_t *player)
{
if (cv_cooplives.value == 2 && (P_IsLocalPlayer(player) || P_IsLocalPlayer(&players[maxlivesplayer])))
S_StartSound(NULL, sfx_jshard); // placeholder
if (players[maxlivesplayer].lives != 0x7f)
if (players[maxlivesplayer].lives != INFLIVES)
players[maxlivesplayer].lives--;
player->lives++;
if (player->lives < 1)
@ -9763,12 +9810,18 @@ void P_PlayerThink(player_t *player)
|| mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR))
continue;
if (mo2->flags2 & MF2_NIGHTSPULL)
continue;
if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale))
continue;
// Yay! The thing's in reach! Pull it in!
mo2->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
mo2->flags2 |= MF2_NIGHTSPULL;
// New NiGHTS attract speed dummied out because the older behavior
// is exploited as a mechanic. Uncomment to enable.
mo2->movefactor = 0; // 40*FRACUNIT; // initialize the NightsItemChase timer
P_SetTarget(&mo2->tracer, player->mo);
}
}
@ -9808,7 +9861,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 +9997,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;

View file

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

View file

@ -1146,9 +1146,9 @@ void R_RenderPlayerView(player_t *player)
if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1
{
if (cv_homremoval.value == 1)
V_DrawFill(0, 0, vid.width, vid.height, 31); // No HOM effect!
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect!
else //'development' HOM removal -- makes it blindingly obvious if HOM is spotted.
V_DrawFill(0, 0, vid.width, vid.height, 32+(timeinmap&15));
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 32+(timeinmap&15));
}
// load previous saved value of skyVisible for the player

View file

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

View file

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

View file

@ -807,7 +807,7 @@ static void ST_drawLivesArea(void)
// lives number
if (gametype == GT_RACE)
{
livescount = 0x7f;
livescount = INFLIVES;
notgreyedout = true;
}
else if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3)
@ -826,9 +826,9 @@ static void ST_drawLivesArea(void)
if (players[i].lives > 1)
notgreyedout = true;
if (players[i].lives == 0x7f)
if (players[i].lives == INFLIVES)
{
livescount = 0x7f;
livescount = INFLIVES;
break;
}
else if (livescount < 99)
@ -837,11 +837,11 @@ static void ST_drawLivesArea(void)
}
else
{
livescount = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0x7f : stplyr->lives);
livescount = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives);
notgreyedout = true;
}
if (livescount == 0x7f)
if (livescount == INFLIVES)
V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8,
'\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false);
else
@ -1205,6 +1205,10 @@ static void ST_drawPowerupHUD(void)
if (stplyr->spectator || stplyr->playerstate != PST_LIVE)
return;
// -------
// Shields
// -------
// Graue 06-18-2004: no V_NOSCALESTART, no SCX, no SCY, snap to right
if (stplyr->powers[pw_shield] & SH_NOSTACK)
{
@ -1247,6 +1251,10 @@ static void ST_drawPowerupHUD(void)
offs -= shieldoffs[q];
// ---------
// CTF flags
// ---------
// YOU have a flag. Display a monitor-like icon for it.
if (stplyr->gotflag)
{
@ -1264,11 +1272,20 @@ static void ST_drawPowerupHUD(void)
offs -= flagoffs[q];
// --------------------
// Timer-based powerups
// --------------------
#define DRAWTIMERICON(patch, timer) \
V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, patch); \
V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", timer/TICRATE));
// Invincibility, both from monitor and after being hit
invulntime = stplyr->powers[pw_flashing] ? stplyr->powers[pw_flashing] : stplyr->powers[pw_invulnerability];
// Note: pw_flashing always makes the icon flicker regardless of time, unlike pw_invulnerability
if (stplyr->powers[pw_invulnerability] > 3*TICRATE || (invulntime && leveltime & 1))
{
V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, invincibility);
V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", invulntime/TICRATE));
DRAWTIMERICON(invincibility, invulntime)
}
if (invulntime > 7)
@ -1281,10 +1298,10 @@ static void ST_drawPowerupHUD(void)
offs -= a;
}
// Super Sneakers
if (stplyr->powers[pw_sneakers] > 3*TICRATE || (stplyr->powers[pw_sneakers] && leveltime & 1))
{
V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, sneakers);
V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", stplyr->powers[pw_sneakers]/TICRATE));
DRAWTIMERICON(sneakers, stplyr->powers[pw_sneakers])
}
if (stplyr->powers[pw_sneakers] > 7)
@ -1297,12 +1314,13 @@ static void ST_drawPowerupHUD(void)
offs -= a;
}
// Gravity Boots
if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1))
{
V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, gravboots);
V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", stplyr->powers[pw_gravityboots]/TICRATE));
DRAWTIMERICON(gravboots, stplyr->powers[pw_gravityboots])
}
#undef DRAWTIMERICON
#undef ICONSEP
}
@ -1361,60 +1379,64 @@ static void ST_drawNightsRecords(void)
if (stplyr->texttimer < TICRATE/2)
aflag |= (9 - 9*stplyr->texttimer/(TICRATE/2)) << V_ALPHASHIFT;
// A "Bonus Time Start" by any other name...
if (stplyr->textvar == 1)
switch (stplyr->textvar)
{
V_DrawCenteredString(BASEVIDWIDTH/2, 52, V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!"));
V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, M_GetText("SCORE MULTIPLIER START!"));
if (stplyr->finishedtime)
case 1: // A "Bonus Time Start" by any other name...
{
V_DrawString(BASEVIDWIDTH/2 - 48, 140, aflag, "TIME:");
V_DrawString(BASEVIDWIDTH/2 - 48, 148, aflag, "BONUS:");
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE));
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
V_DrawCenteredString(BASEVIDWIDTH/2, 52, V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!"));
V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, M_GetText("SCORE MULTIPLIER START!"));
if (stplyr->finishedtime)
{
V_DrawString(BASEVIDWIDTH/2 - 48, 140, aflag, "TIME:");
V_DrawString(BASEVIDWIDTH/2 - 48, 148, aflag, "BONUS:");
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE));
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
}
break;
}
}
// Get n [more] Spheres
else if (stplyr->textvar <= 3 && stplyr->textvar >= 2)
{
if (!stplyr->capsule)
return;
// Yes, this string is an abomination.
V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
(stplyr->textvar == 3) ? M_GetText("MORE ") : "",
(G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP",
(stplyr->capsule->health > 1) ? "S" : ""));
}
// End Bonus
else if (stplyr->textvar == 4)
{
V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:");
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres));
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50));
ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
// If new record, say so!
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore)
case 2: // Get n Spheres
case 3: // Get n more Spheres
{
if (stplyr->texttimer & 16)
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
}
if (!stplyr->capsule)
return;
if (P_HasGrades(gamemap, stplyr->lastmare + 1))
{
if (aflag)
V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag,
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
else
V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, 160, 0,
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
// Yes, this string is an abomination.
V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
(stplyr->textvar == 3) ? M_GetText("MORE ") : "",
(G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP",
(stplyr->capsule->health > 1) ? "S" : ""));
break;
}
case 4: // End Bonus
{
V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:");
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres));
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50));
ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
// If new record, say so!
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore)
{
if (stplyr->texttimer & 16)
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
}
if (P_HasGrades(gamemap, stplyr->lastmare + 1))
{
if (aflag)
V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag,
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
else
V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, 160, 0,
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
}
break;
}
default:
break;
}
}
@ -1450,20 +1472,60 @@ static skincolors_t linkColor[2][NUMLINKCOLORS] = {
{SKINCOLOR_SEAFOAM, SKINCOLOR_CYAN, SKINCOLOR_WAVE, SKINCOLOR_SAPPHIRE, SKINCOLOR_VAPOR, SKINCOLOR_BUBBLEGUM,
SKINCOLOR_VIOLET, SKINCOLOR_RUBY, SKINCOLOR_FLAME, SKINCOLOR_SUNSET, SKINCOLOR_SANDY, SKINCOLOR_LIME}};
static void ST_drawNiGHTSLink(void)
{
static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0};
const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0);
INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? 1 : 0);
skincolors_t colornum;
fixed_t x, y, scale;
if (sel != prevsel[q])
{
prevsel[q] = sel;
prevtime[q] = 2 + mag;
}
if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics)))
colornum = SKINCOLOR_ICY;
else
colornum = linkColor[mag][sel];
aflag |= ((stplyr->linktimer < nightslinktics/3)
? (9 - 9*stplyr->linktimer/(nightslinktics/3)) << V_ALPHASHIFT
: 0);
y = (160+11)<<FRACBITS;
aflag |= V_SNAPTOBOTTOM;
x = (160+4)<<FRACBITS;
if (prevtime[q])
{
scale = ((32 + prevtime[q])<<FRACBITS)/32;
prevtime[q]--;
}
else
scale = FRACUNIT;
y -= (11*scale);
ST_DrawNightsOverlayNum(x-(4*scale), y, scale, aflag, (stplyr->linkcount-1), nightsnum, colornum);
V_DrawFixedPatch(x+(4*scale), y, scale, aflag, nightslink,
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
// Show remaining link time left in debug
if (cv_debug & DBG_NIGHTSBASIC)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_SNAPTOBOTTOM, va("End in %d.%02d", stplyr->linktimer/TICRATE, G_TicsToCentiseconds(stplyr->linktimer)));
}
static void ST_drawNiGHTSHUD(void)
{
INT32 origamount;
INT32 minlink = 1;
INT32 total_spherecount;
const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS));
// Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
if (oldspecialstage || (stplyr->texttimer && stplyr->textvar == 4))
minlink = INT32_MAX;
// When debugging, show "0 Link".
else if (cv_debug & DBG_NIGHTSBASIC)
minlink = 0;
// Drill meter
if (
#ifdef HAVE_BLUA
@ -1508,55 +1570,15 @@ static void ST_drawNiGHTSHUD(void)
}*/
// Link drawing
if (
if (!oldspecialstage
// Don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
&& !(stplyr->texttimer && stplyr->textvar == 4)
#ifdef HAVE_BLUA
LUA_HudEnabled(hud_nightslink) &&
&& LUA_HudEnabled(hud_nightslink)
#endif
stplyr->linkcount > minlink)
&& ((cv_debug & DBG_NIGHTSBASIC) || stplyr->linkcount > 1)) // When debugging, show "0 Link".
{
static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0};
const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0);
INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? 1 : 0);
skincolors_t colornum;
fixed_t x, y, scale;
if (sel != prevsel[q])
{
prevsel[q] = sel;
prevtime[q] = 2 + mag;
}
if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics)))
colornum = SKINCOLOR_ICY;
else
colornum = linkColor[mag][sel];
aflag |= ((stplyr->linktimer < 2*TICRATE/3)
? (9 - 9*stplyr->linktimer/(2*TICRATE/3)) << V_ALPHASHIFT
: 0);
y = (160+11)<<FRACBITS;
aflag |= V_SNAPTOBOTTOM;
x = (160+4)<<FRACBITS;
if (prevtime[q])
{
scale = ((32 + prevtime[q])<<FRACBITS)/32;
prevtime[q]--;
}
else
scale = FRACUNIT;
y -= (11*scale);
ST_DrawNightsOverlayNum(x-(4*scale), y, scale, aflag, (stplyr->linkcount-1), nightsnum, colornum);
V_DrawFixedPatch(x+(4*scale), y, scale, aflag, nightslink,
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
// Show remaining link time left in debug
if (cv_debug & DBG_NIGHTSBASIC)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_SNAPTOBOTTOM, va("End in %d.%02d", stplyr->linktimer/TICRATE, G_TicsToCentiseconds(stplyr->linktimer)));
ST_drawNiGHTSLink();
}
if (gametype == GT_RACE || gametype == GT_COMPETITION)
@ -2448,15 +2470,26 @@ void ST_Drawer(void)
#ifdef SEENAMES
if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo)
{
if (cv_seenames.value == 1)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, player_names[seenplayer-players]);
else if (cv_seenames.value == 2)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF,
va("%s%s", G_GametypeHasTeams() ? ((seenplayer->ctfteam == 1) ? "\x85" : "\x84") : "", player_names[seenplayer-players]));
else //if (cv_seenames.value == 3)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF,
va("%s%s", !G_RingSlingerGametype() || (G_GametypeHasTeams() && players[consoleplayer].ctfteam == seenplayer->ctfteam)
? "\x83" : "\x85", player_names[seenplayer-players]));
INT32 c = 0;
switch (cv_seenames.value)
{
case 1: // Colorless
break;
case 2: // Team
if (G_GametypeHasTeams())
c = (seenplayer->ctfteam == 1) ? V_REDMAP : V_BLUEMAP;
break;
case 3: // Ally/Foe
default:
// Green = Ally, Red = Foe
if (G_GametypeHasTeams())
c = (players[consoleplayer].ctfteam == seenplayer->ctfteam) ? V_GREENMAP : V_REDMAP;
else // Everyone is an ally, or everyone is a foe!
c = (G_RingSlingerGametype()) ? V_REDMAP : V_GREENMAP;
break;
}
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF|c, player_names[seenplayer-players]);
}
#endif

View file

@ -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))<<FRACBITS, pscale);
x -= FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale) + 1;
}
else
x -= FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale);
@ -1236,7 +1236,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{ // Clear the entire screen, from dest to deststop. Yes, this really works.
memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
memset(screens[0], (c&255), vid.width * vid.height * vid.bpp);
return;
}
@ -1299,7 +1299,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
c &= 255;
for (;(--h >= 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<<FRACBITS;
continue;
@ -2126,7 +2131,7 @@ void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
}
w = SHORT(cred_font[c]->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;

View file

@ -1874,7 +1874,9 @@ static void Y_AwardCoopBonuses(void)
players[i].score = MAXSCORE;
}
ptlives = (!ultimatemode && !modeattacking && players[i].lives != 0x7f) ? 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 != 0x7f) ? 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);