Merge remote-tracking branch 'origin/master' into titlecards

This commit is contained in:
Jaime Passos 2019-11-18 17:55:47 -03:00
commit aa659836ee
42 changed files with 474 additions and 191 deletions

View File

@ -90,6 +90,7 @@ SINT8 nodetoplayer[MAXNETNODES];
SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
tic_t servermaxping = 800; // server's max ping. Defaults to 800
static tic_t nettics[MAXNETNODES]; // what tic the client have received static tic_t nettics[MAXNETNODES]; // what tic the client have received
static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet
static UINT8 nodewaiting[MAXNETNODES]; static UINT8 nodewaiting[MAXNETNODES];
@ -610,6 +611,11 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->health = LONG(players[i].mo->health); rsp->health = LONG(players[i].mo->health);
rsp->angle = (angle_t)LONG(players[i].mo->angle); rsp->angle = (angle_t)LONG(players[i].mo->angle);
#ifdef ROTSPRITE
rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle);
#else
rsp->rollangle = 0;
#endif
rsp->x = LONG(players[i].mo->x); rsp->x = LONG(players[i].mo->x);
rsp->y = LONG(players[i].mo->y); rsp->y = LONG(players[i].mo->y);
rsp->z = LONG(players[i].mo->z); rsp->z = LONG(players[i].mo->z);
@ -760,6 +766,9 @@ static void resynch_read_player(resynch_pak *rsp)
//At this point, the player should have a body, whether they were respawned or not. //At this point, the player should have a body, whether they were respawned or not.
P_UnsetThingPosition(players[i].mo); P_UnsetThingPosition(players[i].mo);
players[i].mo->angle = (angle_t)LONG(rsp->angle); players[i].mo->angle = (angle_t)LONG(rsp->angle);
#ifdef ROTSPRITE
players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle);
#endif
players[i].mo->eflags = (UINT16)SHORT(rsp->eflags); players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
players[i].mo->flags = LONG(rsp->flags); players[i].mo->flags = LONG(rsp->flags);
players[i].mo->flags2 = LONG(rsp->flags2); players[i].mo->flags2 = LONG(rsp->flags2);
@ -4208,10 +4217,12 @@ static void HandlePacketFromPlayer(SINT8 node)
//Update client ping table from the server. //Update client ping table from the server.
if (client) if (client)
{ {
INT32 i; UINT8 i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS];
} }
break; break;
@ -4733,6 +4744,14 @@ void TryRunTics(tic_t realtics)
} }
} }
/*
Ping Update except better:
We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out.
If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave.
*/
static INT32 pingtimeout[MAXPLAYERS];
static inline void PingUpdate(void) static inline void PingUpdate(void)
{ {
INT32 i; INT32 i;
@ -4753,6 +4772,8 @@ static inline void PingUpdate(void)
laggers[i] = true; laggers[i] = true;
numlaggers++; numlaggers++;
} }
else
pingtimeout[i] = 0;
} }
//kick lagging players... unless everyone but the server's ping sucks. //kick lagging players... unless everyone but the server's ping sucks.
@ -4763,12 +4784,27 @@ static inline void PingUpdate(void)
{ {
if (playeringame[i] && laggers[i]) if (playeringame[i] && laggers[i])
{ {
char buf[2]; pingtimeout[i]++;
if (pingtimeout[i] > cv_pingtimeout.value)
// ok your net has been bad for too long, you deserve to die.
{
char buf[2];
buf[0] = (char)i; pingtimeout[i] = 0;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2); buf[0] = (char)i;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2);
}
} }
/*
you aren't lagging,
but you aren't free yet.
In case you'll keep spiking,
we just make the timer go back down. (Very unstable net must still get kicked).
*/
else
pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1);
} }
} }
} }
@ -4783,10 +4819,13 @@ static inline void PingUpdate(void)
realpingtable[i] = 0; //Reset each as we go. realpingtable[i] = 0; //Reset each as we go.
} }
// send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked.
netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value;
//send out our ping packets //send out our ping packets
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
if (nodeingame[i]) if (nodeingame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1));
pingmeasurecount = 1; //Reset count pingmeasurecount = 1; //Reset count
} }
@ -4816,7 +4855,7 @@ void NetUpdate(void)
if (server) if (server)
{ {
if (netgame && !(gametime % 255)) if (netgame && !(gametime % 35)) // update once per second.
PingUpdate(); PingUpdate();
// update node latency values so we can take an average later. // update node latency values so we can take an average later.
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)

View File

@ -255,6 +255,7 @@ typedef struct
INT32 health; INT32 health;
angle_t angle; angle_t angle;
angle_t rollangle;
fixed_t x; fixed_t x;
fixed_t y; fixed_t y;
fixed_t z; fixed_t z;
@ -423,9 +424,9 @@ typedef struct
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38) plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE) plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
UINT32 pingtable[MAXPLAYERS]; // 128 bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
@ -487,6 +488,7 @@ extern tic_t jointimeout;
extern UINT16 pingmeasurecount; extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed; extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;

View File

@ -87,6 +87,7 @@ static void JoinTimeout_OnChange(void);
static void CoopStarposts_OnChange(void); static void CoopStarposts_OnChange(void);
static void CoopLives_OnChange(void); static void CoopLives_OnChange(void);
static void ExitMove_OnChange(void);
static void Ringslinger_OnChange(void); static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void); static void Gravity_OnChange(void);
@ -341,6 +342,14 @@ consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
consvar_t cv_showping = {"showping", "Warning", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// Intermission time Tails 04-19-2002 // Intermission time Tails 04-19-2002
static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -353,9 +362,12 @@ consvar_t cv_cooplives = {"cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_C
static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}}; static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}}; static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}};
consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_exitmove = {"exitmove", "Off", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -514,6 +526,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_inttime); CV_RegisterVar(&cv_inttime);
CV_RegisterVar(&cv_advancemap); CV_RegisterVar(&cv_advancemap);
CV_RegisterVar(&cv_playersforexit); CV_RegisterVar(&cv_playersforexit);
CV_RegisterVar(&cv_exitmove);
CV_RegisterVar(&cv_timelimit); CV_RegisterVar(&cv_timelimit);
CV_RegisterVar(&cv_playbackspeed); CV_RegisterVar(&cv_playbackspeed);
CV_RegisterVar(&cv_forceskin); CV_RegisterVar(&cv_forceskin);
@ -577,6 +590,8 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep); CV_RegisterVar(&cv_sleep);
CV_RegisterVar(&cv_maxping); CV_RegisterVar(&cv_maxping);
CV_RegisterVar(&cv_pingtimeout);
CV_RegisterVar(&cv_showping);
#ifdef SEENAMES #ifdef SEENAMES
CV_RegisterVar(&cv_allowseenames); CV_RegisterVar(&cv_allowseenames);
@ -3778,6 +3793,17 @@ static void CoopLives_OnChange(void)
} }
} }
static void ExitMove_OnChange(void)
{
if (!(netgame || multiplayer) || gametype != GT_COOP)
return;
if (cv_exitmove.value)
CONS_Printf(M_GetText("Players can now move after completing the level.\n"));
else
CONS_Printf(M_GetText("Players can no longer move after completing the level.\n"));
}
UINT32 timelimitintics = 0; UINT32 timelimitintics = 0;
/** Deals with a timelimit change by printing the change to the console. /** Deals with a timelimit change by printing the change to the console.

View File

@ -94,7 +94,7 @@ extern consvar_t cv_recycler;
extern consvar_t cv_itemfinder; extern consvar_t cv_itemfinder;
extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit; extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit, cv_exitmove;
extern consvar_t cv_overtime; extern consvar_t cv_overtime;
extern consvar_t cv_startinglives; extern consvar_t cv_startinglives;
@ -106,6 +106,9 @@ extern consvar_t cv_ringslinger, cv_soundtest;
extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes; extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
extern consvar_t cv_maxping; extern consvar_t cv_maxping;
extern consvar_t cv_pingtimeout;
extern consvar_t cv_showping;
extern consvar_t cv_skipmapcheck; extern consvar_t cv_skipmapcheck;

View File

@ -716,7 +716,7 @@ void SV_FileSendTicker(void)
if (ram) if (ram)
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size); M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size) else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile))); I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile));
p->position = LONG(transfer[i].position); p->position = LONG(transfer[i].position);
// Put flag so receiver knows the total size // Put flag so receiver knows the total size
if (transfer[i].position + size == f->size) if (transfer[i].position + size == f->size)
@ -794,7 +794,7 @@ void Got_Filetxpak(void)
// We can receive packet in the wrong order, anyway all os support gaped file // We can receive packet in the wrong order, anyway all os support gaped file
fseek(file->file, pos, SEEK_SET); fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1) if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file))); I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file));
file->currentsize += size; file->currentsize += size;
// Finished? // Finished?

View File

@ -151,6 +151,7 @@ typedef enum
/*** misc ***/ /*** misc ***/
PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
PF_CANCARRY = 1<<29, // Can carry another player? PF_CANCARRY = 1<<29, // Can carry another player?
PF_FINISHED = 1<<30, // The player finished the level. NOT the same as exiting
// up to 1<<31 is free // up to 1<<31 is free
} pflags_t; } pflags_t;

View File

@ -1201,6 +1201,14 @@ static void readlevelheader(MYFILE *f, INT32 num)
word2 = tmp += 2; word2 = tmp += 2;
i = atoi(word2); // used for numerical settings i = atoi(word2); // used for numerical settings
if (fastcmp(word, "LEVELNAME"))
{
deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
continue;
}
// CHEAP HACK: move this over here for lowercase subtitles // CHEAP HACK: move this over here for lowercase subtitles
if (fastcmp(word, "SUBTITLE")) if (fastcmp(word, "SUBTITLE"))
{ {
@ -1344,12 +1352,6 @@ static void readlevelheader(MYFILE *f, INT32 num)
} }
// Strings that can be truncated // Strings that can be truncated
else if (fastcmp(word, "LEVELNAME"))
{
deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
}
else if (fastcmp(word, "SELECTHEADING")) else if (fastcmp(word, "SELECTHEADING"))
{ {
deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2, deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2,
@ -5357,6 +5359,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FSGNA", "S_FSGNA",
"S_FSGNB", "S_FSGNB",
"S_FSGNC", "S_FSGNC",
"S_FSGND",
// Black Eggman (Boss 7) // Black Eggman (Boss 7)
"S_BLACKEGG_STND", "S_BLACKEGG_STND",
@ -7511,6 +7514,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_POPHAT_SHOOT1", "S_POPHAT_SHOOT1",
"S_POPHAT_SHOOT2", "S_POPHAT_SHOOT2",
"S_POPHAT_SHOOT3", "S_POPHAT_SHOOT3",
"S_POPHAT_SHOOT4",
"S_POPSHOT",
"S_POPSHOT_TRAIL",
"S_HIVEELEMENTAL_LOOK", "S_HIVEELEMENTAL_LOOK",
"S_HIVEELEMENTAL_PREPARE1", "S_HIVEELEMENTAL_PREPARE1",
@ -8375,6 +8381,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_PENGUINATOR", "MT_PENGUINATOR",
"MT_POPHAT", "MT_POPHAT",
"MT_POPSHOT", "MT_POPSHOT",
"MT_POPSHOT_TRAIL",
"MT_HIVEELEMENTAL", "MT_HIVEELEMENTAL",
"MT_BUMBLEBORE", "MT_BUMBLEBORE",
@ -8584,6 +8591,7 @@ static const char *const PLAYERFLAG_LIST[] = {
/*** misc ***/ /*** misc ***/
"FORCESTRAFE", // Translate turn inputs into strafe inputs "FORCESTRAFE", // Translate turn inputs into strafe inputs
"CANCARRY", // Can carry? "CANCARRY", // Can carry?
"FINISHED",
NULL // stop loop here. NULL // stop loop here.
}; };

View File

@ -98,6 +98,9 @@ void I_FinishUpdate (void)
if (cv_ticrate.value) if (cv_ticrate.value)
SCR_DisplayTicRate(); SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
//blast it to the screen //blast it to the screen
// this code sucks // this code sucks
//memcpy(dascreen,screens[0],screenwidth*screenheight); //memcpy(dascreen,screens[0],screenwidth*screenheight);

View File

@ -1388,10 +1388,13 @@ void F_StartGameEvaluation(void)
// Credits option in secrets menu // Credits option in secrets menu
if (cursaveslot == -1) if (cursaveslot == -1)
{ {
S_FadeOutStopMusic(2*MUSICRATE);
F_StartGameEnd(); F_StartGameEnd();
return; return;
} }
S_FadeOutStopMusic(5*MUSICRATE);
G_SetGamestate(GS_EVALUATION); G_SetGamestate(GS_EVALUATION);
// Just in case they're open ... somehow // Just in case they're open ... somehow
@ -1638,7 +1641,7 @@ void F_StartEnding(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
S_StopMusic(); // todo: placeholder S_StopMusic();
S_StopSounds(); S_StopSounds();
finalecount = -10; // what? this totally isn't a hack. why are you asking? finalecount = -10; // what? this totally isn't a hack. why are you asking?
@ -1719,6 +1722,9 @@ void F_EndingTicker(void)
return; return;
} }
if (finalecount == -8)
S_ChangeMusicInternal((goodending ? "_endg" : "_endb"), false);
if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets
{ {
endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL); endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL);
@ -2148,7 +2154,6 @@ void F_StartGameEnd(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
S_StopMusic();
S_StopSounds(); S_StopSounds();
// In case menus are still up?!! // In case menus are still up?!!

View File

@ -2889,6 +2889,31 @@ void G_AddPlayer(INT32 playernum)
P_DoPlayerExit(p); P_DoPlayerExit(p);
} }
boolean G_EnoughPlayersFinished(void)
{
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
INT32 total = 0;
INT32 exiting = 0;
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].lives <= 0)
continue;
total++;
if (players[i].pflags & PF_FINISHED)
exiting++;
}
if (exiting)
return exiting * 4 / total >= numneeded;
else
return false;
}
void G_ExitLevel(void) void G_ExitLevel(void)
{ {
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
@ -4087,7 +4112,7 @@ char *G_BuildMapTitle(INT32 mapnum)
len += strlen(mapheaderinfo[mapnum-1]->lvlttl); len += strlen(mapheaderinfo[mapnum-1]->lvlttl);
if (!(mapheaderinfo[mapnum-1]->levelflags & LF_NOZONE)) if (!(mapheaderinfo[mapnum-1]->levelflags & LF_NOZONE))
{ {
zonetext = M_GetText("ZONE"); zonetext = M_GetText("Zone");
len += strlen(zonetext) + 1; // ' ' + zonetext len += strlen(zonetext) + 1; // ' ' + zonetext
} }
if (actnum > 0) if (actnum > 0)
@ -5250,7 +5275,10 @@ void G_ReadMetalTic(mobj_t *metal)
{ // But wait, there's more! { // But wait, there's more!
xziptic = READUINT8(metal_p); xziptic = READUINT8(metal_p);
if (xziptic & EZT_FLIP) if (xziptic & EZT_FLIP)
{
metal->eflags ^= MFE_VERTICALFLIP; metal->eflags ^= MFE_VERTICALFLIP;
metal->flags2 ^= MF2_OBJECTFLIP;
}
if (xziptic & EZT_SCALE) if (xziptic & EZT_SCALE)
{ {
metal->destscale = READFIXED(metal_p); metal->destscale = READFIXED(metal_p);

View File

@ -209,6 +209,7 @@ boolean G_GametypeHasSpectators(void);
boolean G_RingSlingerGametype(void); boolean G_RingSlingerGametype(void);
boolean G_PlatformGametype(void); boolean G_PlatformGametype(void);
boolean G_TagGametype(void); boolean G_TagGametype(void);
boolean G_EnoughPlayersFinished(void);
void G_ExitLevel(void); void G_ExitLevel(void);
void G_NextLevel(void); void G_NextLevel(void);
void G_Continue(void); void G_Continue(void);

View File

@ -4068,6 +4068,7 @@ static gr_vissprite_t *HWR_NewVisSprite(void)
return HWR_GetVisSprite(gr_visspritecount++); return HWR_GetVisSprite(gr_visspritecount++);
} }
#ifdef GLBADSHADOWS
// Finds a floor through which light does not pass. // Finds a floor through which light does not pass.
static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
{ {
@ -4098,6 +4099,7 @@ static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t hei
return floorz; return floorz;
} }
#endif //#ifdef GLBADSHADOWS
// //
// HWR_DoCulling // HWR_DoCulling
@ -4139,6 +4141,7 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
return false; return false;
} }
#ifdef GLBADSHADOWS
static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale) static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
{ {
FOutVector swallVerts[4]; FOutVector swallVerts[4];
@ -4311,6 +4314,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip); HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
} }
} }
#endif //#ifdef GLBADSHADOWS
// This is expecting a pointer to an array containing 4 wallVerts for a sprite // This is expecting a pointer to an array containing 4 wallVerts for a sprite
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts) static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
@ -4386,6 +4390,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap); HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite // Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow. && (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
@ -4401,6 +4406,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
//////////////////// ////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale); HWR_DrawSpriteShadow(spr, gpatch, this_scale);
} }
#endif //#ifdef GLBADSHADOWS
baseWallVerts[0].x = baseWallVerts[3].x = spr->x1; baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
baseWallVerts[2].x = baseWallVerts[1].x = spr->x2; baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
@ -4788,6 +4794,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap); HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite // Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow. && (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
@ -4803,6 +4810,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
//////////////////// ////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale); HWR_DrawSpriteShadow(spr, gpatch, this_scale);
} }
#endif //#ifdef GLBADSHADOWS
// if it has a dispoffset, push it a little towards the camera // if it has a dispoffset, push it a little towards the camera
if (spr->dispoffset) { if (spr->dispoffset) {

View File

@ -2322,13 +2322,14 @@ void HU_Erase(void)
// //
// HU_drawPing // HU_drawPing
// //
void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext) void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags)
{ {
UINT8 numbars = 1; // how many ping bars do we draw? UINT8 numbars = 1; // how many ping bars do we draw?
UINT8 barcolor = 35; // color we use for the bars (green, yellow or red) UINT8 barcolor = 35; // color we use for the bars (green, yellow or red)
SINT8 i = 0; SINT8 i = 0;
SINT8 yoffset = 6; SINT8 yoffset = 6;
INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping), V_ALLOWLOWERCASE)/2); INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping),
V_ALLOWLOWERCASE|flags)/2);
if (ping < 128) if (ping < 128)
{ {
@ -2342,13 +2343,13 @@ void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext)
} }
if (!notext || vid.width >= 640) // how sad, we're using a shit resolution. if (!notext || vid.width >= 640) // how sad, we're using a shit resolution.
V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE, va("%dms", ping)); V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE|flags, va("%dms", ping));
for (i=0; (i<3); i++) // Draw the ping bar for (i=0; (i<3); i++) // Draw the ping bar
{ {
V_DrawFill(x+2 *(i-1), y+yoffset-4, 2, 8-yoffset, 31); V_DrawFill(x+2 *(i-1), y+yoffset-4, 2, 8-yoffset, 31|flags);
if (i < numbars) if (i < numbars)
V_DrawFill(x+2 *(i-1), y+yoffset-3, 1, 8-yoffset-1, barcolor); V_DrawFill(x+2 *(i-1), y+yoffset-3, 1, 8-yoffset-1, barcolor|flags);
yoffset -= 2; yoffset -= 2;
} }
@ -2379,7 +2380,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
if (!splitscreen) // don't draw it on splitscreen, if (!splitscreen) // don't draw it on splitscreen,
{ {
if (!(tab[i].num == serverplayer)) if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 253, y+2, playerpingtable[tab[i].num], false); HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0);
//else //else
// V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER"); // V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER");
} }
@ -2443,7 +2444,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
V_DrawSmallScaledPatch(x-32, y-4, 0, tagico); V_DrawSmallScaledPatch(x-32, y-4, 0, tagico);
} }
if (players[tab[i].num].exiting) if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
if (gametype == GT_RACE) if (gametype == GT_RACE)
@ -2578,7 +2579,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (!splitscreen) if (!splitscreen)
{ {
if (!(tab[i].num == serverplayer)) if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 135, y+3, playerpingtable[tab[i].num], true); HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else //else
//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); //V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
} }
@ -2702,7 +2703,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (!splitscreen) if (!splitscreen)
{ {
if (!(tab[i].num == serverplayer)) if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 113, y+2, playerpingtable[tab[i].num], false); HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else //else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
} }
@ -2733,7 +2734,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
strlcpy(name, tab[i].name, 7); strlcpy(name, tab[i].name, 7);
if (!(tab[i].num == serverplayer)) if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 113, y+2, playerpingtable[tab[i].num], false); HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else //else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
@ -2747,7 +2748,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
if (players[tab[i].num].exiting) if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
// Draw emeralds // Draw emeralds
@ -2841,7 +2842,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
if (!splitscreen) // don't draw it on splitscreen, if (!splitscreen) // don't draw it on splitscreen,
{ {
if (!(tab[i].num == serverplayer)) if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 135, y+3, playerpingtable[tab[i].num], true); HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else //else
// V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); // V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
} }

View File

@ -28,7 +28,7 @@
// Level title font // Level title font
#define LT_FONTSTART '!' // the first font characters #define LT_FONTSTART '!' // the first font characters
#define LT_FONTEND 'Z' // the last font characters #define LT_FONTEND 'z' // the last font characters
#define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1) #define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1)
#define CRED_FONTSTART '!' // the first font character #define CRED_FONTSTART '!' // the first font character
@ -113,7 +113,7 @@ void HU_Drawer(void);
char HU_dequeueChatChar(void); char HU_dequeueChatChar(void);
void HU_Erase(void); void HU_Erase(void);
void HU_clearChatChars(void); void HU_clearChatChars(void);
void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext); // Lat': Ping drawer for scoreboard. void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags); // Lat': Ping drawer for scoreboard.
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer); void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);
void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer); void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer);
void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer); void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);

View File

@ -1487,6 +1487,7 @@ state_t states[NUMSTATES] =
{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA {SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA
{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB {SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB
{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC {SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC
{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGND
// Black Eggman (Boss 7) // Black Eggman (Boss 7)
{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND {SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND
@ -3722,9 +3723,12 @@ state_t states[NUMSTATES] =
{SPR_PENG, 0, 5, {A_FaceTarget}, 0, 0, S_PENGUINATOR_LOOK}, // S_PENGUINATOR_SLIDE5 {SPR_PENG, 0, 5, {A_FaceTarget}, 0, 0, S_PENGUINATOR_LOOK}, // S_PENGUINATOR_SLIDE5
{SPR_POPH, 0, 2, {A_Look}, (2048<<16)|1, 0, S_POPHAT_LOOK}, // S_POPHAT_LOOK {SPR_POPH, 0, 2, {A_Look}, (2048<<16)|1, 0, S_POPHAT_LOOK}, // S_POPHAT_LOOK
{SPR_POPH, 1, 2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1 {SPR_POPH, 1, 0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1
{SPR_POPH, 2, 1, {NULL}, 0, 0, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2 {SPR_POPH, 1, 2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2
{SPR_POPH, 0, 57, {NULL}, 0, 0, S_POPHAT_LOOK}, // S_POPHAT_SHOOT3 {SPR_POPH, 2, 1, {NULL}, 0, 0, S_POPHAT_SHOOT4}, // S_POPHAT_SHOOT3
{SPR_POPH, 0, 57, {NULL}, 0, 0, S_POPHAT_LOOK}, // S_POPHAT_SHOOT4
{SPR_POPH, 3, 3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT}, // S_POPSHOT
{SPR_NULL, 0, 2, {NULL}, 0, 0, S_SPINDUST1}, // S_POPSHOT_TRAIL
{SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK {SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK
{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1 {SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1
@ -6115,11 +6119,11 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
S_FSGNC, // deathstate S_FSGNC, // deathstate
S_NULL, // xdeathstate S_FSGND, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
0, // speed 0, // speed
124*FRACUNIT, // radius 74*FRACUNIT, // radius
640*FRACUNIT, // height 320*FRACUNIT, // height
0, // display offset 0, // display offset
0, // mass 0, // mass
0, // damage 0, // damage
@ -19989,10 +19993,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_POPSHOT { // MT_POPSHOT
-1, // doomednum -1, // doomednum
S_ROCKCRUMBLEI, // spawnstate S_POPSHOT, // spawnstate
1, // spawnhealth 1, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_cannon, // seesound sfx_kc4c, // seesound
0, // reactiontime 0, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
@ -20000,9 +20004,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound sfx_None, // painsound
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
S_XPLD1, // deathstate S_SONIC3KBOSSEXPLOSION1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_pop, // deathsound sfx_cybdth, // deathsound
0, // speed 0, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 32*FRACUNIT, // height
@ -20014,6 +20018,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_POPSHOT_TRAIL
-1, // doomednum
S_POPSHOT_TRAIL,// spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
4*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_HIVEELEMENTAL { // MT_HIVEELEMENTAL
127, // doomednum 127, // doomednum
S_HIVEELEMENTAL_LOOK, // spawnstate S_HIVEELEMENTAL_LOOK, // spawnstate

View File

@ -1657,6 +1657,7 @@ typedef enum state
S_FSGNA, S_FSGNA,
S_FSGNB, S_FSGNB,
S_FSGNC, S_FSGNC,
S_FSGND,
// Black Eggman (Boss 7) // Black Eggman (Boss 7)
S_BLACKEGG_STND, S_BLACKEGG_STND,
@ -3812,6 +3813,9 @@ typedef enum state
S_POPHAT_SHOOT1, S_POPHAT_SHOOT1,
S_POPHAT_SHOOT2, S_POPHAT_SHOOT2,
S_POPHAT_SHOOT3, S_POPHAT_SHOOT3,
S_POPHAT_SHOOT4,
S_POPSHOT,
S_POPSHOT_TRAIL,
S_HIVEELEMENTAL_LOOK, S_HIVEELEMENTAL_LOOK,
S_HIVEELEMENTAL_PREPARE1, S_HIVEELEMENTAL_PREPARE1,
@ -4698,6 +4702,7 @@ typedef enum mobj_type
MT_PENGUINATOR, MT_PENGUINATOR,
MT_POPHAT, MT_POPHAT,
MT_POPSHOT, MT_POPSHOT,
MT_POPSHOT_TRAIL,
MT_HIVEELEMENTAL, MT_HIVEELEMENTAL,
MT_BUMBLEBORE, MT_BUMBLEBORE,

View File

@ -1165,6 +1165,17 @@ static int lib_pElementalFire(lua_State *L)
return 0; return 0;
} }
static int lib_pDoPlayerFinish(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_DoPlayerFinish(player);
return 0;
}
static int lib_pDoPlayerExit(lua_State *L) static int lib_pDoPlayerExit(lua_State *L)
{ {
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -2674,6 +2685,13 @@ static int lib_gSetCustomExitVars(lua_State *L)
return 0; return 0;
} }
static int lib_gEnoughPlayersFinished(lua_State *L)
{
INLEVEL
lua_pushboolean(L, G_EnoughPlayersFinished());
return 1;
}
static int lib_gExitLevel(lua_State *L) static int lib_gExitLevel(lua_State *L)
{ {
int n = lua_gettop(L); // Num arguments int n = lua_gettop(L); // Num arguments
@ -2869,6 +2887,7 @@ static luaL_Reg lib[] = {
{"P_DoBubbleBounce",lib_pDoBubbleBounce}, {"P_DoBubbleBounce",lib_pDoBubbleBounce},
{"P_BlackOw",lib_pBlackOw}, {"P_BlackOw",lib_pBlackOw},
{"P_ElementalFire",lib_pElementalFire}, {"P_ElementalFire",lib_pElementalFire},
{"P_DoPlayerFinish",lib_pDoPlayerFinish},
{"P_DoPlayerExit",lib_pDoPlayerExit}, {"P_DoPlayerExit",lib_pDoPlayerExit},
{"P_InstaThrust",lib_pInstaThrust}, {"P_InstaThrust",lib_pInstaThrust},
{"P_ReturnThrustX",lib_pReturnThrustX}, {"P_ReturnThrustX",lib_pReturnThrustX},
@ -2981,6 +3000,7 @@ static luaL_Reg lib[] = {
{"G_BuildMapName",lib_gBuildMapName}, {"G_BuildMapName",lib_gBuildMapName},
{"G_DoReborn",lib_gDoReborn}, {"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars}, {"G_SetCustomExitVars",lib_gSetCustomExitVars},
{"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished},
{"G_ExitLevel",lib_gExitLevel}, {"G_ExitLevel",lib_gExitLevel},
{"G_IsSpecialStage",lib_gIsSpecialStage}, {"G_IsSpecialStage",lib_gIsSpecialStage},
{"G_GametypeUsesLives",lib_gGametypeUsesLives}, {"G_GametypeUsesLives",lib_gGametypeUsesLives},

View File

@ -744,7 +744,7 @@ static int power_get(lua_State *L)
UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS)); UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS));
powertype_t p = luaL_checkinteger(L, 2); powertype_t p = luaL_checkinteger(L, 2);
if (p >= NUMPOWERS) if (p >= NUMPOWERS)
return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p); return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p);
lua_pushinteger(L, powers[p]); lua_pushinteger(L, powers[p]);
return 1; return 1;
} }
@ -756,7 +756,7 @@ static int power_set(lua_State *L)
powertype_t p = luaL_checkinteger(L, 2); powertype_t p = luaL_checkinteger(L, 2);
UINT16 i = (UINT16)luaL_checkinteger(L, 3); UINT16 i = (UINT16)luaL_checkinteger(L, 3);
if (p >= NUMPOWERS) if (p >= NUMPOWERS)
return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p); return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p);
if (hud_running) if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!"); return luaL_error(L, "Do not alter player_t in HUD rendering code!");
powers[p] = i; powers[p] = i;

View File

@ -16,6 +16,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "command.h" #include "command.h"
#include "m_argv.h" #include "m_argv.h"
#include "m_misc.h"
/** \brief number of arg /** \brief number of arg
*/ */
@ -161,7 +162,7 @@ void M_FindResponseFile(void)
if (!file) if (!file)
I_Error("No more free memory for the response file"); I_Error("No more free memory for the response file");
if (fread(file, size, 1, handle) != 1) if (fread(file, size, 1, handle) != 1)
I_Error("Couldn't read response file because %s", strerror(ferror(handle))); I_Error("Couldn't read response file because %s", M_FileError(handle));
fclose(handle); fclose(handle);
// keep all the command line arguments following @responsefile // keep all the command line arguments following @responsefile

View File

@ -201,14 +201,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv(fixed_t a, fixed_t b)
*/ */
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRem(fixed_t x, fixed_t y) FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRem(fixed_t x, fixed_t y)
{ {
const boolean n = x < 0; return x % y;
x = abs(x);
while (x >= y)
x -= y;
if (n)
return -x;
else
return x;
} }
/** \brief The FixedSqrt function /** \brief The FixedSqrt function

View File

@ -1224,32 +1224,33 @@ static menuitem_t OP_VideoOptionsMenu[] =
NULL, "HUD Transparency", &cv_translucenthud, 66}, NULL, "HUD Transparency", &cv_translucenthud, 66},
{IT_STRING | IT_CVAR, NULL, "Score/Time/Rings", &cv_timetic, 71}, {IT_STRING | IT_CVAR, NULL, "Score/Time/Rings", &cv_timetic, 71},
{IT_STRING | IT_CVAR, NULL, "Show Powerups", &cv_powerupdisplay, 76}, {IT_STRING | IT_CVAR, NULL, "Show Powerups", &cv_powerupdisplay, 76},
{IT_STRING | IT_CVAR, NULL, "Local ping display", &cv_showping, 81}, // shows ping next to framerate if we want to.
#ifdef SEENAMES #ifdef SEENAMES
{IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 81}, {IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 86},
#endif #endif
{IT_HEADER, NULL, "Console", NULL, 90}, {IT_HEADER, NULL, "Console", NULL, 95},
{IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 96}, {IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 101},
{IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 101}, {IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 106},
{IT_HEADER, NULL, "Chat", NULL, 110}, {IT_HEADER, NULL, "Chat", NULL, 115},
{IT_STRING | IT_CVAR, NULL, "Chat Mode", &cv_consolechat, 116}, {IT_STRING | IT_CVAR, NULL, "Chat Mode", &cv_consolechat, 121},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Width", &cv_chatwidth, 121}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Width", &cv_chatwidth, 126},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Height", &cv_chatheight, 126}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Height", &cv_chatheight, 131},
{IT_STRING | IT_CVAR, NULL, "Message Fadeout Time", &cv_chattime, 131}, {IT_STRING | IT_CVAR, NULL, "Message Fadeout Time", &cv_chattime, 136},
{IT_STRING | IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 136}, {IT_STRING | IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 141},
{IT_STRING | IT_CVAR, NULL, "Spam Protection", &cv_chatspamprotection, 141}, {IT_STRING | IT_CVAR, NULL, "Spam Protection", &cv_chatspamprotection, 146},
{IT_STRING | IT_CVAR, NULL, "Chat background tint", &cv_chatbacktint, 146}, {IT_STRING | IT_CVAR, NULL, "Chat background tint", &cv_chatbacktint, 151},
{IT_HEADER, NULL, "Level", NULL, 155}, {IT_HEADER, NULL, "Level", NULL, 160},
{IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 161}, {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 166},
{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 166}, {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 171},
{IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.", &cv_drawdist_nights, 171}, {IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.", &cv_drawdist_nights, 176},
{IT_HEADER, NULL, "Diagnostic", NULL, 180}, {IT_HEADER, NULL, "Diagnostic", NULL, 184},
{IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 186}, {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 190},
{IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 191}, {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 195},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 196}, {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 200},
}; };
static menuitem_t OP_VideoModeMenu[] = static menuitem_t OP_VideoModeMenu[] =
@ -7175,7 +7176,7 @@ static void M_DrawSoundTest(void)
titl = va("%s - ", curplaying->title); titl = va("%s - ", curplaying->title);
} }
else else
titl = "NONE - "; titl = "None - ";
i = V_LevelNameWidth(titl); i = V_LevelNameWidth(titl);
@ -7189,7 +7190,7 @@ static void M_DrawSoundTest(void)
while (x > y) while (x > y)
{ {
x -= i; x -= i;
V_DrawLevelTitle(x, 24, 0, titl); V_DrawLevelTitle(x, 22, 0, titl);
} }
if (curplaying) if (curplaying)

View File

@ -23,6 +23,8 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <errno.h>
// Extended map support. // Extended map support.
#include <ctype.h> #include <ctype.h>
@ -2441,3 +2443,13 @@ void M_SetupMemcpy(void)
M_Memcpy = cpu_cpy; M_Memcpy = cpu_cpy;
#endif #endif
} }
/** Return the appropriate message for a file error or end of file.
*/
const char *M_FileError(FILE *fp)
{
if (ferror(fp))
return strerror(errno);
else
return "end-of-file";
}

View File

@ -94,6 +94,8 @@ void strcatbf(char *s1, const char *s2, const char *s3);
void M_SetupMemcpy(void); void M_SetupMemcpy(void);
const char *M_FileError(FILE *handle);
// counting bits, for weapon ammo code, usually // counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size); FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

View File

@ -4070,19 +4070,28 @@ bossjustdie:
mobj_t *pole = P_SpawnMobj( mobj_t *pole = P_SpawnMobj(
mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time), mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time), mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->floorz + 4*FRACUNIT, mo->tracer->floorz + (256+1)*FRACUNIT,
MT_FSGNB); MT_FSGNB);
P_SetTarget(&pole->tracer, P_SpawnMobj( P_SetTarget(&pole->tracer, P_SpawnMobj(
pole->x, pole->y,
pole->z - 256*FRACUNIT,
MT_FSGNB));
P_SetTarget(&pole->tracer->tracer, P_SpawnMobj(
pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT), pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT),
pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT), pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT),
pole->z + 256*FRACUNIT, pole->z + 256*FRACUNIT,
MT_FSGNA)); MT_FSGNA));
pole->angle = mo->tracer->angle; pole->tracer->flags |= MF_NOCLIPTHING;
pole->tracer->angle = pole->angle - ANGLE_90; P_SetScale(pole, (pole->destscale = 2*FRACUNIT));
P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT));
pole->angle = pole->tracer->angle = mo->tracer->angle;
pole->tracer->tracer->angle = pole->angle - ANGLE_90;
pole->momx = P_ReturnThrustX(pole, pole->angle, speed); pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
pole->momy = P_ReturnThrustY(pole, pole->angle, speed); pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
pole->tracer->momx = pole->momx; pole->tracer->momx = pole->momx;
pole->tracer->momy = pole->momy; pole->tracer->momy = pole->momy;
pole->tracer->tracer->momx = pole->momx;
pole->tracer->tracer->momy = pole->momy;
} }
} }
else else
@ -5121,7 +5130,7 @@ void A_SignPlayer(mobj_t *actor)
return; return;
#endif #endif
if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins) if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins || signcolor >= MAXTRANSLATIONS)
return; return;
// if no face overlay, spawn one // if no face overlay, spawn one
@ -5148,26 +5157,9 @@ void A_SignPlayer(mobj_t *actor)
if (signcolor) if (signcolor)
; ;
else if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor? else if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor?
{
signcolor = skin->prefoppositecolor; signcolor = skin->prefoppositecolor;
/*
If you're here from the comment above Color_Opposite,
the following line is the one which is dependent on the
array being symmetrical. It gets the opposite of the
opposite of your desired colour just so it can get the
brightness frame for the End Sign. It's not a great
design choice, but it's constant time array access and
the idea that the colours should be OPPOSITES is kind
of in the name. If you have a better idea, feel free
to let me know. ~toast 2016/07/20
*/
signframe += (15 - Color_Opposite[Color_Opposite[skin->prefoppositecolor - 1][0] - 1][1]);
}
else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor. else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor.
{
signcolor = Color_Opposite[actor->target->player->skincolor - 1][0]; signcolor = Color_Opposite[actor->target->player->skincolor - 1][0];
signframe += (15 - Color_Opposite[actor->target->player->skincolor - 1][1]);
}
else else
signcolor = SKINCOLOR_NONE; signcolor = SKINCOLOR_NONE;
} }
@ -5188,10 +5180,10 @@ void A_SignPlayer(mobj_t *actor)
skinnum = P_RandomKey(skincount); skinnum = P_RandomKey(skincount);
for (skincount = 0; skincount < numskins; skincount++) for (skincount = 0; skincount < numskins; skincount++)
{ {
if (skincheck(skincount))
skinnum++;
if (skincount > skinnum) if (skincount > skinnum)
break; break;
if (skincheck(skincount))
skinnum++;
} }
} }
else // otherwise, advance 1 skin else // otherwise, advance 1 skin
@ -5203,42 +5195,46 @@ void A_SignPlayer(mobj_t *actor)
skin = &skins[skinnum]; skin = &skins[skinnum];
} }
else // specific skin else // specific skin
{
skin = &skins[locvar1]; skin = &skins[locvar1];
}
facecolor = skin->prefcolor; facecolor = skin->prefcolor;
if (signcolor) if (signcolor)
; ;
else if (skin->prefoppositecolor) else if (skin->prefoppositecolor)
{
signcolor = skin->prefoppositecolor; signcolor = skin->prefoppositecolor;
} else if (facecolor)
else
{
signcolor = Color_Opposite[facecolor - 1][0]; signcolor = Color_Opposite[facecolor - 1][0];
}
signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
} }
if (skin != NULL && skin->sprites[SPR2_SIGN].numframes) // player face if (skin && skin->sprites[SPR2_SIGN].numframes) // player face
{ {
ov->color = facecolor; ov->color = facecolor;
ov->skin = skin; ov->skin = skin;
P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
actor->tracer->color = signcolor;
actor->tracer->frame = signframe;
} }
else // Eggman face else // Eggman face
{ {
ov->color = SKINCOLOR_NONE; ov->color = SKINCOLOR_NONE;
P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN
if (signcolor) if (!signcolor)
actor->tracer->color = signcolor; signcolor = SKINCOLOR_CARBON;
else
actor->tracer->color = signcolor = SKINCOLOR_CARBON;
actor->tracer->frame = signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
} }
actor->tracer->color = signcolor;
/*
If you're here from the comment above Color_Opposite,
the following line is the one which is dependent on the
array being symmetrical. It gets the opposite of the
opposite of your desired colour just so it can get the
brightness frame for the End Sign. It's not a great
design choice, but it's constant time array access and
the idea that the colours should be OPPOSITES is kind
of in the name. If you have a better idea, feel free
to let me know. ~toast 2016/07/20
*/
if (signcolor && signcolor < MAXSKINCOLORS)
signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
actor->tracer->frame = signframe;
} }
// Function: A_OverlayThink // Function: A_OverlayThink

View File

@ -2741,7 +2741,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
case MT_EGGTRAP: case MT_EGGTRAP:
// Time for birdies! Yaaaaaaaay! // Time for birdies! Yaaaaaaaay!
target->fuse = TICRATE*2; target->fuse = TICRATE;
break; break;
case MT_MINECART: case MT_MINECART:
@ -3002,6 +3002,10 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN); P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN);
S_StartSound(target, sfx_nghurt); S_StartSound(target, sfx_nghurt);
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
if (oldnightstime > 10*TICRATE if (oldnightstime > 10*TICRATE
&& player->nightstime < 10*TICRATE) && player->nightstime < 10*TICRATE)
{ {

View File

@ -172,6 +172,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle);
void P_DoPityCheck(player_t *player); void P_DoPityCheck(player_t *player);
void P_PlayerThink(player_t *player); void P_PlayerThink(player_t *player);
void P_PlayerAfterThink(player_t *player); void P_PlayerAfterThink(player_t *player);
void P_DoPlayerFinish(player_t *player);
void P_DoPlayerExit(player_t *player); void P_DoPlayerExit(player_t *player);
void P_NightserizePlayer(player_t *player, INT32 ptime); void P_NightserizePlayer(player_t *player, INT32 ptime);

View File

@ -592,6 +592,9 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
if (!(tails->pflags & PF_CANCARRY)) if (!(tails->pflags & PF_CANCARRY))
return; return;
if (sonic->pflags & PF_FINISHED)
return;
if (tails->bot == 1) if (tails->bot == 1)
return; return;
@ -661,31 +664,32 @@ static void P_SlapStick(mobj_t *fang, mobj_t *pole)
momx2 = fang->momx/dist; momx2 = fang->momx/dist;
momy2 = fang->momy/dist; momy2 = fang->momy/dist;
pole->tracer->momx = momx1 + (dist-1)*momx2; pole->tracer->tracer->momx = momx1 + (dist-1)*momx2;
pole->tracer->momy = momy1 + (dist-1)*momy2; pole->tracer->tracer->momy = momy1 + (dist-1)*momy2;
fang->momx = (dist-1)*momx1 + momx2; fang->momx = (dist-1)*momx1 + momx2;
fang->momy = (dist-1)*momy1 + momy2; fang->momy = (dist-1)*momy1 + momy2;
#undef dist #undef dist
P_SetMobjState(pole, pole->info->deathstate); P_SetObjectMomZ(pole->tracer->tracer, 6*FRACUNIT, false);
pole->tracer->tracer->flags &= ~(MF_NOGRAVITY|MF_NOCLIP);
P_SetObjectMomZ(pole->tracer, 6*FRACUNIT, false); pole->tracer->tracer->movedir = ANGLE_67h;
pole->tracer->flags &= ~(MF_NOGRAVITY|MF_NOCLIP); if ((R_PointToAngle(fang->x - pole->tracer->tracer->x, fang->y - pole->tracer->tracer->y) - pole->angle) > ANGLE_180)
pole->tracer->movedir = ANGLE_67h; pole->tracer->tracer->movedir = InvAngle(pole->tracer->movedir);
if ((R_PointToAngle(fang->x - pole->tracer->x, fang->y - pole->tracer->y) - pole->angle) > ANGLE_180)
pole->tracer->movedir = InvAngle(pole->tracer->movedir);
P_SetObjectMomZ(fang, 14*FRACUNIT, false); P_SetObjectMomZ(fang, 14*FRACUNIT, false);
fang->flags |= MF_NOGRAVITY|MF_NOCLIP; fang->flags |= MF_NOGRAVITY|MF_NOCLIP;
P_SetMobjState(fang, fang->info->xdeathstate); P_SetMobjState(fang, fang->info->xdeathstate);
pole->tracer->tics = pole->tics = fang->tics; pole->tracer->tracer->tics = pole->tracer->tics = pole->tics = fang->tics;
var1 = var2 = 0; var1 = var2 = 0;
A_Scream(pole->tracer); A_Scream(pole->tracer->tracer);
S_StartSound(fang, sfx_altdi1); S_StartSound(fang, sfx_altdi1);
P_SetTarget(&pole->tracer->tracer, NULL);
P_SetMobjState(pole->tracer, pole->info->xdeathstate);
P_SetTarget(&pole->tracer, NULL); P_SetTarget(&pole->tracer, NULL);
P_SetMobjState(pole, pole->info->deathstate);
} }
static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel) static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel)
@ -1089,7 +1093,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // overhead return true; // overhead
if (thing->z + thing->height < tmthing->z) if (thing->z + thing->height < tmthing->z)
return true; // underneath return true; // underneath
if (!thing->tracer) if (!thing->tracer || !thing->tracer->tracer)
return true; return true;
P_SlapStick(tmthing, thing); P_SlapStick(tmthing, thing);
// no return value was used in the original prototype script at this point, // no return value was used in the original prototype script at this point,

View File

@ -246,6 +246,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
{ {
case S_PLAY_STND: case S_PLAY_STND:
case S_PLAY_WAIT: case S_PLAY_WAIT:
case S_PLAY_NIGHTS_STAND:
player->panim = PA_IDLE; player->panim = PA_IDLE;
break; break;
case S_PLAY_EDGE: case S_PLAY_EDGE:
@ -254,6 +255,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
case S_PLAY_WALK: case S_PLAY_WALK:
case S_PLAY_SKID: case S_PLAY_SKID:
case S_PLAY_FLOAT: case S_PLAY_FLOAT:
case S_PLAY_NIGHTS_FLOAT:
player->panim = PA_WALK; player->panim = PA_WALK;
break; break;
case S_PLAY_RUN: case S_PLAY_RUN:
@ -269,6 +271,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
break; break;
case S_PLAY_ROLL: case S_PLAY_ROLL:
//case S_PLAY_SPINDASH: -- everyone can ROLL thanks to zoom tubes... //case S_PLAY_SPINDASH: -- everyone can ROLL thanks to zoom tubes...
case S_PLAY_NIGHTS_ATTACK:
player->panim = PA_ROLL; player->panim = PA_ROLL;
break; break;
case S_PLAY_JUMP: case S_PLAY_JUMP:
@ -8227,7 +8230,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->flags2 ^= MF2_DONTDRAW; mobj->flags2 ^= MF2_DONTDRAW;
break; break;
case MT_EGGTRAP: // Egg Capsule animal release case MT_EGGTRAP: // Egg Capsule animal release
if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7)) if (mobj->fuse > 0)// && mobj->fuse < TICRATE-(TICRATE/7))
{ {
INT32 i; INT32 i;
fixed_t x,y,z; fixed_t x,y,z;
@ -8236,9 +8239,9 @@ void P_MobjThinker(mobj_t *mobj)
mobj_t *flicky; mobj_t *flicky;
z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64)<<FRACBITS); z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64)<<FRACBITS);
for (i = 0; i < 2; i++) for (i = 0; i < 3; i++)
{ {
const angle_t fa = (P_RandomByte()*FINEANGLES/16) & FINEMASK; const angle_t fa = P_RandomKey(FINEANGLES) & FINEMASK;
ns = 64 * FRACUNIT; ns = 64 * FRACUNIT;
x = mobj->x + FixedMul(FINESINE(fa),ns); x = mobj->x + FixedMul(FINESINE(fa),ns);
y = mobj->y + FixedMul(FINECOSINE(fa),ns); y = mobj->y + FixedMul(FINECOSINE(fa),ns);

View File

@ -4675,7 +4675,7 @@ DoneSection2:
{ {
INT32 lineindex; INT32 lineindex;
P_DoPlayerExit(player); P_DoPlayerFinish(player);
P_SetupSignExit(player); P_SetupSignExit(player);
// important: use sector->tag on next line instead of player->mo->subsector->tag // important: use sector->tag on next line instead of player->mo->subsector->tag

View File

@ -636,6 +636,10 @@ static void P_DeNightserizePlayer(player_t *player)
player->marebonuslap = 0; player->marebonuslap = 0;
player->flyangle = 0; player->flyangle = 0;
player->anotherflyangle = 0; player->anotherflyangle = 0;
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
P_SetTarget(&player->mo->target, NULL); P_SetTarget(&player->mo->target, NULL);
P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL)); P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL));
@ -762,6 +766,9 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->secondjump = 0; player->secondjump = 0;
player->flyangle = 0; player->flyangle = 0;
player->anotherflyangle = 0; player->anotherflyangle = 0;
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
player->powers[pw_shield] = SH_NONE; player->powers[pw_shield] = SH_NONE;
player->powers[pw_super] = 0; player->powers[pw_super] = 0;
@ -2124,6 +2131,30 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
} }
/** Called when \p player finishes the level.
*
* Only use for cases where the player should be able to move
* while waiting for others to finish. Otherwise, use P_DoPlayerExit().
*
* In single player or if ::cv_exitmove is disabled, this will also cause
* P_PlayerThink() to call P_DoPlayerExit(), so you do not need to
* make a special cases for those.
*
* \param player The player who finished the level.
* \sa P_DoPlayerExit
*
*/
void P_DoPlayerFinish(player_t *player)
{
if (player->pflags & PF_FINISHED)
return;
player->pflags |= PF_FINISHED;
if (netgame)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
}
// //
// P_DoPlayerExit // P_DoPlayerExit
// //
@ -2158,12 +2189,14 @@ void P_DoPlayerExit(player_t *player)
player->pflags |= P_GetJumpFlags(player); player->pflags |= P_GetJumpFlags(player);
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
} }
else if (player->pflags & PF_STARTDASH)
{
player->pflags &= ~PF_STARTDASH;
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
player->powers[pw_underwater] = 0; player->powers[pw_underwater] = 0;
player->powers[pw_spacetime] = 0; player->powers[pw_spacetime] = 0;
P_RestoreMusic(player); P_RestoreMusic(player);
if (playeringame[player-players] && netgame && !circuitmap)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
} }
#define SPACESPECIAL 12 #define SPACESPECIAL 12
@ -7701,9 +7734,9 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
I_Assert(!P_MobjWasRemoved(player->mo)); I_Assert(!P_MobjWasRemoved(player->mo));
if (player->mo->eflags & MFE_VERTICALFLIP) if (player->mo->eflags & MFE_VERTICALFLIP)
ground = player->mo->ceilingz - FixedMul(mobjinfo[MT_SPINFIRE].height, player->mo->scale); ground = player->mo->ceilingz - FixedMul(mobjinfo[MT_SPINFIRE].height - 1, player->mo->scale);
else else
ground = player->mo->floorz; ground = player->mo->floorz + 1;
if (cropcircle) if (cropcircle)
{ {
@ -9889,10 +9922,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
pviewheight = FixedMul(41*player->height/48, mo->scale); pviewheight = FixedMul(41*player->height/48, mo->scale);
if (mo->eflags & MFE_VERTICALFLIP) if (sign)
z = mo->z + mo->height - pviewheight - camheight + distz; {
if (mo->eflags & MFE_VERTICALFLIP)
z = sign->ceilingz - pviewheight - camheight;
else
z = sign->floorz + pviewheight + camheight;
}
else else
z = mo->z + pviewheight + camheight + distz; {
if (mo->eflags & MFE_VERTICALFLIP)
z = mo->z + mo->height - pviewheight - camheight + distz;
else
z = mo->z + pviewheight + camheight + distz;
}
// move camera down to move under lower ceilings // move camera down to move under lower ceilings
newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1));
@ -11400,6 +11443,14 @@ void P_PlayerThink(player_t *player)
} }
} }
if (player->pflags & PF_FINISHED)
{
if (cv_exitmove.value && !G_EnoughPlayersFinished())
player->exiting = 0;
else
P_DoPlayerExit(player);
}
// check water content, set stuff in mobj // check water content, set stuff in mobj
P_MobjCheckWater(player->mo); P_MobjCheckWater(player->mo);

View File

@ -123,8 +123,12 @@ consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChan
consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif //#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
#ifdef GLBADSHADOWS
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif //#ifdef GLBADSHADOWS
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
@ -1172,8 +1176,12 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_chasecam); CV_RegisterVar(&cv_chasecam);
CV_RegisterVar(&cv_chasecam2); CV_RegisterVar(&cv_chasecam2);
#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
CV_RegisterVar(&cv_shadow); CV_RegisterVar(&cv_shadow);
#endif //#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_shadowoffs); CV_RegisterVar(&cv_shadowoffs);
#endif //#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_skybox); CV_RegisterVar(&cv_skybox);
CV_RegisterVar(&cv_cam_dist); CV_RegisterVar(&cv_cam_dist);

View File

@ -76,7 +76,12 @@ extern consvar_t cv_showhud, cv_translucenthud;
extern consvar_t cv_homremoval; extern consvar_t cv_homremoval;
extern consvar_t cv_chasecam, cv_chasecam2; extern consvar_t cv_chasecam, cv_chasecam2;
extern consvar_t cv_flipcam, cv_flipcam2; extern consvar_t cv_flipcam, cv_flipcam2;
extern consvar_t cv_shadow, cv_shadowoffs; #if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
extern consvar_t cv_shadow;
#endif
#ifdef GLBADSHADOWS
extern conscar_t cv_shadowoffs;
#endif //#ifdef GLBADSHADOWS
extern consvar_t cv_translucency; extern consvar_t cv_translucency;
extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip; extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
extern consvar_t cv_skybox; extern consvar_t cv_skybox;

View File

@ -1196,20 +1196,20 @@ static void R_ProjectSprite(mobj_t *thing)
#ifdef ROTSPRITE #ifdef ROTSPRITE
sprinfo = NULL; sprinfo = NULL;
#endif #endif
}
if (rot >= sprdef->numframes) if (rot >= sprdef->numframes)
{
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
rot = thing->frame&FF_FRAMEMASK;
if (!thing->skin)
{ {
thing->state->sprite = thing->sprite; CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
thing->state->frame = thing->frame; sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
if (thing->sprite == thing->state->sprite && thing->frame == thing->state->frame)
{
thing->state->sprite = states[S_UNKNOWN].sprite;
thing->state->frame = states[S_UNKNOWN].frame;
}
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
rot = thing->frame&FF_FRAMEMASK;
} }
} }

View File

@ -428,6 +428,17 @@ void SCR_DisplayTicRate(void)
lasttic = ontic; lasttic = ontic;
} }
void SCR_DisplayLocalPing(void)
{
UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P
if (cv_showping.value == 1 || (cv_showping.value == 2 && servermaxping && ping > servermaxping)) // only show 2 (warning) if our ping is at a bad level
{
INT32 dispy = cv_ticrate.value ? 180 : 189;
HU_drawPing(307, dispy, ping, true, V_SNAPTORIGHT | V_SNAPTOBOTTOM);
}
}
void SCR_ClosedCaptions(void) void SCR_ClosedCaptions(void)
{ {
UINT8 i; UINT8 i;

View File

@ -167,5 +167,6 @@ FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
// move out to main code for consistency // move out to main code for consistency
void SCR_DisplayTicRate(void); void SCR_DisplayTicRate(void);
void SCR_ClosedCaptions(void); void SCR_ClosedCaptions(void);
void SCR_DisplayLocalPing(void);
#undef DNWH #undef DNWH
#endif //__SCREEN_H__ #endif //__SCREEN_H__

View File

@ -1180,6 +1180,9 @@ void I_FinishUpdate(void)
{ {
if (cv_ticrate.value) if (cv_ticrate.value)
SCR_DisplayTicRate(); SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
} }
if (rendermode == render_soft && screens[0]) if (rendermode == render_soft && screens[0])

View File

@ -779,7 +779,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"kc49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop-shot"},
{"kc4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power up"}, {"kc4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power up"},
{"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View File

@ -1308,7 +1308,7 @@ void ST_drawTitleCard(void)
lvlttlxpos -= V_LevelActNumWidth(actnum); lvlttlxpos -= V_LevelActNumWidth(actnum);
ttlnumxpos = lvlttlxpos + V_LevelNameWidth(lvlttl); ttlnumxpos = lvlttlxpos + V_LevelNameWidth(lvlttl);
zonexpos = ttlnumxpos - V_LevelNameWidth(M_GetText("ZONE")); zonexpos = ttlnumxpos - V_LevelNameWidth(M_GetText("Zone"));
ttlnumxpos++; ttlnumxpos++;
if (lvlttlxpos < 0) if (lvlttlxpos < 0)
@ -1332,7 +1332,7 @@ void ST_drawTitleCard(void)
V_DrawLevelTitle(lvlttlxpos - ttlscroll, 80, V_PERPLAYER, lvlttl); V_DrawLevelTitle(lvlttlxpos - ttlscroll, 80, V_PERPLAYER, lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
V_DrawLevelTitle(zonexpos + ttlscroll, 104, V_PERPLAYER, M_GetText("ZONE")); V_DrawLevelTitle(zonexpos + ttlscroll, 104, V_PERPLAYER, M_GetText("Zone"));
V_DrawCenteredString(subttlxpos - ttlnumxpos, 128, V_PERPLAYER|V_ALLOWLOWERCASE, subttl); V_DrawCenteredString(subttlxpos - ttlnumxpos, 128, V_PERPLAYER|V_ALLOWLOWERCASE, subttl);
lt_lasttic = lt_ticker; lt_lasttic = lt_ticker;
@ -2236,7 +2236,7 @@ static void ST_drawTextHUD(void)
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
} }
if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && stplyr->exiting) if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && (stplyr->exiting || (stplyr->pflags & PF_FINISHED)))
{ {
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
if (numneeded) if (numneeded)
@ -2251,7 +2251,7 @@ static void ST_drawTextHUD(void)
continue; continue;
total++; total++;
if (players[i].exiting) if (players[i].exiting || (players[i].pflags & PF_FINISHED))
exiting++; exiting++;
} }

View File

@ -2900,7 +2900,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
continue; continue;
} }
c = toupper(*ch) - LT_FONTSTART; c = *ch - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
{ {
cx += 16*dupx; cx += 16*dupx;
@ -2935,7 +2935,7 @@ INT32 V_LevelNameWidth(const char *string)
{ {
if (string[i] & 0x80) if (string[i] & 0x80)
continue; continue;
c = toupper(string[i]) - LT_FONTSTART; c = string[i] - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
w += 16; w += 16;
else else
@ -2954,7 +2954,7 @@ INT32 V_LevelNameHeight(const char *string)
for (i = 0; i < strlen(string); i++) for (i = 0; i < strlen(string); i++)
{ {
c = toupper(string[i]) - LT_FONTSTART; c = string[i] - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
continue; continue;

View File

@ -383,7 +383,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
// read the header // read the header
if (fread(&header, 1, sizeof header, handle) < sizeof header) if (fread(&header, 1, sizeof header, handle) < sizeof header)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), strerror(ferror(handle))); CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), M_FileError(handle));
return NULL; return NULL;
} }
@ -406,7 +406,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
if (fseek(handle, header.infotableofs, SEEK_SET) == -1 if (fseek(handle, header.infotableofs, SEEK_SET) == -1
|| fread(fileinfo, 1, i, handle) < i) || fread(fileinfo, 1, i, handle) < i)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), strerror(ferror(handle))); CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), M_FileError(handle));
free(fileinfov); free(fileinfov);
return NULL; return NULL;
} }
@ -427,7 +427,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
handle) < sizeof realsize) handle) < sizeof realsize)
{ {
I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout? I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout?
filename, strerror(ferror(handle))); filename, M_FileError(handle));
} }
realsize = LONG(realsize); realsize = LONG(realsize);
if (realsize != 0) if (realsize != 0)
@ -565,7 +565,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fseek(handle, -4, SEEK_CUR); fseek(handle, -4, SEEK_CUR);
if (fread(&zend, 1, sizeof zend, handle) < sizeof zend) if (fread(&zend, 1, sizeof zend, handle) < sizeof zend)
{ {
CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", strerror(ferror(handle))); CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle));
return NULL; return NULL;
} }
numlumps = zend.entries; numlumps = zend.entries;
@ -582,7 +582,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t))
{ {
CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", strerror(ferror(handle))); CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle));
Z_Free(lumpinfo); Z_Free(lumpinfo);
free(zentries); free(zentries);
return NULL; return NULL;
@ -602,7 +602,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fullname = malloc(zentry->namelen + 1); fullname = malloc(zentry->namelen + 1);
if (fgets(fullname, zentry->namelen + 1, handle) != fullname) if (fgets(fullname, zentry->namelen + 1, handle) != fullname)
{ {
CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", strerror(ferror(handle))); CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle));
Z_Free(lumpinfo); Z_Free(lumpinfo);
free(zentries); free(zentries);
free(fullname); free(fullname);

View File

@ -371,6 +371,9 @@ void I_FinishUpdate(void)
if (cv_ticrate.value) if (cv_ticrate.value)
SCR_DisplayTicRate(); SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
// //
if (bDIBMode) if (bDIBMode)
{ {

View File

@ -399,10 +399,13 @@ void Y_IntermissionDrawer(void)
// draw the "got through act" lines and act number // draw the "got through act" lines and act number
V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1); V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1);
V_DrawLevelTitle(data.coop.passedx2, 49+V_LevelNameHeight(data.coop.passed2)+2, 0, data.coop.passed2); {
INT32 h = V_LevelNameHeight(data.coop.passed2);
V_DrawLevelTitle(data.coop.passedx2, 49+h+2, 0, data.coop.passed2);
if (data.coop.actnum) if (data.coop.actnum)
V_DrawLevelActNum(244, 57, 0, data.coop.actnum); V_DrawLevelActNum(244, 42+h, 0, data.coop.actnum);
}
bonusy = 150; bonusy = 150;
// Total // Total
@ -485,10 +488,10 @@ void Y_IntermissionDrawer(void)
if (drawsection == 1) if (drawsection == 1)
{ {
const char *ringtext = "\x82" "50 RINGS, NO SHIELD"; const char *ringtext = "\x82" "50 rings, no shield";
const char *tut1text = "\x82" "PRESS " "\x80" "SPIN"; const char *tut1text = "\x82" "press " "\x80" "spin";
const char *tut2text = "\x82" "MID-" "\x80" "JUMP"; const char *tut2text = "\x82" "mid-" "\x80" "jump";
ttheight = 16; ttheight = 8;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed3) + 2; ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3);
@ -497,9 +500,9 @@ void Y_IntermissionDrawer(void)
ttheight = 108; ttheight = 108;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext); V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext);
ttheight += V_LevelNameHeight(ringtext) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text);
ttheight += V_LevelNameHeight(tut1text) + 2; ttheight += V_LevelNameHeight(tut1text) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text);
ttheight += V_LevelNameHeight(tut2text) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text); V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text);
} }
else else
@ -1384,21 +1387,21 @@ void Y_StartIntermission(void)
// too long so just show "YOU GOT THROUGH THE ACT" // too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13) if (strlen(skins[players[consoleplayer].skin].realname) > 13)
{ {
strcpy(data.coop.passed1, "YOU GOT"); strcpy(data.coop.passed1, "you got");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
} }
// long enough that "X GOT" won't fit so use "X PASSED THE ACT" // long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8) else if (strlen(skins[players[consoleplayer].skin].realname) > 8)
{ {
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "PASSED ACT" : "PASSED THE ACT"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act");
} }
// length is okay for normal use // length is okay for normal use
else else
{ {
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s GOT", snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
} }
// set X positions // set X positions
@ -1498,7 +1501,7 @@ void Y_StartIntermission(void)
// set up the "got through act" message according to skin name // set up the "got through act" message according to skin name
if (stagefailed) if (stagefailed)
{ {
strcpy(data.spec.passed2, "SPECIAL STAGE"); strcpy(data.spec.passed2, "Special Stage");
data.spec.passed1[0] = '\0'; data.spec.passed1[0] = '\0';
} }
else if (ALL7EMERALDS(emeralds)) else if (ALL7EMERALDS(emeralds))
@ -1507,13 +1510,13 @@ void Y_StartIntermission(void)
sizeof data.spec.passed1, "%s", sizeof data.spec.passed1, "%s",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin].realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
strcpy(data.spec.passed2, "GOT THEM ALL!"); strcpy(data.spec.passed2, "got them all!");
if (players[consoleplayer].charflags & SF_SUPER) if (players[consoleplayer].charflags & SF_SUPER)
{ {
strcpy(data.spec.passed3, "CAN NOW BECOME"); strcpy(data.spec.passed3, "can now become");
snprintf(data.spec.passed4, snprintf(data.spec.passed4,
sizeof data.spec.passed4, "SUPER %s", sizeof data.spec.passed4, "Super %s",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin].realname);
data.spec.passed4[sizeof data.spec.passed4 - 1] = '\0'; data.spec.passed4[sizeof data.spec.passed4 - 1] = '\0';
} }
@ -1523,13 +1526,13 @@ void Y_StartIntermission(void)
if (strlen(skins[players[consoleplayer].skin].realname) <= SKINNAMESIZE-5) if (strlen(skins[players[consoleplayer].skin].realname) <= SKINNAMESIZE-5)
{ {
snprintf(data.spec.passed1, snprintf(data.spec.passed1,
sizeof data.spec.passed1, "%s GOT", sizeof data.spec.passed1, "%s got",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin].realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
} }
else else
strcpy(data.spec.passed1, "YOU GOT"); strcpy(data.spec.passed1, "You got");
strcpy(data.spec.passed2, "A CHAOS EMERALD"); strcpy(data.spec.passed2, "a Chaos Emerald");
if (P_GetNextEmerald() > 6) if (P_GetNextEmerald() > 6)
{ {
data.spec.passed2[15] = '?'; data.spec.passed2[15] = '?';