Merge branch 'master' into lua-more-stuff

This commit is contained in:
Monster Iestyn 2017-01-25 17:32:08 +00:00
commit 58abd6f056
38 changed files with 1527 additions and 693 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.14 VERSION 2.1.17
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.1.16.{branch}-{build} version: 2.1.17.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

View file

@ -391,18 +391,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
endif() endif()
if(${SRB2_CONFIG_USEASM}) if(${SRB2_CONFIG_USEASM})
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
if(${CMAKE_SYSTEM} MATCHES "Linux")
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
endif()
if(${SRB2_CONFIG_YASM}) if(${SRB2_CONFIG_YASM})
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_YASM) enable_language(ASM_YASM)
else() else()
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_NASM) enable_language(ASM_NASM)
endif() endif()
set(SRB2_USEASM ON) set(SRB2_USEASM ON)
add_definitions(-DUSEASM) add_definitions(-DUSEASM)
else() else()
set(SRB2_USEASM OFF) set(SRB2_USEASM OFF)
add_definitions(-DNOASM -DNONX86) add_definitions(-DNONX86 -DNORUSEASM)
endif() endif()
# Targets # Targets

View file

@ -72,14 +72,21 @@
#define MAX_REASONLENGTH 30 #define MAX_REASONLENGTH 30
boolean server = true; // true or false but !server == client boolean server = true; // true or false but !server == client
#define client (!server)
boolean nodownload = false; boolean nodownload = false;
static boolean serverrunning = false; static boolean serverrunning = false;
INT32 serverplayer = 0; INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
// server specific vars // Server specific vars
UINT8 playernode[MAXPLAYERS]; UINT8 playernode[MAXPLAYERS];
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
tic_t jointimeout = (10*TICRATE);
static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
#ifdef NEWPING #ifdef NEWPING
UINT16 pingmeasurecount = 1; UINT16 pingmeasurecount = 1;
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
@ -108,7 +115,7 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
static UINT8 player_joining = false; static UINT8 player_joining = false;
UINT8 hu_resynching = 0; UINT8 hu_resynching = 0;
// client specific // Client specific
static ticcmd_t localcmds; static ticcmd_t localcmds;
static ticcmd_t localcmds2; static ticcmd_t localcmds2;
static boolean cl_packetmissed; static boolean cl_packetmissed;
@ -404,7 +411,7 @@ static void ExtraDataTicker(void)
// If you are a client, you can safely forget the net commands for this tic // If you are a client, you can safely forget the net commands for this tic
// If you are the server, you need to remember them until every client has been aknowledged, // If you are the server, you need to remember them until every client has been aknowledged,
// because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it // because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
if (!server) if (client)
D_FreeTextcmd(gametic); D_FreeTextcmd(gametic);
} }
@ -912,7 +919,7 @@ static inline void resynch_read_others(resynchend_pak *p)
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
// We don't care if they're in the game or not, just write all the data. // We don't care if they're in the game or not, just write all the data.
players[i].spectator = !(loc_ingame & i<<i); players[i].spectator = !(loc_ingame & (1<<i));
players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
players[i].score = (UINT32)LONG(p->score[i]); players[i].score = (UINT32)LONG(p->score[i]);
players[i].numboxes = SHORT(p->numboxes[i]); players[i].numboxes = SHORT(p->numboxes[i]);
@ -1033,6 +1040,9 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
resynch_status[node] &= ~(1<<rsg); resynch_status[node] &= ~(1<<rsg);
--resynch_score[node]; // unpenalize --resynch_score[node]; // unpenalize
} }
// Don't let resynch cause a timeout
freezetimeout[node] = I_GetTime() + connectiontimeout;
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// end resynch // end resynch
@ -1126,12 +1136,17 @@ static inline void CL_DrawConnectionStatus(void)
{ {
#ifdef JOININGAME #ifdef JOININGAME
case CL_DOWNLOADSAVEGAME: case CL_DOWNLOADSAVEGAME:
cltext = M_GetText("Downloading game state..."); if (lastfilenum != -1)
Net_GetNetStat(); {
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, cltext = M_GetText("Downloading game state...");
va(" %4uK",fileneeded[lastfilenum].currentsize>>10)); Net_GetNetStat();
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024)); va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024));
}
else
cltext = M_GetText("Waiting to download game state...");
break; break;
#endif #endif
case CL_ASKJOIN: case CL_ASKJOIN:
@ -1146,25 +1161,31 @@ static inline void CL_DrawConnectionStatus(void)
} }
else else
{ {
INT32 dldlength; if (lastfilenum != -1)
static char tempname[32]; {
INT32 dldlength;
static char tempname[32];
Net_GetNetStat(); Net_GetNetStat();
dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256); dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
if (dldlength > 256) if (dldlength > 256)
dldlength = 256; dldlength = 256;
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96); V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96);
memset(tempname, 0, sizeof(tempname)); memset(tempname, 0, sizeof(tempname));
nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31)); nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
va(M_GetText("Downloading \"%s\""), tempname)); va(M_GetText("Downloading \"%s\""), tempname));
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10)); va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024)); va("%3.1fK/s ", ((double)getbps)/1024));
}
else
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
M_GetText("Waiting to download files..."));
} }
} }
#endif #endif
@ -1453,6 +1474,10 @@ static void SV_SendSaveGame(INT32 node)
SV_SendRam(node, buffertosend, length, SF_RAM, 0); SV_SendRam(node, buffertosend, length, SF_RAM, 0);
save_p = NULL; save_p = NULL;
// Remember when we started sending the savegame so we can handle timeouts
sendingsavegame[node] = true;
freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
} }
#ifdef DUMPCONSISTENCY #ifdef DUMPCONSISTENCY
@ -1745,7 +1770,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
return false; return false;
} }
if (!server) if (client)
{ {
D_ParseFileneeded(serverlist[i].info.fileneedednum, D_ParseFileneeded(serverlist[i].info.fileneedednum,
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
@ -1919,7 +1944,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
*oldtic = I_GetTime(); *oldtic = I_GetTime();
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
if (!server && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
{ {
F_TitleScreenTicker(true); F_TitleScreenTicker(true);
F_TitleScreenDrawer(); F_TitleScreenDrawer();
@ -1961,7 +1986,7 @@ static void CL_ConnectToServer(boolean viams)
cl_mode = CL_SEARCHING; cl_mode = CL_SEARCHING;
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
lastfilenum = 0; lastfilenum = -1;
#endif #endif
#ifdef JOININGAME #ifdef JOININGAME
@ -2032,7 +2057,7 @@ static void CL_ConnectToServer(boolean viams)
pnumnodes++; pnumnodes++;
} }
} }
while (!(cl_mode == CL_CONNECTED && (!server || (server && nodewaited <= pnumnodes)))); while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
DEBFILE(va("Synchronisation Finished\n")); DEBFILE(va("Synchronisation Finished\n"));
@ -2569,6 +2594,14 @@ static void Command_Kick(void)
WRITESINT8(p, pn); WRITESINT8(p, pn);
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
if (COM_Argc() == 2) if (COM_Argc() == 2)
{ {
WRITEUINT8(p, KICK_MSG_GO_AWAY); WRITEUINT8(p, KICK_MSG_GO_AWAY);
@ -2781,7 +2814,12 @@ consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL
// max file size to send to a player (in kilobytes) // max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = {"maxsend", "1024", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
// Speed of file downloading (in packets per tic)
static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static void Got_AddPlayer(UINT8 **p, INT32 playernum); static void Got_AddPlayer(UINT8 **p, INT32 playernum);
@ -2804,6 +2842,9 @@ void D_ClientServerInit(void)
COM_AddCommand("drop", Command_Drop); COM_AddCommand("drop", Command_Drop);
COM_AddCommand("droprate", Command_Droprate); COM_AddCommand("droprate", Command_Droprate);
#endif #endif
#ifdef _DEBUG
COM_AddCommand("numnodes", Command_Numnodes);
#endif
#endif #endif
RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_KICK, Got_KickCmd);
@ -2839,6 +2880,7 @@ static void ResetNode(INT32 node)
supposedtics[node] = gametic; supposedtics[node] = gametic;
nodewaiting[node] = 0; nodewaiting[node] = 0;
playerpernode[node] = 0; playerpernode[node] = 0;
sendingsavegame[node] = false;
} }
void SV_ResetServer(void) void SV_ResetServer(void)
@ -3131,7 +3173,7 @@ void CL_RemoveSplitscreenPlayer(void)
// is there a game running // is there a game running
boolean Playing(void) boolean Playing(void)
{ {
return (server && serverrunning) || (!server && cl_mode == CL_CONNECTED); return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
} }
boolean SV_SpawnServer(void) boolean SV_SpawnServer(void)
@ -3394,12 +3436,19 @@ static void HandlePacketFromAwayNode(SINT8 node)
} }
if (cl_mode == CL_WAITJOINRESPONSE) if (cl_mode == CL_WAITJOINRESPONSE)
{ {
// Save the reason so it can be displayed after quitting the netgame
char *reason = strdup(netbuffer->u.serverrefuse.reason);
if (!reason)
I_Error("Out of memory!\n");
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
D_StartTitle(); D_StartTitle();
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING); reason), NULL, MM_NOTHING);
free(reason);
// Will be reset by caller. Signals refusal. // Will be reset by caller. Signals refusal.
cl_mode = CL_ABORTED; cl_mode = CL_ABORTED;
@ -3420,7 +3469,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (cl_mode != CL_WAITJOINRESPONSE) if (cl_mode != CL_WAITJOINRESPONSE)
break; break;
if (!server) if (client)
{ {
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype; gametype = netbuffer->u.servercfg.gametype;
@ -3548,7 +3597,7 @@ FILESTAMP
case PT_CLIENT2MIS: case PT_CLIENT2MIS:
case PT_NODEKEEPALIVE: case PT_NODEKEEPALIVE:
case PT_NODEKEEPALIVEMIS: case PT_NODEKEEPALIVEMIS:
if (!server) if (client)
break; break;
// Ignore tics from those not synched // Ignore tics from those not synched
@ -3581,6 +3630,13 @@ FILESTAMP
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS) || netbuffer->packettype == PT_NODEKEEPALIVEMIS)
break; break;
// If a client sends a ticcmd it should mean they are done receiving the savegame
sendingsavegame[node] = false;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
/// \todo Use a separate cvar for that kind of timeout?
freezetimeout[node] = I_GetTime() + connectiontimeout;
// Copy ticcmd // Copy ticcmd
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
@ -3647,7 +3703,7 @@ FILESTAMP
case PT_TEXTCMD2: // splitscreen special case PT_TEXTCMD2: // splitscreen special
netconsole = nodetoplayer2[node]; netconsole = nodetoplayer2[node];
case PT_TEXTCMD: case PT_TEXTCMD:
if (!server) if (client)
break; break;
if (netconsole < 0 || netconsole >= MAXPLAYERS) if (netconsole < 0 || netconsole >= MAXPLAYERS)
@ -3691,7 +3747,7 @@ FILESTAMP
break; break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
case PT_CLIENTQUIT: case PT_CLIENTQUIT:
if (!server) if (client)
break; break;
// nodeingame will be put false in the execution of kick command // nodeingame will be put false in the execution of kick command
@ -3723,7 +3779,7 @@ FILESTAMP
// Only accept PT_RESYNCHEND from the server. // Only accept PT_RESYNCHEND from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
if (server) if (server)
{ {
@ -3801,13 +3857,20 @@ FILESTAMP
neededtic = realend; neededtic = realend;
} }
else else
{
DEBFILE(va("frame not in bound: %u\n", neededtic)); DEBFILE(va("frame not in bound: %u\n", neededtic));
/*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart)
I_Error("Received an out of order PT_SERVERTICS packet!\n"
"Got tics %d-%d, needed tic %d\n\n"
"Please report this crash on the Master Board,\n"
"IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/
}
break; break;
case PT_RESYNCHING: case PT_RESYNCHING:
// Only accept PT_RESYNCHING from the server. // Only accept PT_RESYNCHING from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
if (server) if (server)
{ {
@ -3827,7 +3890,7 @@ FILESTAMP
// Only accept PT_PING from the server. // Only accept PT_PING from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_PING", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
if (server) if (server)
{ {
@ -3841,7 +3904,7 @@ FILESTAMP
} }
//Update client ping table from the server. //Update client ping table from the server.
if (!server) if (client)
{ {
INT32 i; INT32 i;
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
@ -3854,7 +3917,7 @@ FILESTAMP
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
if (!server) if (client)
Got_Filetxpak(); Got_Filetxpak();
break; break;
default: default:
@ -3884,17 +3947,18 @@ FILESTAMP
HandleConnect(node); HandleConnect(node);
continue; continue;
} }
if (netbuffer->packettype == PT_SERVERSHUTDOWN && node == servernode if (node == servernode && client && cl_mode != CL_SEARCHING)
&& !server && cl_mode != CL_SEARCHING)
{ {
HandleShutdown(node); if (netbuffer->packettype == PT_SERVERSHUTDOWN)
continue; {
} HandleShutdown(node);
if (netbuffer->packettype == PT_NODETIMEOUT && node == servernode continue;
&& !server && cl_mode != CL_SEARCHING) }
{ if (netbuffer->packettype == PT_NODETIMEOUT)
HandleTimeout(node); {
continue; HandleTimeout(node);
continue;
}
} }
#ifndef NONET #ifndef NONET
@ -3911,7 +3975,7 @@ FILESTAMP
// Packet received from someone already playing // Packet received from someone already playing
if (nodeingame[node]) if (nodeingame[node])
HandlePacketFromPlayer(node); HandlePacketFromPlayer(node);
// Packet received from someone trying to join // Packet received from someone not playing
else else
HandlePacketFromAwayNode(node); HandlePacketFromAwayNode(node);
} }
@ -4042,7 +4106,7 @@ static void CL_SendClientCmd(void)
if (gamestate == GS_WAITINGPLAYERS) if (gamestate == GS_WAITINGPLAYERS)
{ {
// send NODEKEEPALIVE packet // Send PT_NODEKEEPALIVE packet
netbuffer->packettype += 4; netbuffer->packettype += 4;
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
@ -4052,7 +4116,7 @@ static void CL_SendClientCmd(void)
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// send a special packet with 2 cmd for splitscreen // Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame) if (splitscreen || botingame)
{ {
netbuffer->packettype += 2; netbuffer->packettype += 2;
@ -4067,23 +4131,23 @@ static void CL_SendClientCmd(void)
if (cl_mode == CL_CONNECTED || dedicated) if (cl_mode == CL_CONNECTED || dedicated)
{ {
// send extra data if needed // Send extra data if needed
if (localtextcmd[0]) if (localtextcmd[0])
{ {
netbuffer->packettype = PT_TEXTCMD; netbuffer->packettype = PT_TEXTCMD;
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
// all extra data have been sended // All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // send can fail... if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
localtextcmd[0] = 0; localtextcmd[0] = 0;
} }
// send extra data if needed for player 2 (splitscreen) // Send extra data if needed for player 2 (splitscreen)
if (localtextcmd2[0]) if (localtextcmd2[0])
{ {
netbuffer->packettype = PT_TEXTCMD2; netbuffer->packettype = PT_TEXTCMD2;
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
// all extra data have been sended // All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // send can fail... if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
localtextcmd2[0] = 0; localtextcmd2[0] = 0;
} }
} }
@ -4347,7 +4411,7 @@ static inline void PingUpdate(void)
//check for ping limit breakage. //check for ping limit breakage.
if (cv_maxping.value) if (cv_maxping.value)
{ {
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
{ {
@ -4361,7 +4425,7 @@ static inline void PingUpdate(void)
//in that case, it is probably the server's fault. //in that case, it is probably the server's fault.
if (numlaggers < D_NumPlayers() - 1) if (numlaggers < D_NumPlayers() - 1)
{ {
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && laggers[i]) if (playeringame[i] && laggers[i])
{ {
@ -4376,7 +4440,7 @@ static inline void PingUpdate(void)
} }
//make the ping packet and clear server data for next one //make the ping packet and clear server data for next one
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
//server takes a snapshot of the real ping for display. //server takes a snapshot of the real ping for display.
@ -4386,7 +4450,7 @@ static inline void PingUpdate(void)
} }
//send out our ping packets //send out our ping packets
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
@ -4435,7 +4499,7 @@ void NetUpdate(void)
} }
#endif #endif
if (!server) if (client)
maketic = neededtic; maketic = neededtic;
Local_Maketic(realtics); // make local tic, and call menu? Local_Maketic(realtics); // make local tic, and call menu?
@ -4450,7 +4514,7 @@ FILESTAMP
MasterClient_Ticker(); // Acking the Master Server MasterClient_Ticker(); // Acking the Master Server
if (!server) if (client)
{ {
if (!resynch_local_inprogress) if (!resynch_local_inprogress)
CL_SendClientCmd(); // Send tic cmd CL_SendClientCmd(); // Send tic cmd
@ -4500,6 +4564,11 @@ FILESTAMP
} }
} }
Net_AckTicker(); Net_AckTicker();
// Handle timeouts to prevent definitive freezes from happenning
if (server)
for (i = 1; i < MAXNETNODES; i++)
if (nodeingame[i] && freezetimeout[i] < I_GetTime())
Net_ConnectionTimeout(i);
nowtime /= NEWTICRATERATIO; nowtime /= NEWTICRATERATIO;
if (nowtime > resptime) if (nowtime > resptime)
{ {

View file

@ -80,6 +80,9 @@ typedef enum
void Command_Drop(void); void Command_Drop(void);
void Command_Droprate(void); void Command_Droprate(void);
#endif #endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
@ -447,6 +450,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
extern boolean server; extern boolean server;
#define client (!server)
extern boolean dedicated; // For dedicated server extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH; extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode; extern boolean acceptnewnode;
@ -454,13 +458,14 @@ extern SINT8 servernode;
void Command_Ping_f(void); void Command_Ping_f(void);
extern tic_t connectiontimeout; extern tic_t connectiontimeout;
extern tic_t jointimeout;
#ifdef NEWPING #ifdef NEWPING
extern UINT16 pingmeasurecount; extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
#endif #endif
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend; extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
// Used in d_net, the only dependence // Used in d_net, the only dependence
tic_t ExpandTics(INT32 low); tic_t ExpandTics(INT32 low);

View file

@ -42,7 +42,7 @@
// Normally maketic >= gametic > 0 // Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000 #define FORCECLOSE 0x8000
tic_t connectiontimeout = (15*TICRATE); tic_t connectiontimeout = (10*TICRATE);
/// \brief network packet /// \brief network packet
doomcom_t *doomcom = NULL; doomcom_t *doomcom = NULL;
@ -62,7 +62,7 @@ INT32 net_bandwidth;
/// \brief max length per packet /// \brief max length per packet
INT16 hardware_MAXPACKETLENGTH; INT16 hardware_MAXPACKETLENGTH;
void (*I_NetGet)(void) = NULL; boolean (*I_NetGet)(void) = NULL;
void (*I_NetSend)(void) = NULL; void (*I_NetSend)(void) = NULL;
boolean (*I_NetCanSend)(void) = NULL; boolean (*I_NetCanSend)(void) = NULL;
boolean (*I_NetCanGet)(void) = NULL; boolean (*I_NetCanGet)(void) = NULL;
@ -142,7 +142,7 @@ typedef struct
UINT8 destinationnode; // The node to send the ack to UINT8 destinationnode; // The node to send the ack to
tic_t senttime; // The time when the ack was sent tic_t senttime; // The time when the ack was sent
UINT16 length; // The packet size UINT16 length; // The packet size
UINT16 resentnum; // The number of UINT16 resentnum; // The number of times the ack has been resent
union { union {
SINT8 raw[MAXPACKETLENGTH]; SINT8 raw[MAXPACKETLENGTH];
doomdata_t data; doomdata_t data;
@ -152,11 +152,12 @@ typedef struct
typedef enum typedef enum
{ {
CLOSE = 1, // flag is set when connection is closing NF_CLOSE = 1, // Flag is set when connection is closing
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t; } node_flags_t;
#ifndef NONET #ifndef NONET
// table of packet that was not acknowleged can be resend (the sender window) // Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS]; static ackpak_t ackpak[MAXACKPACKETS];
#endif #endif
@ -274,6 +275,38 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
/** Counts how many acks are free
*
* \param urgent True if the type of the packet meant to
* use an ack is lower than PT_CANFAIL
* If for some reason you don't want use it
* for any packet type in particular,
* just set to false
* \return The number of free acks
*
*/
INT32 Net_GetFreeAcks(boolean urgent)
{
INT32 i, numfreeslot = 0;
INT32 n = 0; // Number of free acks found
for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
// For low priority packets, make sure to let freeslots so urgent packets can be sent
if (!urgent)
{
numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
n++;
}
return n;
}
// Get a ack to send in the queue of this node // Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node) static UINT8 GetAcktosend(INT32 node)
{ {
@ -298,7 +331,7 @@ static void RemoveAck(INT32 i)
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum)); DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif #endif
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
if (nodes[node].flags & CLOSE) if (nodes[node].flags & NF_CLOSE)
Net_CloseConnection(node); Net_CloseConnection(node);
} }
@ -452,8 +485,13 @@ static void GotAcks(void)
} }
#endif #endif
static inline void Net_ConnectionTimeout(INT32 node) void Net_ConnectionTimeout(INT32 node)
{ {
// Don't timeout several times
if (nodes[node].flags & NF_TIMEOUT)
return;
nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue) // Send a very special packet to self (hack the reboundstore queue)
// Main code will handle it // Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
@ -484,7 +522,7 @@ void Net_AckTicker(void)
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime()) if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif #endif
{ {
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE)) if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
{ {
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n", DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
i, nodei)); i, nodei));
@ -520,7 +558,7 @@ void Net_AckTicker(void)
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime()) if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i); Net_SendAcks(i);
if (!(nodes[i].flags & CLOSE) if (!(nodes[i].flags & NF_CLOSE)
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime()) && nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
{ {
Net_ConnectionTimeout(i); Net_ConnectionTimeout(i);
@ -678,7 +716,7 @@ void Net_CloseConnection(INT32 node)
if (!node) if (!node)
return; return;
nodes[node].flags |= CLOSE; nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem) // try to Send ack back (two army problem)
if (GetAcktosend(node)) if (GetAcktosend(node))
@ -813,18 +851,20 @@ static void DebugPrintpacket(const char *header)
case PT_SERVERTICS: case PT_SERVERTICS:
{ {
servertics_pak *serverpak = &netbuffer->u.serverpak; servertics_pak *serverpak = &netbuffer->u.serverpak;
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics]; UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd; size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ", fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd)); (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
fprintfstring((char *)cmd, 3); /// \todo Display more readable information about net commands
fprintfstringnewline((char *)cmd, ntxtcmd);
/*fprintfstring((char *)cmd, 3);
if (ntxtcmd > 4) if (ntxtcmd > 4)
{ {
fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]); fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4); fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
} }
fprintf(debugfile, "\n"); fprintf(debugfile, "\n");*/
break; break;
} }
case PT_CLIENTCMD: case PT_CLIENTCMD:
@ -891,7 +931,7 @@ void Command_Drop(void)
if (COM_Argc() < 2) if (COM_Argc() < 2)
{ {
CONS_Printf("drop <packettype> [quantity]: drop packets\n" CONS_Printf("drop <packettype> [quantity]: drop packets\n"
"drop reset: cancel all packet drops"); "drop reset: cancel all packet drops\n");
return; return;
} }
@ -1067,6 +1107,8 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
// //
boolean HGetPacket(void) boolean HGetPacket(void)
{ {
//boolean nodejustjoined;
// Get a packet from self // Get a packet from self
if (rebound_tail != rebound_head) if (rebound_tail != rebound_head)
{ {
@ -1092,9 +1134,10 @@ boolean HGetPacket(void)
while(true) while(true)
{ {
//nodejustjoined = I_NetGet();
I_NetGet(); I_NetGet();
if (doomcom->remotenode == -1) if (doomcom->remotenode == -1) // No packet received
return false; return false;
getbytes += packetheaderlength + doomcom->datalength; // For stat getbytes += packetheaderlength + doomcom->datalength; // For stat
@ -1110,6 +1153,7 @@ boolean HGetPacket(void)
if (netbuffer->checksum != NetbufferChecksum()) if (netbuffer->checksum != NetbufferChecksum())
{ {
DEBFILE("Bad packet checksum\n"); DEBFILE("Bad packet checksum\n");
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
Net_CloseConnection(doomcom->remotenode); Net_CloseConnection(doomcom->remotenode);
continue; continue;
} }
@ -1119,11 +1163,26 @@ boolean HGetPacket(void)
DebugPrintpacket("GET"); DebugPrintpacket("GET");
#endif #endif
// proceed the ack and ackreturn field /*// If a new node sends an unexpected packet, just ignore it
if (nodejustjoined && server
&& !(netbuffer->packettype == PT_ASKINFO
|| netbuffer->packettype == PT_SERVERINFO
|| netbuffer->packettype == PT_PLAYERINFO
|| netbuffer->packettype == PT_REQUESTFILE
|| netbuffer->packettype == PT_ASKINFOVIAMS
|| netbuffer->packettype == PT_CLIENTJOIN))
{
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
continue;
}*/
// Proceed the ack and ackreturn field
if (!Processackpak()) if (!Processackpak())
continue; // discarded (duplicated) continue; // discarded (duplicated)
// a packet with just ackreturn // A packet with just ackreturn
if (netbuffer->packettype == PT_NOTHING) if (netbuffer->packettype == PT_NOTHING)
{ {
GotAcks(); GotAcks();
@ -1136,9 +1195,10 @@ boolean HGetPacket(void)
return true; return true;
} }
static void Internal_Get(void) static boolean Internal_Get(void)
{ {
doomcom->remotenode = -1; doomcom->remotenode = -1;
return false;
} }
FUNCNORETURN static ATTRNORETURN void Internal_Send(void) FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
@ -1223,7 +1283,7 @@ boolean D_CheckNetGame(void)
if (netgame) if (netgame)
ret = true; ret = true;
if (!server && netgame) if (client && netgame)
netgame = false; netgame = false;
server = true; // WTF? server always true??? server = true; // WTF? server always true???
// no! The deault mode is server. Client is set elsewhere // no! The deault mode is server. Client is set elsewhere

View file

@ -39,6 +39,7 @@ extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if a
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void); void Net_AckTicker(void);
// If reliable return true if packet sent, 0 else // If reliable return true if packet sent, 0 else
@ -53,6 +54,7 @@ boolean D_CheckNetGame(void);
void D_CloseConnection(void); void D_CloseConnection(void);
void Net_UnAcknowledgePacket(INT32 node); void Net_UnAcknowledgePacket(INT32 node);
void Net_CloseConnection(INT32 node); void Net_CloseConnection(INT32 node);
void Net_ConnectionTimeout(INT32 node);
void Net_AbortPacketType(UINT8 packettype); void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node); void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout); void Net_WaitAllAckReceived(UINT32 timeout);

View file

@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
static void TeamScramble_OnChange(void); static void TeamScramble_OnChange(void);
static void NetTimeout_OnChange(void); static void NetTimeout_OnChange(void);
static void JoinTimeout_OnChange(void);
static void Ringslinger_OnChange(void); static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void); static void Gravity_OnChange(void);
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 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};
#ifdef NEWPING #ifdef NEWPING
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};
#endif #endif
@ -546,9 +549,12 @@ void D_RegisterServerCommands(void)
// d_clisrv // d_clisrv
CV_RegisterVar(&cv_maxplayers); CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed);
COM_AddCommand("ping", Command_Ping_f); COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
CV_RegisterVar(&cv_jointimeout);
CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep); CV_RegisterVar(&cv_sleep);
@ -1005,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true; return true;
// Force skin in effect. // Force skin in effect.
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1)) if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
return false; return false;
// Can change skin in intermission and whatnot. // Can change skin in intermission and whatnot.
@ -1616,7 +1622,7 @@ static void Command_Map_f(void)
return; return;
} }
if (!server && !(adminplayer == consoleplayer)) if (client && !(adminplayer == consoleplayer))
{ {
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return; return;
@ -1943,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
// You can't suicide someone else. Nice try, there. // You can't suicide someone else. Nice try, there.
if (suicideplayer != playernum || (!G_PlatformGametype())) if (suicideplayer != playernum || (!G_PlatformGametype()))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server) if (server)
{ {
XBOXSTATIC UINT8 buf[2]; XBOXSTATIC UINT8 buf[2];
@ -2658,7 +2664,7 @@ static void Command_Changepassword_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security. // If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else #else
if (!server) // cannot change remotely if (client) // cannot change remotely
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2717,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16); READMEM(*cp, sentmd5, 16);
if (!server) if (client)
return; return;
// Do the final pass to compare with the sent md5 // Do the final pass to compare with the sent md5
@ -2739,7 +2745,7 @@ static void Command_Verify_f(void)
char *temp; char *temp;
INT32 playernum; INT32 playernum;
if (!server) if (client)
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2823,7 +2829,7 @@ static void Command_MotD_f(void)
return; return;
} }
if ((netgame || multiplayer) && !server) if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd)); SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else else
{ {
@ -3080,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
// Only the server processes this message. // Only the server processes this message.
if (!server) if (client)
return; return;
// Disallow non-printing characters and semicolons. // Disallow non-printing characters and semicolons.
@ -3347,6 +3353,11 @@ static void NetTimeout_OnChange(void)
connectiontimeout = (tic_t)cv_nettimeout.value; connectiontimeout = (tic_t)cv_nettimeout.value;
} }
static void JoinTimeout_OnChange(void)
{
jointimeout = (tic_t)cv_jointimeout.value;
}
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

@ -97,7 +97,7 @@ char downloaddir[256] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
// for cl loading screen // for cl loading screen
INT32 lastfilenum = 0; INT32 lastfilenum = -1;
#endif #endif
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
@ -487,6 +487,9 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
INT32 i; INT32 i;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
// Find the last file in the list and set a pointer to its "next" field // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
while (*q) while (*q)
@ -609,6 +612,8 @@ static void SV_EndFileSend(INT32 node)
switch (p->ram) switch (p->ram)
{ {
case SF_FILE: // It's a file, close it and free its filename case SF_FILE: // It's a file, close it and free its filename
if (cv_noticedownload.value)
CONS_Printf("Ending file transfer for node %d\n", node);
if (transfer[node].currentfile) if (transfer[node].currentfile)
fclose(transfer[node].currentfile); fclose(transfer[node].currentfile);
free(p->id.filename); free(p->id.filename);
@ -636,6 +641,9 @@ static void SV_EndFileSend(INT32 node)
/** Handles file transmission /** Handles file transmission
* *
* \todo Use an acknowledging method more adapted to file transmission
* The current download speed suffers from lack of ack packets,
* especially when the one downloading has high latency
* *
*/ */
void SV_FileSendTicker(void) void SV_FileSendTicker(void)
@ -644,17 +652,38 @@ void SV_FileSendTicker(void)
filetx_pak *p; filetx_pak *p;
size_t size; size_t size;
filetx_t *f; filetx_t *f;
INT32 packetsent = PACKETPERTIC, ram, i; INT32 packetsent, ram, i, j;
INT32 maxpacketsent;
if (!filestosend) if (!filestosend) // No file to send
return; return;
if (!packetsent)
packetsent++; if (cv_downloadspeed.value) // New (and experimental) behavior
{
packetsent = cv_downloadspeed.value;
// Don't send more packets than we have free acks
#ifndef NONET
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
#else
maxpacketsent = 1;
#endif
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
packetsent = maxpacketsent;
}
else // Old behavior
{
packetsent = PACKETPERTIC;
if (!packetsent)
packetsent = 1;
}
netbuffer->packettype = PT_FILEFRAGMENT;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth) // (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filestosend != 0) while (packetsent-- && filestosend != 0)
{ {
for (i = currentnode, ram = 0; ram < MAXNETNODES; for (i = currentnode, j = 0; j < MAXNETNODES;
i = (i+1) % MAXNETNODES, ram++) i = (i+1) % MAXNETNODES, j++)
{ {
if (transfer[i].txlist) if (transfer[i].txlist)
goto found; goto found;
@ -713,7 +742,6 @@ void SV_FileSendTicker(void)
p->position |= LONG(0x80000000); p->position |= LONG(0x80000000);
p->fileid = f->fileid; p->fileid = f->fileid;
p->size = SHORT((UINT16)size); p->size = SHORT((UINT16)size);
netbuffer->packettype = PT_FILEFRAGMENT;
// Send the packet // Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
@ -735,27 +763,40 @@ void SV_FileSendTicker(void)
void Got_Filetxpak(void) void Got_Filetxpak(void)
{ {
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum];
char *filename = file->filename;
static INT32 filetime = 0; static INT32 filetime = 0;
if (!(strcmp(filename, "srb2.srb")
&& strcmp(filename, "srb2.wad")
&& strcmp(filename, "zones.dta")
&& strcmp(filename, "player.dta")
&& strcmp(filename, "rings.dta")
&& strcmp(filename, "patch.dta")
&& strcmp(filename, "music.dta")
))
I_Error("Tried to download \"%s\"", filename);
if (filenum >= fileneedednum) if (filenum >= fileneedednum)
{ {
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum)); DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
return; return;
} }
if (fileneeded[filenum].status == FS_REQUESTED) if (file->status == FS_REQUESTED)
{ {
if (fileneeded[filenum].file) if (file->file)
I_Error("Got_Filetxpak: already open file\n"); I_Error("Got_Filetxpak: already open file\n");
fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb"); file->file = fopen(filename, "wb");
if (!fileneeded[filenum].file) if (!file->file)
I_Error("Can't create file %s: %s", fileneeded[filenum].filename, strerror(errno)); I_Error("Can't create file %s: %s", filename, strerror(errno));
CONS_Printf("\r%s...\n",fileneeded[filenum].filename); CONS_Printf("\r%s...\n",filename);
fileneeded[filenum].currentsize = 0; file->currentsize = 0;
fileneeded[filenum].status = FS_DOWNLOADING; file->status = FS_DOWNLOADING;
} }
if (fileneeded[filenum].status == FS_DOWNLOADING) if (file->status == FS_DOWNLOADING)
{ {
UINT32 pos = LONG(netbuffer->u.filetxpak.position); UINT32 pos = LONG(netbuffer->u.filetxpak.position);
UINT16 size = SHORT(netbuffer->u.filetxpak.size); UINT16 size = SHORT(netbuffer->u.filetxpak.size);
@ -764,27 +805,47 @@ void Got_Filetxpak(void)
if (pos & 0x80000000) if (pos & 0x80000000)
{ {
pos &= ~0x80000000; pos &= ~0x80000000;
fileneeded[filenum].totalsize = pos + size; file->totalsize = pos + size;
} }
// 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(fileneeded[filenum].file, pos, SEEK_SET); fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1) if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file))); I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
fileneeded[filenum].currentsize += size; file->currentsize += size;
// Finished? // Finished?
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize) if (file->currentsize == file->totalsize)
{ {
fclose(fileneeded[filenum].file); fclose(file->file);
fileneeded[filenum].file = NULL; file->file = NULL;
fileneeded[filenum].status = FS_FOUND; file->status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"), CONS_Printf(M_GetText("Downloading %s...(done)\n"),
fileneeded[filenum].filename); filename);
} }
} }
else else
I_Error("Received a file not requested\n"); {
const char *s;
switch(file->status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_FOUND:
s = "FS_FOUND";
break;
case FS_OPEN:
s = "FS_OPEN";
break;
case FS_MD5SUMBAD:
s = "FS_MD5SUMBAD";
break;
default:
s = "unknown";
break;
}
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
}
// Send ack back quickly // Send ack back quickly
if (++filetime == 3) if (++filetime == 3)
{ {
@ -797,12 +858,23 @@ void Got_Filetxpak(void)
#endif #endif
} }
/** Cancels all file requests for a node /** \brief Checks if a node is downloading a file
* *
* \param node The destination * \param node The node to check for
* \sa SV_EndFileSend * \return True if the node is downloading a file
* *
*/ */
boolean SV_SendingFile(INT32 node)
{
return transfer[node].txlist != NULL;
}
/** Cancels all file requests for a node
*
* \param node The destination
* \sa SV_EndFileSend
*
*/
void SV_AbortSendFiles(INT32 node) void SV_AbortSendFiles(INT32 node)
{ {
while (transfer[node].txlist) while (transfer[node].txlist)

View file

@ -65,6 +65,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
void SV_FileSendTicker(void); void SV_FileSendTicker(void);
void Got_Filetxpak(void); void Got_Filetxpak(void);
boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);

View file

@ -1961,6 +1961,7 @@ static actionpointer_t actionpointers[] =
{{A_FlickyCheck}, "A_FLICKYCHECK"}, {{A_FlickyCheck}, "A_FLICKYCHECK"},
{{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"}, {{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"},
{{A_FlickyFlutter}, "A_FLICKYFLUTTER"}, {{A_FlickyFlutter}, "A_FLICKYFLUTTER"},
{{A_FlameParticle}, "A_FLAMEPARTICLE"},
{{NULL}, "NONE"}, {{NULL}, "NONE"},
@ -4398,6 +4399,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_GOOP1", "S_GOOP1",
"S_GOOP2", "S_GOOP2",
"S_GOOP3", "S_GOOP3",
"S_GOOPTRAIL",
// Boss 3 // Boss 3
"S_EGGMOBILE3_STND", "S_EGGMOBILE3_STND",
@ -4974,7 +4976,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Starpost // Starpost
"S_STARPOST_IDLE", "S_STARPOST_IDLE",
"S_STARPOST_FLASH", "S_STARPOST_FLASH",
"S_STARPOST_STARTSPIN",
"S_STARPOST_SPIN", "S_STARPOST_SPIN",
"S_STARPOST_ENDSPIN",
// Big floating mine // Big floating mine
"S_BIGMINE1", "S_BIGMINE1",
@ -5156,21 +5160,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DEMONFIRE6", "S_DEMONFIRE6",
"S_GFZFLOWERA", "S_GFZFLOWERA",
"S_GFZFLOWERA2", "S_GFZFLOWERB",
"S_GFZFLOWERC",
"S_GFZFLOWERB1",
"S_GFZFLOWERB2",
"S_GFZFLOWERC1",
"S_BERRYBUSH", "S_BERRYBUSH",
"S_BUSH", "S_BUSH",
// THZ Plant // THZ Plant
"S_THZPLANT1", "S_THZFLOWERA",
"S_THZPLANT2", "S_THZFLOWERB",
"S_THZPLANT3",
"S_THZPLANT4",
// THZ Alarm // THZ Alarm
"S_ALARM1", "S_ALARM1",
@ -5215,6 +5213,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FLAME2", "S_FLAME2",
"S_FLAME3", "S_FLAME3",
"S_FLAME4", "S_FLAME4",
"S_FLAME5",
"S_FLAME6",
"S_FLAMEPARTICLE",
"S_FLAMEREST",
// Eggman Statue // Eggman Statue
"S_EGGSTATUE1", "S_EGGSTATUE1",
@ -5276,36 +5279,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Spinning flame jets // Spinning flame jets
"S_FJSPINAXISA1", // Counter-clockwise "S_FJSPINAXISA1", // Counter-clockwise
"S_FJSPINAXISA2", "S_FJSPINAXISA2",
"S_FJSPINAXISA3",
"S_FJSPINAXISA4",
"S_FJSPINAXISA5",
"S_FJSPINAXISA6",
"S_FJSPINAXISA7",
"S_FJSPINAXISA8",
"S_FJSPINAXISA9",
"S_FJSPINHELPERA1",
"S_FJSPINHELPERA2",
"S_FJSPINHELPERA3",
"S_FJSPINAXISB1", // Clockwise "S_FJSPINAXISB1", // Clockwise
"S_FJSPINAXISB2", "S_FJSPINAXISB2",
"S_FJSPINAXISB3",
"S_FJSPINAXISB4",
"S_FJSPINAXISB5",
"S_FJSPINAXISB6",
"S_FJSPINAXISB7",
"S_FJSPINAXISB8",
"S_FJSPINAXISB9",
"S_FJSPINHELPERB1",
"S_FJSPINHELPERB2",
"S_FJSPINHELPERB3",
// Blade's flame // Blade's flame
"S_FLAMEJETFLAMEB1", "S_FLAMEJETFLAMEB1",
"S_FLAMEJETFLAMEB2", "S_FLAMEJETFLAMEB2",
"S_FLAMEJETFLAMEB3", "S_FLAMEJETFLAMEB3",
"S_FLAMEJETFLAMEB4",
"S_FLAMEJETFLAMEB5",
"S_FLAMEJETFLAMEB6",
// Trapgoyles // Trapgoyles
"S_TRAPGOYLE", "S_TRAPGOYLE",
@ -5400,8 +5380,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_BSZVINE_ORANGE", "S_BSZVINE_ORANGE",
"S_BSZSHRUB", "S_BSZSHRUB",
"S_BSZCLOVER", "S_BSZCLOVER",
"S_BSZFISH", "S_BIG_PALMTREE_TRUNK",
"S_BSZSUNFLOWER", "S_BIG_PALMTREE_TOP",
"S_PALMTREE_TRUNK",
"S_PALMTREE_TOP",
"S_DBALL1", "S_DBALL1",
"S_DBALL2", "S_DBALL2",
@ -6120,20 +6102,19 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FIREBALLEXP2", "S_FIREBALLEXP2",
"S_FIREBALLEXP3", "S_FIREBALLEXP3",
"S_SHELL", "S_SHELL",
"S_SHELL1", "S_PUMA_START1",
"S_SHELL2", "S_PUMA_START2",
"S_SHELL3", "S_PUMA_UP1",
"S_SHELL4", "S_PUMA_UP2",
"S_PUMA1", "S_PUMA_UP3",
"S_PUMA2", "S_PUMA_DOWN1",
"S_PUMA3", "S_PUMA_DOWN2",
"S_PUMA4", "S_PUMA_DOWN3",
"S_PUMA5", "S_PUMATRAIL1",
"S_PUMA6", "S_PUMATRAIL2",
"S_HAMMER1", "S_PUMATRAIL3",
"S_HAMMER2", "S_PUMATRAIL4",
"S_HAMMER3", "S_HAMMER",
"S_HAMMER4",
"S_KOOPA1", "S_KOOPA1",
"S_KOOPA2", "S_KOOPA2",
"S_KOOPAFLAME1", "S_KOOPAFLAME1",
@ -6386,6 +6367,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BOSSTANK2", "MT_BOSSTANK2",
"MT_BOSSSPIGOT", "MT_BOSSSPIGOT",
"MT_GOOP", "MT_GOOP",
"MT_GOOPTRAIL",
// Boss 3 // Boss 3
"MT_EGGMOBILE3", "MT_EGGMOBILE3",
@ -6555,7 +6537,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BUSH", "MT_BUSH",
// Techno Hill Scenery // Techno Hill Scenery
"MT_THZPLANT", // THZ Plant "MT_THZFLOWER1",
"MT_THZFLOWER2",
"MT_ALARM", "MT_ALARM",
// Deep Sea Scenery // Deep Sea Scenery
@ -6571,6 +6554,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Castle Eggman Scenery // Castle Eggman Scenery
"MT_CHAIN", // CEZ Chain "MT_CHAIN", // CEZ Chain
"MT_FLAME", // Flame (has corona) "MT_FLAME", // Flame (has corona)
"MT_FLAMEPARTICLE",
"MT_EGGSTATUE", // Eggman Statue "MT_EGGSTATUE", // Eggman Statue
"MT_MACEPOINT", // Mace rotation point "MT_MACEPOINT", // Mace rotation point
"MT_SWINGMACEPOINT", // Mace swinging point "MT_SWINGMACEPOINT", // Mace swinging point
@ -6597,9 +6581,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_FLAMEJETFLAME", "MT_FLAMEJETFLAME",
"MT_FJSPINAXISA", // Counter-clockwise "MT_FJSPINAXISA", // Counter-clockwise
"MT_FJSPINHELPERA",
"MT_FJSPINAXISB", // Clockwise "MT_FJSPINAXISB", // Clockwise
"MT_FJSPINHELPERB",
"MT_FLAMEJETFLAMEB", // Blade's flame "MT_FLAMEJETFLAMEB", // Blade's flame
@ -6676,8 +6658,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BSZVINE_ORANGE", "MT_BSZVINE_ORANGE",
"MT_BSZSHRUB", "MT_BSZSHRUB",
"MT_BSZCLOVER", "MT_BSZCLOVER",
"MT_BSZFISH", "MT_BIG_PALMTREE_TRUNK",
"MT_BSZSUNFLOWER", "MT_BIG_PALMTREE_TOP",
"MT_PALMTREE_TRUNK",
"MT_PALMTREE_TOP",
// Misc scenery // Misc scenery
"MT_DBALL", "MT_DBALL",
@ -6783,6 +6767,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_FIREBALL", "MT_FIREBALL",
"MT_SHELL", "MT_SHELL",
"MT_PUMA", "MT_PUMA",
"MT_PUMATRAIL",
"MT_HAMMER", "MT_HAMMER",
"MT_KOOPA", "MT_KOOPA",
"MT_KOOPAFLAME", "MT_KOOPAFLAME",

View file

@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 21 #define MODVERSION 22
// ========================================================================= // =========================================================================

View file

@ -974,7 +974,7 @@ static const char *credits[] = {
"Scott \"Graue\" Feeney", "Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux", "Nathan \"Jazz\" Giroux",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"John \"JTE\" Muniz", "John \"JTE\" Muniz",
"Ehab \"Wolfy\" Saeed", "Ehab \"Wolfy\" Saeed",
@ -986,6 +986,7 @@ static const char *credits[] = {
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom) "\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
"Andrew \"orospakr\" Clunis", "Andrew \"orospakr\" Clunis",
"Gregor \"Oogaland\" Dick", "Gregor \"Oogaland\" Dick",
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
"Vivian \"toaster\" Grannell", "Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
@ -1021,7 +1022,7 @@ static const char *credits[] = {
"Paul \"Boinciel\" Clempson", "Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe", "Cyan Helkaraxe",
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Jarel \"Arrow\" Jones", "Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia", "Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton", "Shane Mychal Sexton",

View file

@ -296,6 +296,7 @@ light_t *t_lspr[NUMSPRITES] =
// Techno Hill Scenery // Techno Hill Scenery
&lspr[NOLIGHT], // SPR_THZP &lspr[NOLIGHT], // SPR_THZP
&lspr[NOLIGHT], // SPR_FWR5
&lspr[REDBALL_L], // SPR_ALRM &lspr[REDBALL_L], // SPR_ALRM
// Deep Sea Scenery // Deep Sea Scenery

View file

@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
boolean action = false; boolean action = false;
char *ptr; char *ptr;
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]); CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
target = READSINT8(*p); target = READSINT8(*p);
flags = READUINT8(*p); flags = READUINT8(*p);
@ -1102,7 +1102,19 @@ void HU_Drawer(void)
// draw desynch text // draw desynch text
if (hu_resynching) if (hu_resynching)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching..."); {
static UINT32 resynch_ticker = 0;
char resynch_text[14];
UINT32 i;
// Animate the dots
resynch_ticker++;
strcpy(resynch_text, "Resynching");
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
strcat(resynch_text, ".");
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
}
} }
//====================================================================== //======================================================================

View file

@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
/** \brief return packet in doomcom struct /** \brief return packet in doomcom struct
*/ */
extern void (*I_NetGet)(void); extern boolean (*I_NetGet)(void);
/** \brief ask to driver if there is data waiting /** \brief ask to driver if there is data waiting
*/ */

View file

@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
#include "i_system.h" #include "i_system.h"
#include "i_net.h" #include "i_net.h"
#include "d_net.h" #include "d_net.h"
#include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "m_argv.h"
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
return false; return false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
return -1;
}
// This is a hack. For some reason, nodes aren't being freed properly. // This is a hack. For some reason, nodes aren't being freed properly.
// This goes through and cleans up what nodes were supposed to be freed. // This goes through and cleans up what nodes were supposed to be freed.
/** \warning This function causes the file downloading to stop if someone joins.
* How? Because it removes nodes that are connected but not in game,
* which is exactly what clients downloading a file are.
*/
static void cleanupnodes(void) static void cleanupnodes(void)
{ {
SINT8 j; SINT8 j;
@ -506,13 +498,81 @@ static void cleanupnodes(void)
// Why can't I start at zero? // Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++) for (j = 1; j < MAXNETNODES; j++)
//if (!(nodeingame[j] || SV_SendingFile(j)))
if (!nodeingame[j]) if (!nodeingame[j])
nodeconnected[j] = false; nodeconnected[j] = false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
cleanupnodes();
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
/** \warning No free node? Just in case a node might not have been freed properly,
* look if there are connected nodes that aren't in game, and forget them.
* It's dirty, and might result in a poor guy having to restart
* downloading a needed wad, but it's better than not letting anyone join...
*/
/*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j])
return j;*/
return -1;
}
#ifdef _DEBUG
void Command_Numnodes(void)
{
INT32 connected = 0;
INT32 ingame = 0;
INT32 i;
for (i = 1; i < MAXNETNODES; i++)
{
if (!(nodeconnected[i] || nodeingame[i]))
continue;
if (nodeconnected[i])
connected++;
if (nodeingame[i])
ingame++;
CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1)
CONS_Printf("player %.2d", nodetoplayer[i]);
else
CONS_Printf(" ");
if (nodeconnected[i])
CONS_Printf(" - connected");
else
CONS_Printf(" - ");
if (nodeingame[i])
CONS_Printf(" - ingame");
else
CONS_Printf(" - ");
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
}
CONS_Printf("\n"
"Connected: %d\n"
"Ingame: %d\n",
connected, ingame);
}
#endif
#endif #endif
#ifndef NONET #ifndef NONET
static void SOCK_Get(void) // Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{ {
size_t i, n; size_t i, n;
int j; int j;
@ -535,13 +595,12 @@ static void SOCK_Get(void)
doomcom->remotenode = (INT16)j; // good packet from a game player doomcom->remotenode = (INT16)j; // good packet from a game player
doomcom->datalength = (INT16)c; doomcom->datalength = (INT16)c;
nodesocket[j] = mysockets[n]; nodesocket[j] = mysockets[n];
return; return false;
} }
} }
// not found // not found
// find a free slot // find a free slot
cleanupnodes();
j = getfreenode(); j = getfreenode();
if (j > 0) if (j > 0)
{ {
@ -564,14 +623,15 @@ static void SOCK_Get(void)
} }
if (i == numbans) if (i == numbans)
SOCK_bannednode[j] = false; SOCK_bannednode[j] = false;
return; return true;
} }
else else
DEBFILE("New node detected: No more free slots\n"); DEBFILE("New node detected: No more free slots\n");
} }
} }
doomcom->remotenode = -1; // no packet doomcom->remotenode = -1; // no packet
return false;
} }
#endif #endif
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
gaie = I_getaddrinfo(address, port, &hints, &ai); gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
cleanupnodes();
newnode = getfreenode(); newnode = getfreenode();
} }
if (newnode == -1) if (newnode == -1)

View file

@ -184,6 +184,7 @@ char sprnames[NUMSPRITES + 1][5] =
// Techno Hill Scenery // Techno Hill Scenery
"THZP", // Techno Hill Zone Plant "THZP", // Techno Hill Zone Plant
"FWR5", // Another one
"ALRM", // THZ2 Alarm "ALRM", // THZ2 Alarm
// Deep Sea Scenery // Deep Sea Scenery
@ -990,9 +991,10 @@ state_t states[NUMSTATES] =
{SPR_SPNK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT {SPR_SPNK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT
// Boss 2 Goop // Boss 2 Goop
{SPR_GOOP, 0, 2, {NULL}, 0, 0, S_GOOP2}, // S_GOOP1 {SPR_GOOP, 0, 2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2}, // S_GOOP1
{SPR_GOOP, 1, 2, {NULL}, 0, 0, S_GOOP1}, // S_GOOP2 {SPR_GOOP, 1, 2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP1}, // S_GOOP2
{SPR_GOOP, 2,-1, {NULL}, 0, 0, S_NULL}, // S_GOOP3 {SPR_GOOP, 2, -1, {NULL}, 0, 0, S_NULL}, // S_GOOP3
{SPR_GOOP, FF_ANIMATE|3, 11, {NULL}, 2, 6, S_NULL}, // S_GOOPTRAIL
// Boss 3 // Boss 3
{SPR_EGGO, 0, 1, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_STND {SPR_EGGO, 0, 1, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_STND
@ -1244,12 +1246,12 @@ state_t states[NUMSTATES] =
{SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3}, // S_CYBRAKDEMONMISSILE_EXPLODE2 {SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3}, // S_CYBRAKDEMONMISSILE_EXPLODE2
{SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONMISSILE_EXPLODE3 {SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONMISSILE_EXPLODE3
{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1 {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1
{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2 {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2
{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3 {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3
{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE
{SPR_FLAM, FF_TRANS50|FF_FULLBRIGHT|3, 3, {A_SetFuse}, 10*TICRATE, 0, S_FLAME1}, // S_CYBRAKDEMONFLAMEREST {SPR_FLAM, FF_TRANS20|FF_FULLBRIGHT|5, 3, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST
{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 {SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2 {SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2
@ -1570,9 +1572,11 @@ state_t states[NUMSTATES] =
{SPR_USPK, 2,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2 {SPR_USPK, 2,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
// Starpost // Starpost
{SPR_STPT, 0 , -1, {NULL}, 0, 0, S_NULL}, // S_STARPOST_IDLE {SPR_STPT, 0 , -1, {NULL}, 0, 0, S_NULL}, // S_STARPOST_IDLE
{SPR_STPT, FF_ANIMATE , -1, {NULL}, 1, 2, S_NULL}, // S_STARPOST_FLASH {SPR_STPT, FF_ANIMATE|17, -1, {NULL}, 5, 1, S_NULL}, // S_STARPOST_FLASH
{SPR_STPT, FF_ANIMATE|2, 31, {NULL}, 15, 1, S_STARPOST_FLASH}, // S_STARPOST_SPIN {SPR_STPT, FF_ANIMATE|13, 2, {NULL}, 1, 1, S_STARPOST_SPIN}, // S_STARPOST_STARTSPIN
{SPR_STPT, FF_ANIMATE|1 , 23, {NULL}, 11, 1, S_STARPOST_ENDSPIN}, // S_STARPOST_SPIN
{SPR_STPT, FF_ANIMATE|15, 2, {NULL}, 1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN
// Big floating mine // Big floating mine
{SPR_BMNE, 0, 5, {NULL}, 0, 0, S_BIGMINE2}, // S_BIGMINE1 {SPR_BMNE, 0, 5, {NULL}, 0, 0, S_BIGMINE2}, // S_BIGMINE1
@ -1753,21 +1757,15 @@ state_t states[NUMSTATES] =
{SPR_CFIR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_DEMONFIRE1}, // S_DEMONFIRE6 {SPR_CFIR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_DEMONFIRE1}, // S_DEMONFIRE6
// GFZ Flower // GFZ Flower
{SPR_FWR1, 0, 14, {NULL}, 0, 0, S_GFZFLOWERA2}, // S_GFZFLOWERA {SPR_FWR1, FF_ANIMATE, -1, {NULL}, 7, 3, S_NULL}, // S_GFZFLOWERA
{SPR_FWR1, 1, 14, {NULL}, 0, 0, S_GFZFLOWERA}, // S_GFZFLOWERA2 {SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB
{SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_GFZFLOWERC
{SPR_FWR2, 0, 7, {NULL}, 0, 0, S_GFZFLOWERB2}, // S_GFZFLOWERB1
{SPR_FWR2, 1, 7, {NULL}, 0, 0, S_GFZFLOWERB1}, // S_GFZFLOWERB1
{SPR_FWR3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GFZFLOWERC1
{SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH {SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH
{SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH {SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH
{SPR_THZP, 0, 4, {NULL}, 0, 0, S_THZPLANT2}, // S_THZPLANT1 {SPR_THZP, FF_ANIMATE, -1, {NULL}, 7, 4, S_NULL}, // S_THZFLOWERA
{SPR_THZP, 1, 4, {NULL}, 0, 0, S_THZPLANT3}, // S_THZPLANT1 {SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB
{SPR_THZP, 2, 4, {NULL}, 0, 0, S_THZPLANT4}, // S_THZPLANT1
{SPR_THZP, 3, 4, {NULL}, 0, 0, S_THZPLANT1}, // S_THZPLANT1
// THZ Alarm // THZ Alarm
{SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1 {SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1
@ -1808,10 +1806,15 @@ state_t states[NUMSTATES] =
{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN {SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
// Flame // Flame
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_FLAME2}, // S_FLAME1 {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20, 3, {A_FlameParticle}, 3, 0, S_FLAME2}, // S_FLAME1
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|1, 3, {NULL}, 0, 0, S_FLAME3}, // S_FLAME2 {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|1, 3, {NULL}, 0, 0, S_FLAME3}, // S_FLAME2
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|2, 3, {NULL}, 0, 0, S_FLAME4}, // S_FLAME3 {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|2, 3, {A_FlameParticle}, 3, 0, S_FLAME4}, // S_FLAME3
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|3, 3, {NULL}, 0, 0, S_FLAME1}, // S_FLAME4 {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|3, 3, {NULL}, 0, 0, S_FLAME5}, // S_FLAME4
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|4, 3, {A_FlameParticle}, 3, 0, S_FLAME6}, // S_FLAME5
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|5, 3, {NULL}, 0, 0, S_FLAME1}, // S_FLAME6
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS10|6, 24, {NULL}, 0, 0, S_NULL}, // S_FLAMEPARTICLE
{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|FF_ANIMATE, -1, {NULL}, 5, 3, S_FLAME2}, // S_FLAMEREST
// Eggman statue // Eggman statue
{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1 {SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1
@ -1867,48 +1870,23 @@ state_t states[NUMSTATES] =
{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND {SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND
{SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTOP}, // S_FLAMEJETSTART {SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTOP}, // S_FLAMEJETSTART
{SPR_NULL, 0, 1, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTND}, // S_FLAMEJETSTOP {SPR_NULL, 0, 1, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTND}, // S_FLAMEJETSTOP
{SPR_FLME, FF_TRANS50 , 4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1 {SPR_FLME, FF_FULLBRIGHT|FF_TRANS50 , 4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1
{SPR_FLME, FF_TRANS60|1, 5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2 {SPR_FLME, FF_FULLBRIGHT|FF_TRANS60|1, 5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2
{SPR_FLME, FF_TRANS70|2, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME3 {SPR_FLME, FF_FULLBRIGHT|FF_TRANS70|2, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME3
// Spinning flame jets // Spinning flame jets
// A: Counter-clockwise // A: Counter-clockwise
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FJSPINAXISA2}, // S_FJSPINAXISA1 {SPR_NULL, 0, 1, {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISA2}, // S_FJSPINAXISA1
{SPR_NULL, 0, 1, {A_Thrust}, 10, 1, S_FJSPINAXISA3}, // S_FJSPINAXISA2 {SPR_NULL, 0, 2, {A_ChangeAngleRelative}, 6, 6, S_FJSPINAXISA1}, // S_FJSPINAXISA2
{SPR_NULL, 0, 0, {A_Thrust}, 0, 1, S_FJSPINAXISA4}, // S_FJSPINAXISA3
{SPR_NULL, 0, 0, {A_SpawnObjectRelative}, 0, MT_FJSPINHELPERA, S_FJSPINAXISA5}, // S_FJSPINAXISA4
{SPR_NULL, 0, 2, {A_FindTarget}, MT_FJSPINHELPERA, 0, S_FJSPINAXISA6}, // S_FJSPINAXISA5
{SPR_NULL, 0, 1, {A_Thrust}, -10, 1, S_FJSPINAXISA7}, // S_FJSPINAXISA6
{SPR_NULL, 0, 1, {A_Thrust}, 0, 1, S_FJSPINAXISA8}, // S_FJSPINAXISA7
{SPR_NULL, 0, 0, {A_FireShot}, MT_FLAMEJETFLAMEB, -64, S_FJSPINAXISA9}, // S_FJSPINAXISA8
{SPR_NULL, 0, 3, {A_ChangeAngleRelative}, 6, 6, S_FJSPINAXISA8}, // S_FJSPINAXISA9
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FJSPINHELPERA2}, // S_FJSPINHELPERA1
{SPR_NULL, 0, 0, {A_FindTarget}, MT_FJSPINAXISA, 0, S_FJSPINHELPERA3}, // S_FJSPINHELPERA2
{SPR_NULL, 0, 1, {A_CapeChase}, 0, (64<<16), S_FJSPINHELPERA3}, // S_FJSPINHELPERA3
// B: Clockwise // B: Clockwise
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FJSPINAXISB2}, // S_FJSPINAXISB1 {SPR_NULL, 0, 1, {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISB2}, // S_FJSPINAXISB1
{SPR_NULL, 0, 1, {A_Thrust}, 10, 1, S_FJSPINAXISB3}, // S_FJSPINAXISB2 {SPR_NULL, 0, 2, {A_ChangeAngleRelative}, -6, -6, S_FJSPINAXISB1}, // S_FJSPINAXISB2
{SPR_NULL, 0, 0, {A_Thrust}, 0, 1, S_FJSPINAXISB4}, // S_FJSPINAXISB3
{SPR_NULL, 0, 0, {A_SpawnObjectRelative}, 0, MT_FJSPINHELPERB, S_FJSPINAXISB5}, // S_FJSPINAXISB4
{SPR_NULL, 0, 2, {A_FindTarget}, MT_FJSPINHELPERB, 0, S_FJSPINAXISB6}, // S_FJSPINAXISB5
{SPR_NULL, 0, 1, {A_Thrust}, -10, 1, S_FJSPINAXISB7}, // S_FJSPINAXISB6
{SPR_NULL, 0, 1, {A_Thrust}, 0, 1, S_FJSPINAXISB8}, // S_FJSPINAXISB7
{SPR_NULL, 0, 0, {A_FireShot}, MT_FLAMEJETFLAMEB, -64, S_FJSPINAXISB9}, // S_FJSPINAXISB8
{SPR_NULL, 0, 3, {A_ChangeAngleRelative}, -6, -6, S_FJSPINAXISB8}, // S_FJSPINAXISB9
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FJSPINHELPERB2}, // S_FJSPINHELPERB1
{SPR_NULL, 0, 0, {A_FindTarget}, MT_FJSPINAXISB, 0, S_FJSPINHELPERB3}, // S_FJSPINHELPERB2
{SPR_NULL, 0, 1, {A_CapeChase}, 0, (64<<16), S_FJSPINHELPERB3}, // S_FJSPINHELPERB3
// Blade's flame // Blade's flame
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|1, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1 {SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|2, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2 {SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|3,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB4}, // S_FLAMEJETFLAMEB3 {SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL}, // S_FLAMEJETFLAMEB3
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|4,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB5}, // S_FLAMEJETFLAMEB4
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|5,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB6}, // S_FLAMEJETFLAMEB5
{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|6,12, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAMEB6
// Trapgoyles // Trapgoyles
{SPR_GARG, 0, 67, {NULL}, 0, 0, S_TRAPGOYLE_CHECK}, // S_TRAPGOYLE {SPR_GARG, 0, 67, {NULL}, 0, 0, S_TRAPGOYLE_CHECK}, // S_TRAPGOYLE
@ -2006,8 +1984,10 @@ state_t states[NUMSTATES] =
{SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_ORANGE {SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_ORANGE
{SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHRUB {SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHRUB
{SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLOVER {SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLOVER
{SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFISH {SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TRUNK
{SPR_BSZ8, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSUNFLOWER {SPR_BSZ8, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TOP
{SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TRUNK
{SPR_BSZ8, 5, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TOP
// Disco ball // Disco ball
{SPR_DBAL, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_DBALL2}, // S_DBALL1 {SPR_DBAL, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_DBALL2}, // S_DBALL1
@ -2762,25 +2742,25 @@ state_t states[NUMSTATES] =
{SPR_FBLL, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_FIREBALLEXP3 {SPR_FBLL, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_FIREBALLEXP3
// Turtle Shell // Turtle Shell
{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHELL {SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHELL
{SPR_SHLL, 0, 2, {NULL}, 0, 0, S_SHELL2}, // S_SHELL1
{SPR_SHLL, 1, 2, {NULL}, 0, 0, S_SHELL3}, // S_SHELL2
{SPR_SHLL, 2, 2, {NULL}, 0, 0, S_SHELL4}, // S_SHELL3
{SPR_SHLL, 3, 2, {NULL}, 0, 0, S_SHELL1}, // S_SHELL4
// Puma (Mario fireball) // Puma (Mario fireball)
{SPR_PUMA, FF_FULLBRIGHT, 3, {A_FishJump}, 0, 0, S_PUMA2}, // S_PUMA1 {SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2}, // S_PUMA_START1
{SPR_PUMA, FF_FULLBRIGHT|1, 3, {A_FishJump}, 0, 0, S_PUMA3}, // S_PUMA2 {SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1, S_PUMA_UP1}, // S_PUMA_START2
{SPR_PUMA, FF_FULLBRIGHT|2, 3, {A_FishJump}, 0, 0, S_PUMA1}, // S_PUMA3 {SPR_PUMA, FF_FULLBRIGHT , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2}, // S_PUMA_UP1
{SPR_PUMA, FF_FULLBRIGHT|3, 3, {A_FishJump}, 0, 0, S_PUMA5}, // S_PUMA4 {SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3}, // S_PUMA_UP2
{SPR_PUMA, FF_FULLBRIGHT|4, 3, {A_FishJump}, 0, 0, S_PUMA6}, // S_PUMA5 {SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1}, // S_PUMA_UP3
{SPR_PUMA, FF_FULLBRIGHT|5, 3, {A_FishJump}, 0, 0, S_PUMA4}, // S_PUMA6 {SPR_PUMA, FF_FULLBRIGHT|3, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN2}, // S_PUMA_DOWN1
{SPR_PUMA, FF_FULLBRIGHT|4, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN3}, // S_PUMA_DOWN2
{SPR_PUMA, FF_FULLBRIGHT|5, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN1}, // S_PUMA_DOWN3
{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS20|6, 4, {NULL}, 0, 0, S_PUMATRAIL2}, // S_PUMATRAIL1
{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS40|6, 5, {A_SetScale}, FRACUNIT, 1, S_PUMATRAIL3}, // S_PUMATRAIL2
{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS50|7, 4, {NULL}, 0, 0, S_PUMATRAIL4}, // S_PUMATRAIL3
{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3, {NULL}, 0, 0, S_NULL}, // S_PUMATRAIL4
// Hammer // Hammer
{SPR_HAMM, 0, 3, {NULL}, 0, 0, S_HAMMER2}, // S_HAMMER1 {SPR_HAMM, FF_ANIMATE, -1, {NULL}, 4, 3, S_NULL}, // S_HAMMER
{SPR_HAMM, 1, 3, {NULL}, 0, 0, S_HAMMER3}, // S_HAMMER2
{SPR_HAMM, 2, 3, {NULL}, 0, 0, S_HAMMER4}, // S_HAMMER3
{SPR_HAMM, 3, 3, {NULL}, 0, 0, S_HAMMER1}, // S_HAMMER4
// Koopa // Koopa
{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KOOPA1 {SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KOOPA1
@ -3195,8 +3175,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_pop, // deathsound sfx_pop, // deathsound
4*FRACUNIT, // speed 4*FRACUNIT, // speed
20*FRACUNIT, // radius 28*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
100, // mass 100, // mass
0, // damage 0, // damage
@ -3222,8 +3202,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_pop, // deathsound sfx_pop, // deathsound
8*FRACUNIT, // speed 8*FRACUNIT, // speed
20*FRACUNIT, // radius 28*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
100, // mass 100, // mass
0, // damage 0, // damage
@ -4339,6 +4319,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_GOOPTRAIL
-1, // doomednum
S_GOOPTRAIL, // 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
3, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_EGGMOBILE3 { // MT_EGGMOBILE3
202, // doomednum 202, // doomednum
S_EGGMOBILE3_STND, // spawnstate S_EGGMOBILE3_STND, // spawnstate
@ -4726,7 +4733,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // reactiontime 8, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
0, // painchance MT_NULL, // painchance
sfx_None, // painsound sfx_None, // painsound
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
@ -5989,7 +5996,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // seesound sfx_None, // seesound
8, // reactiontime 8, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_STARPOST_SPIN, // painstate S_STARPOST_STARTSPIN, // painstate
0, // painchance 0, // painchance
sfx_strpst, // painsound sfx_strpst, // painsound
S_NULL, // meleestate S_NULL, // meleestate
@ -5999,7 +6006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound sfx_None, // deathsound
8, // speed 8, // speed
64*FRACUNIT, // radius 64*FRACUNIT, // radius
80*FRACUNIT, // height 128*FRACUNIT, // height
0, // display offset 0, // display offset
4, // mass 4, // mass
0, // damage 0, // damage
@ -7927,7 +7934,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_GFZFLOWER2 { // MT_GFZFLOWER2
801, // doomednum 801, // doomednum
S_GFZFLOWERB1, // spawnstate S_GFZFLOWERB, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -7954,7 +7961,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_GFZFLOWER3 { // MT_GFZFLOWER3
802, // doomednum 802, // doomednum
S_GFZFLOWERC1, // spawnstate S_GFZFLOWERC, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -7975,7 +7982,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -8033,9 +8040,36 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_THZPLANT { // MT_THZFLOWER1
900, // doomednum 900, // doomednum
S_THZPLANT1, // spawnstate S_THZFLOWERA, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
8, // speed
8*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_THZFLOWER2
902, // doomednum
S_THZFLOWERB, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -8339,7 +8373,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // reactiontime 8, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
0, // painchance MT_FLAMEPARTICLE, // painchance
sfx_None, // painsound sfx_None, // painsound
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
@ -8357,6 +8391,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_FLAMEPARTICLE
-1, // doomednum
S_FLAMEPARTICLE, // 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
0, // speed
FRACUNIT, // radius
FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_EGGSTATUE { // MT_EGGSTATUE
1102, // doomednum 1102, // doomednum
S_EGGSTATUE1, // spawnstate S_EGGSTATUE1, // spawnstate
@ -8924,33 +8985,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_FJSPINHELPERA
-1, // doomednum
S_FJSPINHELPERA1,// 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
10*FRACUNIT, // speed
16*FRACUNIT, // radius
1*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOCLIP|MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOSECTOR, // flags
S_NULL // raisestate
},
{ // MT_FJSPINAXISB { // MT_FJSPINAXISB
3576, // doomednum 3576, // doomednum
S_FJSPINAXISB1, // spawnstate S_FJSPINAXISB1, // spawnstate
@ -8978,33 +9012,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_FJSPINHELPERB
-1, // doomednum
S_FJSPINHELPERB1,// 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
10*FRACUNIT, // speed
16*FRACUNIT, // radius
1*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOCLIP|MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOSECTOR, // flags
S_NULL // raisestate
},
{ // MT_FLAMEJETFLAMEB { // MT_FLAMEJETFLAMEB
-1, // doomednum -1, // doomednum
S_FLAMEJETFLAMEB1, // spawnstate S_FLAMEJETFLAMEB1, // spawnstate
@ -10709,9 +10716,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_BSZFISH { // MT_BIG_PALMTREE_TRUNK
1472, // doomednum 1472, // doomednum
S_BSZFISH, // spawnstate S_BIG_PALMTREE_TRUNK, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -10736,9 +10743,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_BSZSUNFLOWER { // MT_BIG_PALMTREE_TOP
1473, // doomednum 1473, // doomednum
S_BSZSUNFLOWER, // spawnstate S_BIG_PALMTREE_TOP, // 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
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_PALMTREE_TRUNK
1474, // doomednum
S_PALMTREE_TRUNK, // 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
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_PALMTREE_TOP
1475, // doomednum
S_PALMTREE_TOP, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -13085,9 +13146,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate S_NULL, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
20*FRACUNIT, // speed 16, // speed
8*FRACUNIT, // radius 16*FRACUNIT, // radius
16*FRACUNIT, // height 20*FRACUNIT, // height
0, // display offset 0, // display offset
100, // mass 100, // mass
1, // damage 1, // damage
@ -13098,19 +13159,19 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_PUMA { // MT_PUMA
1805, // doomednum 1805, // doomednum
S_PUMA1, // spawnstate S_PUMA_START1, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_PUMA1, // seestate S_PUMA_START1, // seestate
sfx_None, // seesound sfx_None, // seesound
8, // reactiontime 8, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
0, // painchance 0, // painchance
sfx_None, // painsound sfx_None, // painsound
S_PUMA4, // meleestate S_PUMA_DOWN1, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
S_NULL, // deathstate S_NULL, // deathstate
S_PUMA6, // xdeathstate S_PUMA_DOWN3, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
0, // speed 0, // speed
8*FRACUNIT, // radius 8*FRACUNIT, // radius
@ -13119,12 +13180,40 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_PAIN|MF_FIRE, // flags MF_PAIN|MF_FIRE, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_PUMATRAIL
-1, // doomednum
S_PUMATRAIL1, // 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
0, // speed
2*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_HAMMER { // MT_HAMMER
-1, // doomednum -1, // doomednum
S_HAMMER1, // spawnstate S_HAMMER, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -14335,7 +14424,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14362,7 +14451,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14389,7 +14478,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14416,7 +14505,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14443,7 +14532,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14470,7 +14559,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14497,7 +14586,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14524,7 +14613,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14551,7 +14640,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14578,7 +14667,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14605,7 +14694,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14632,7 +14721,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14659,7 +14748,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14686,7 +14775,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14713,7 +14802,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -14740,7 +14829,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset 0, // display offset
1000, // mass 1000, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },

View file

@ -224,6 +224,7 @@ void A_FlickyFlounder();
void A_FlickyCheck(); void A_FlickyCheck();
void A_FlickyHeightCheck(); void A_FlickyHeightCheck();
void A_FlickyFlutter(); void A_FlickyFlutter();
void A_FlameParticle();
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 256 #define NUMMOBJFREESLOTS 256
@ -388,7 +389,8 @@ typedef enum sprite
SPR_BUS2, // GFZ Bush w/o berries SPR_BUS2, // GFZ Bush w/o berries
// Techno Hill Scenery // Techno Hill Scenery
SPR_THZP, // Techno Hill Zone Plant SPR_THZP, // THZ1 Flower
SPR_FWR5, // Another flower
SPR_ALRM, // THZ2 Alarm SPR_ALRM, // THZ2 Alarm
// Deep Sea Scenery // Deep Sea Scenery
@ -1200,6 +1202,7 @@ typedef enum state
S_GOOP1, S_GOOP1,
S_GOOP2, S_GOOP2,
S_GOOP3, S_GOOP3,
S_GOOPTRAIL,
// Boss 3 // Boss 3
S_EGGMOBILE3_STND, S_EGGMOBILE3_STND,
@ -1776,7 +1779,9 @@ typedef enum state
// Starpost // Starpost
S_STARPOST_IDLE, S_STARPOST_IDLE,
S_STARPOST_FLASH, S_STARPOST_FLASH,
S_STARPOST_STARTSPIN,
S_STARPOST_SPIN, S_STARPOST_SPIN,
S_STARPOST_ENDSPIN,
// Big floating mine // Big floating mine
S_BIGMINE1, S_BIGMINE1,
@ -1960,21 +1965,15 @@ typedef enum state
S_DEMONFIRE6, S_DEMONFIRE6,
S_GFZFLOWERA, S_GFZFLOWERA,
S_GFZFLOWERA2, S_GFZFLOWERB,
S_GFZFLOWERC,
S_GFZFLOWERB1,
S_GFZFLOWERB2,
S_GFZFLOWERC1,
S_BERRYBUSH, S_BERRYBUSH,
S_BUSH, S_BUSH,
// THZ Plant // THZ Plant
S_THZPLANT1, S_THZFLOWERA,
S_THZPLANT2, S_THZFLOWERB,
S_THZPLANT3,
S_THZPLANT4,
// THZ Alarm // THZ Alarm
S_ALARM1, S_ALARM1,
@ -2019,6 +2018,11 @@ typedef enum state
S_FLAME2, S_FLAME2,
S_FLAME3, S_FLAME3,
S_FLAME4, S_FLAME4,
S_FLAME5,
S_FLAME6,
S_FLAMEPARTICLE,
S_FLAMEREST,
// Eggman Statue // Eggman Statue
S_EGGSTATUE1, S_EGGSTATUE1,
@ -2080,36 +2084,13 @@ typedef enum state
// Spinning flame jets // Spinning flame jets
S_FJSPINAXISA1, // Counter-clockwise S_FJSPINAXISA1, // Counter-clockwise
S_FJSPINAXISA2, S_FJSPINAXISA2,
S_FJSPINAXISA3,
S_FJSPINAXISA4,
S_FJSPINAXISA5,
S_FJSPINAXISA6,
S_FJSPINAXISA7,
S_FJSPINAXISA8,
S_FJSPINAXISA9,
S_FJSPINHELPERA1,
S_FJSPINHELPERA2,
S_FJSPINHELPERA3,
S_FJSPINAXISB1, // Clockwise S_FJSPINAXISB1, // Clockwise
S_FJSPINAXISB2, S_FJSPINAXISB2,
S_FJSPINAXISB3,
S_FJSPINAXISB4,
S_FJSPINAXISB5,
S_FJSPINAXISB6,
S_FJSPINAXISB7,
S_FJSPINAXISB8,
S_FJSPINAXISB9,
S_FJSPINHELPERB1,
S_FJSPINHELPERB2,
S_FJSPINHELPERB3,
// Blade's flame // Blade's flame
S_FLAMEJETFLAMEB1, S_FLAMEJETFLAMEB1,
S_FLAMEJETFLAMEB2, S_FLAMEJETFLAMEB2,
S_FLAMEJETFLAMEB3, S_FLAMEJETFLAMEB3,
S_FLAMEJETFLAMEB4,
S_FLAMEJETFLAMEB5,
S_FLAMEJETFLAMEB6,
// Trapgoyles // Trapgoyles
S_TRAPGOYLE, S_TRAPGOYLE,
@ -2204,8 +2185,10 @@ typedef enum state
S_BSZVINE_ORANGE, S_BSZVINE_ORANGE,
S_BSZSHRUB, S_BSZSHRUB,
S_BSZCLOVER, S_BSZCLOVER,
S_BSZFISH, S_BIG_PALMTREE_TRUNK,
S_BSZSUNFLOWER, S_BIG_PALMTREE_TOP,
S_PALMTREE_TRUNK,
S_PALMTREE_TOP,
S_DBALL1, S_DBALL1,
S_DBALL2, S_DBALL2,
@ -2924,20 +2907,19 @@ typedef enum state
S_FIREBALLEXP2, S_FIREBALLEXP2,
S_FIREBALLEXP3, S_FIREBALLEXP3,
S_SHELL, S_SHELL,
S_SHELL1, S_PUMA_START1,
S_SHELL2, S_PUMA_START2,
S_SHELL3, S_PUMA_UP1,
S_SHELL4, S_PUMA_UP2,
S_PUMA1, S_PUMA_UP3,
S_PUMA2, S_PUMA_DOWN1,
S_PUMA3, S_PUMA_DOWN2,
S_PUMA4, S_PUMA_DOWN3,
S_PUMA5, S_PUMATRAIL1,
S_PUMA6, S_PUMATRAIL2,
S_HAMMER1, S_PUMATRAIL3,
S_HAMMER2, S_PUMATRAIL4,
S_HAMMER3, S_HAMMER,
S_HAMMER4,
S_KOOPA1, S_KOOPA1,
S_KOOPA2, S_KOOPA2,
S_KOOPAFLAME1, S_KOOPAFLAME1,
@ -3209,6 +3191,7 @@ typedef enum mobj_type
MT_BOSSTANK2, MT_BOSSTANK2,
MT_BOSSSPIGOT, MT_BOSSSPIGOT,
MT_GOOP, MT_GOOP,
MT_GOOPTRAIL,
// Boss 3 // Boss 3
MT_EGGMOBILE3, MT_EGGMOBILE3,
@ -3378,7 +3361,8 @@ typedef enum mobj_type
MT_BUSH, MT_BUSH,
// Techno Hill Scenery // Techno Hill Scenery
MT_THZPLANT, // THZ Plant MT_THZFLOWER1,
MT_THZFLOWER2,
MT_ALARM, MT_ALARM,
// Deep Sea Scenery // Deep Sea Scenery
@ -3394,6 +3378,7 @@ typedef enum mobj_type
// Castle Eggman Scenery // Castle Eggman Scenery
MT_CHAIN, // CEZ Chain MT_CHAIN, // CEZ Chain
MT_FLAME, // Flame (has corona) MT_FLAME, // Flame (has corona)
MT_FLAMEPARTICLE,
MT_EGGSTATUE, // Eggman Statue MT_EGGSTATUE, // Eggman Statue
MT_MACEPOINT, // Mace rotation point MT_MACEPOINT, // Mace rotation point
MT_SWINGMACEPOINT, // Mace swinging point MT_SWINGMACEPOINT, // Mace swinging point
@ -3420,9 +3405,7 @@ typedef enum mobj_type
MT_FLAMEJETFLAME, MT_FLAMEJETFLAME,
MT_FJSPINAXISA, // Counter-clockwise MT_FJSPINAXISA, // Counter-clockwise
MT_FJSPINHELPERA,
MT_FJSPINAXISB, // Clockwise MT_FJSPINAXISB, // Clockwise
MT_FJSPINHELPERB,
MT_FLAMEJETFLAMEB, // Blade's flame MT_FLAMEJETFLAMEB, // Blade's flame
@ -3499,8 +3482,10 @@ typedef enum mobj_type
MT_BSZVINE_ORANGE, MT_BSZVINE_ORANGE,
MT_BSZSHRUB, MT_BSZSHRUB,
MT_BSZCLOVER, MT_BSZCLOVER,
MT_BSZFISH, MT_BIG_PALMTREE_TRUNK,
MT_BSZSUNFLOWER, MT_BIG_PALMTREE_TOP,
MT_PALMTREE_TRUNK,
MT_PALMTREE_TOP,
// Misc scenery // Misc scenery
MT_DBALL, MT_DBALL,
@ -3606,6 +3591,7 @@ typedef enum mobj_type
MT_FIREBALL, MT_FIREBALL,
MT_SHELL, MT_SHELL,
MT_PUMA, MT_PUMA,
MT_PUMATRAIL,
MT_HAMMER, MT_HAMMER,
MT_KOOPA, MT_KOOPA,
MT_KOOPAFLAME, MT_KOOPAFLAME,

View file

@ -252,6 +252,7 @@ void A_FlickyFlounder(mobj_t *actor);
void A_FlickyCheck(mobj_t *actor); void A_FlickyCheck(mobj_t *actor);
void A_FlickyHeightCheck(mobj_t *actor); void A_FlickyHeightCheck(mobj_t *actor);
void A_FlickyFlutter(mobj_t *actor); void A_FlickyFlutter(mobj_t *actor);
void A_FlameParticle(mobj_t *actor);
// //
// ENEMY THINKING // ENEMY THINKING
@ -2134,13 +2135,15 @@ void A_Boss1Laser(mobj_t *actor)
if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
{ {
point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET);
point->angle = actor->angle;
point->fuse = actor->tics+1; point->fuse = actor->tics+1;
P_SetTarget(&point->target, actor->target); P_SetTarget(&point->target, actor->target);
P_SetTarget(&actor->target, point); P_SetTarget(&actor->target, point);
} }
} }
/* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path
else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/
if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)
angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT);
@ -2190,11 +2193,16 @@ void A_Boss1Laser(mobj_t *actor)
// var1: // var1:
// 0 - accelerative focus with friction // 0 - accelerative focus with friction
// 1 - steady focus with fixed movement speed // 1 - steady focus with fixed movement speed
// var2 = unused // anything else - don't move
// var2:
// 0 - don't trace target, just move forwards
// & 1 - change horizontal angle
// & 2 - change vertical angle
// //
void A_FocusTarget(mobj_t *actor) void A_FocusTarget(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_FocusTarget", actor)) if (LUA_CallAction("A_FocusTarget", actor))
return; return;
@ -2203,9 +2211,9 @@ void A_FocusTarget(mobj_t *actor)
if (actor->target) if (actor->target)
{ {
fixed_t speed = FixedMul(actor->info->speed, actor->scale); fixed_t speed = FixedMul(actor->info->speed, actor->scale);
fixed_t dist = R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y); fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1);
angle_t vangle = R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist); angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle);
angle_t hangle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90);
switch(locvar1) switch(locvar1)
{ {
case 0: case 0:
@ -3534,41 +3542,49 @@ void A_ScoreRise(mobj_t *actor)
// Function: A_ParticleSpawn // Function: A_ParticleSpawn
// //
// Description: Spawns a particle at a specified interval // Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN.
// //
// var1 = type (if 0, defaults to MT_PARTICLE) // var1 = unused
// var2 = unused // var2 = unused
// //
void A_ParticleSpawn(mobj_t *actor) void A_ParticleSpawn(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 i = 0;
fixed_t speed;
mobjtype_t type;
mobj_t *spawn; mobj_t *spawn;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_ParticleSpawn", actor)) if (LUA_CallAction("A_ParticleSpawn", actor))
return; return;
#endif #endif
if (!actor->spawnpoint) if (!actor->health)
{
P_RemoveMobj(actor);
return; return;
if (!actor->lastlook)
return;
if (!actor->threshold)
return;
for (i = 0; i < actor->lastlook; i++)
{
spawn = P_SpawnMobj(
actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)),
actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)),
actor->z,
(mobjtype_t)actor->threshold);
P_SetScale(spawn, actor->scale);
spawn->momz = FixedMul(actor->movefactor, spawn->scale);
spawn->destscale = spawn->scale/100;
spawn->scalespeed = spawn->scale/actor->health;
spawn->tics = (tic_t)actor->health;
spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP);
spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
if (spawn->frame & FF_ANIMATE)
spawn->frame += P_RandomKey(spawn->state->var1);
actor->angle += actor->movedir;
} }
actor->angle += (angle_t)actor->movecount;
if (locvar1)
type = (mobjtype_t)locvar1;
else
type = MT_PARTICLE;
speed = FixedMul((actor->spawnpoint->angle >> 12)<<FRACBITS, actor->scale);
spawn = P_SpawnMobj(actor->x, actor->y, actor->z, type);
P_SetScale(spawn, actor->scale);
spawn->momz = speed;
spawn->destscale = FixedDiv(spawn->scale<<FRACBITS, 100<<FRACBITS);
spawn->scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) << FRACBITS, 100<<FRACBITS);
actor->tics = actor->spawnpoint->extrainfo + 1;
} }
// Function: A_BunnyHop // Function: A_BunnyHop
@ -3882,11 +3898,18 @@ void A_DropMine(mobj_t *actor)
void A_FishJump(mobj_t *actor) void A_FishJump(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_FishJump", actor)) if (LUA_CallAction("A_FishJump", actor))
return; return;
#endif #endif
if (locvar2)
{
fixed_t rad = actor->radius>>FRACBITS;
P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
}
if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale))) if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale)))
{ {
fixed_t jumpval; fixed_t jumpval;
@ -9623,14 +9646,19 @@ void A_HomingChase(mobj_t *actor)
// lower 16 bits = object # to fire // lower 16 bits = object # to fire
// upper 16 bits = front offset // upper 16 bits = front offset
// var2: // var2:
// lower 16 bits = vertical angle // lower 15 bits = vertical angle variable
// 16th bit:
// - 0: use vertical angle variable as vertical angle in degrees
// - 1: mimic P_SpawnXYZMissile
// use z of actor minus z of missile as vertical distance to cover during momz calculation
// use vertical angle variable as horizontal distance to cover during momz calculation
// upper 16 bits = height offset // upper 16 bits = height offset
// //
void A_TrapShot(mobj_t *actor) void A_TrapShot(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 locvar1 = var1;
INT32 locvar2 = var2; INT32 locvar2 = var2;
angle_t vertang = FixedAngle(((INT16)(locvar2 & 65535))*FRACUNIT); boolean oldstyle = (locvar2 & 32768) ? true : false;
mobjtype_t type = (mobjtype_t)(locvar1 & 65535); mobjtype_t type = (mobjtype_t)(locvar1 & 65535);
mobj_t *missile; mobj_t *missile;
INT16 frontoff = (INT16)(locvar1 >> 16); INT16 frontoff = (INT16)(locvar1 >> 16);
@ -9646,10 +9674,7 @@ void A_TrapShot(mobj_t *actor)
y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
if (actor->eflags & MFE_VERTICALFLIP) if (actor->eflags & MFE_VERTICALFLIP)
{
z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale); z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale);
vertang = InvAngle(vertang); // flip firing angle
}
else else
z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale); z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale);
@ -9660,20 +9685,35 @@ void A_TrapShot(mobj_t *actor)
if (actor->eflags & MFE_VERTICALFLIP) if (actor->eflags & MFE_VERTICALFLIP)
missile->flags2 |= MF2_OBJECTFLIP; missile->flags2 |= MF2_OBJECTFLIP;
missile->destscale = actor->destscale;
P_SetScale(missile, missile->destscale); missile->destscale = actor->scale;
P_SetScale(missile, actor->scale);
if (missile->info->seesound) if (missile->info->seesound)
S_StartSound(actor, missile->info->seesound); S_StartSound(missile, missile->info->seesound);
P_SetTarget(&missile->target, actor); P_SetTarget(&missile->target, actor);
missile->angle = actor->angle; missile->angle = actor->angle;
speed = FixedMul(missile->info->speed, missile->scale); speed = FixedMul(missile->info->speed, missile->scale);
missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed)); if (oldstyle)
missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed)); {
missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed); missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed);
missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed);
// The below line basically mimics P_SpawnXYZMissile's momz calculation.
missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed);
P_CheckMissileSpawn(missile);
}
else
{
angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT);
if (actor->eflags & MFE_VERTICALFLIP)
vertang = InvAngle(vertang); // flip firing angle
missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed));
missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed));
missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed);
}
} }
// Function: A_VileTarget // Function: A_VileTarget
@ -10735,3 +10775,32 @@ void A_FlickyFlutter(mobj_t *actor)
} }
#undef FLICKYHITWALL #undef FLICKYHITWALL
// Function: A_FlameParticle
//
// Description: Creates the mobj's painchance at a random position around the object's radius.
//
// var1 = momz of particle.
//
void A_FlameParticle(mobj_t *actor)
{
mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance);
INT32 locvar1 = var1;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_FlameParticle", actor))
return;
#endif
if (type)
{
fixed_t rad = 2*actor->radius>>FRACBITS;
fixed_t hei = actor->height>>FRACBITS;
mobj_t *particle = P_SpawnMobjFromMobj(actor,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(hei/2, hei)<<FRACBITS,
type);
P_SetObjectMomZ(particle, locvar1<<FRACBITS, false);
}
}

View file

@ -13,7 +13,11 @@
#include "doomdef.h" #include "doomdef.h"
#include "doomstat.h" #include "doomstat.h"
#include "m_random.h"
#include "p_local.h" #include "p_local.h"
#ifdef ESLOPE
#include "p_slopes.h"
#endif
#include "r_state.h" #include "r_state.h"
#include "s_sound.h" #include "s_sound.h"
#include "z_zone.h" #include "z_zone.h"
@ -1141,6 +1145,7 @@ void T_MarioBlock(levelspecthink_t *block)
block->sector->ceilingdata = NULL; block->sector->ceilingdata = NULL;
block->sector->floorspeed = 0; block->sector->floorspeed = 0;
block->sector->ceilspeed = 0; block->sector->ceilspeed = 0;
block->direction = 0;
} }
for (i = -1; (i = P_FindSectorFromTag((INT16)block->vars[0], i)) >= 0 ;) for (i = -1; (i = P_FindSectorFromTag((INT16)block->vars[0], i)) >= 0 ;)
@ -1800,10 +1805,24 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
void T_MarioBlockChecker(levelspecthink_t *block) void T_MarioBlockChecker(levelspecthink_t *block)
{ {
line_t *masterline = block->sourceline; line_t *masterline = block->sourceline;
if (block->vars[2] == 1) // Don't update the textures when the block's being bumped upwards.
return;
if (SearchMarioNode(block->sector->touching_thinglist)) if (SearchMarioNode(block->sector->touching_thinglist))
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; {
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; // Update textures
if (masterline->backsector)
{
block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->ceilingpic; // Update flats to be backside's ceiling
}
}
else else
{
sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].toptexture; sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].toptexture;
if (masterline->backsector)
{
block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->floorpic; // Update flats to be backside's floor
}
}
} }
// This is the Thwomp's 'brain'. It looks around for players nearby, and if // This is the Thwomp's 'brain'. It looks around for players nearby, and if
@ -2523,6 +2542,29 @@ void T_CameraScanner(elevator_t *elevator)
} }
} }
void T_PlaneDisplace(planedisplace_t *pd)
{
sector_t *control, *target;
INT32 direction;
fixed_t diff;
control = &sectors[pd->control];
target = &sectors[pd->affectee];
if (control->floorheight == pd->last_height)
return; // no change, no movement
direction = (control->floorheight > pd->last_height) ? 1 : -1;
diff = FixedMul(control->floorheight-pd->last_height, pd->speed);
if (pd->type == pd_floor || pd->type == pd_both)
T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor
if (pd->type == pd_ceiling || pd->type == pd_both)
T_MovePlane(target, INT32_MAX/2, target->ceilingheight+diff, 0, 1, direction); // move ceiling
pd->last_height = control->floorheight;
}
// //
// EV_DoFloor // EV_DoFloor
// //
@ -2880,18 +2922,41 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
size_t topmostvertex = 0, bottommostvertex = 0; size_t topmostvertex = 0, bottommostvertex = 0;
fixed_t leftx, rightx; fixed_t leftx, rightx;
fixed_t topy, bottomy; fixed_t topy, bottomy;
fixed_t topz; fixed_t topz, bottomz;
fixed_t widthfactor, heightfactor;
fixed_t a, b, c; fixed_t a, b, c;
mobjtype_t type = MT_ROCKCRUMBLE1; mobjtype_t type = MT_ROCKCRUMBLE1;
fixed_t spacing = (32<<FRACBITS);
tic_t lifetime = 3*TICRATE;
INT16 flags = 0;
// If the control sector has a special #define controlsec rover->master->frontsector
// of Section3:7-15, use the custom debris.
if (GETSECSPECIAL(rover->master->frontsector->special, 3) >= 8) if (controlsec->tag != 0)
type = MT_ROCKCRUMBLE1+(GETSECSPECIAL(rover->master->frontsector->special, 3)-7); {
INT32 tagline = P_FindSpecialLineFromTag(14, controlsec->tag, -1);
if (tagline != -1)
{
if (sides[lines[tagline].sidenum[0]].toptexture)
type = (mobjtype_t)sides[lines[tagline].sidenum[0]].toptexture; // Set as object type in p_setup.c...
if (sides[lines[tagline].sidenum[0]].textureoffset)
spacing = sides[lines[tagline].sidenum[0]].textureoffset;
if (sides[lines[tagline].sidenum[0]].rowoffset)
{
if (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS != -1)
lifetime = (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS);
else
lifetime = 0;
}
flags = lines[tagline].flags;
}
}
#undef controlsec
// soundorg z height never gets set normally, so MEH. // soundorg z height never gets set normally, so MEH.
sec->soundorg.z = sec->floorheight; sec->soundorg.z = sec->floorheight;
S_StartSound(&sec->soundorg, sfx_crumbl); S_StartSound(&sec->soundorg, mobjinfo[type].activesound);
// Find the outermost vertexes in the subsector // Find the outermost vertexes in the subsector
for (i = 0; i < sec->linecount; i++) for (i = 0; i < sec->linecount; i++)
@ -2910,23 +2975,46 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
bottommostvertex = i; bottommostvertex = i;
} }
leftx = sec->lines[leftmostvertex]->v1->x+(16<<FRACBITS); leftx = sec->lines[leftmostvertex]->v1->x+(spacing>>1);
rightx = sec->lines[rightmostvertex]->v1->x; rightx = sec->lines[rightmostvertex]->v1->x;
topy = sec->lines[topmostvertex]->v1->y-(16<<FRACBITS); topy = sec->lines[topmostvertex]->v1->y-(spacing>>1);
bottomy = sec->lines[bottommostvertex]->v1->y; bottomy = sec->lines[bottommostvertex]->v1->y;
topz = *rover->topheight-(16<<FRACBITS);
for (a = leftx; a < rightx; a += (32<<FRACBITS)) topz = *rover->topheight-(spacing>>1);
bottomz = *rover->bottomheight;
if (flags & ML_EFFECT1)
{ {
for (b = topy; b > bottomy; b -= (32<<FRACBITS)) widthfactor = (rightx + topy - leftx - bottomy)>>3;
heightfactor = (topz - *rover->bottomheight)>>2;
}
for (a = leftx; a < rightx; a += spacing)
{
for (b = topy; b > bottomy; b -= spacing)
{ {
if (R_PointInSubsector(a, b)->sector == sec) if (R_PointInSubsector(a, b)->sector == sec)
{ {
mobj_t *spawned = NULL; mobj_t *spawned = NULL;
for (c = topz; c > *rover->bottomheight; c -= (32<<FRACBITS)) #ifdef ESLOPE
if (*rover->t_slope)
topz = P_GetZAt(*rover->t_slope, a, b) - (spacing>>1);
if (*rover->b_slope)
bottomz = P_GetZAt(*rover->b_slope, a, b);
#endif
for (c = topz; c > bottomz; c -= spacing)
{ {
spawned = P_SpawnMobj(a, b, c, type); spawned = P_SpawnMobj(a, b, c, type);
spawned->fuse = 3*TICRATE; spawned->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
if (flags & ML_EFFECT1)
{
P_InstaThrust(spawned, R_PointToAngle2(sec->soundorg.x, sec->soundorg.y, a, b), FixedDiv(P_AproxDistance(a - sec->soundorg.x, b - sec->soundorg.y), widthfactor));
P_SetObjectMomZ(spawned, FixedDiv((c - bottomz), heightfactor), false);
}
spawned->fuse = lifetime;
} }
} }
} }
@ -3086,8 +3174,10 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
return 1; return 1;
} }
INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mobj_t *puncher) INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
{ {
sector_t *roversec = rover->master->frontsector;
fixed_t topheight = *rover->topheight;
levelspecthink_t *block; levelspecthink_t *block;
mobj_t *thing; mobj_t *thing;
fixed_t oldx = 0, oldy = 0, oldz = 0; fixed_t oldx = 0, oldy = 0, oldz = 0;
@ -3095,11 +3185,14 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
I_Assert(puncher != NULL); I_Assert(puncher != NULL);
I_Assert(puncher->player != NULL); I_Assert(puncher->player != NULL);
if (sec->floordata || sec->ceilingdata) if (roversec->floordata || roversec->ceilingdata)
return 0; return 0;
if (!(rover->flags & FF_SOLID))
rover->flags |= (FF_SOLID|FF_RENDERALL|FF_CUTLEVEL);
// Find an item to pop out! // Find an item to pop out!
thing = SearchMarioNode(sec->touching_thinglist); thing = SearchMarioNode(roversec->touching_thinglist);
// Found something! // Found something!
if (thing) if (thing)
@ -3109,13 +3202,13 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL); block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
P_AddThinker(&block->thinker); P_AddThinker(&block->thinker);
sec->floordata = block; roversec->floordata = block;
sec->ceilingdata = block; roversec->ceilingdata = block;
block->thinker.function.acp1 = (actionf_p1)T_MarioBlock; block->thinker.function.acp1 = (actionf_p1)T_MarioBlock;
// Set up the fields // Set up the fields
block->sector = sec; block->sector = roversec;
block->vars[0] = roversector->tag; // actionsector block->vars[0] = sector->tag; // actionsector
block->vars[1] = 4*FRACUNIT; // speed block->vars[1] = 4*FRACUNIT; // speed
block->vars[2] = 1; // Up // direction block->vars[2] = 1; // Up // direction
block->vars[3] = block->sector->floorheight; // floorwasheight block->vars[3] = block->sector->floorheight; // floorwasheight
@ -3131,8 +3224,8 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
} }
P_UnsetThingPosition(thing); P_UnsetThingPosition(thing);
thing->x = roversector->soundorg.x; thing->x = sector->soundorg.x;
thing->y = roversector->soundorg.y; thing->y = sector->soundorg.y;
thing->z = topheight; thing->z = topheight;
thing->momz = FixedMul(6*FRACUNIT, thing->scale); thing->momz = FixedMul(6*FRACUNIT, thing->scale);
P_SetThingPosition(thing); P_SetThingPosition(thing);
@ -3149,7 +3242,7 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
{ {
if (thing->type == MT_EMMY && thing->spawnpoint && (thing->spawnpoint->options & MTF_OBJECTSPECIAL)) if (thing->type == MT_EMMY && thing->spawnpoint && (thing->spawnpoint->options & MTF_OBJECTSPECIAL))
{ {
mobj_t *tokenobj = P_SpawnMobj(roversector->soundorg.x, roversector->soundorg.y, topheight, MT_TOKEN); mobj_t *tokenobj = P_SpawnMobj(sector->soundorg.x, sector->soundorg.y, topheight, MT_TOKEN);
P_SetTarget(&thing->tracer, tokenobj); P_SetTarget(&thing->tracer, tokenobj);
P_SetTarget(&tokenobj->target, thing); P_SetTarget(&tokenobj->target, thing);
P_SetMobjState(tokenobj, mobjinfo[MT_TOKEN].seestate); P_SetMobjState(tokenobj, mobjinfo[MT_TOKEN].seestate);

View file

@ -1174,15 +1174,33 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Mario // // Mario //
// ***** // // ***** //
case MT_SHELL: case MT_SHELL:
if (special->state == &states[S_SHELL]) // Resting anim
{ {
// Kick that sucker around! boolean bounceon = ((P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0));
special->angle = toucher->angle; if (special->threshold == TICRATE) // it's moving
P_InstaThrust(special, special->angle, FixedMul(special->info->speed, special->scale)); {
S_StartSound(toucher, sfx_mario2); if (bounceon)
P_SetMobjState(special, S_SHELL1); {
P_SetTarget(&special->target, toucher); // Stop it!
special->threshold = (3*TICRATE)/2; special->momx = special->momy = 0;
S_StartSound(toucher, sfx_mario2);
P_SetTarget(&special->target, NULL);
special->threshold = TICRATE - 1;
toucher->momz = -toucher->momz;
}
else // can't handle in PIT_CheckThing because of landing-on causing it to stop
P_DamageMobj(toucher, special, special->target, 1, 0);
}
else if (special->threshold == 0)
{
// Kick that sucker around!
special->movedir = ((special->movedir == 1) ? -1 : 1);
P_InstaThrust(special, toucher->angle, (special->info->speed*special->scale));
S_StartSound(toucher, sfx_mario2);
P_SetTarget(&special->target, toucher);
special->threshold = (3*TICRATE)/2;
if (bounceon)
toucher->momz = -toucher->momz;
}
} }
return; return;
case MT_AXE: case MT_AXE:
@ -1792,7 +1810,7 @@ void P_CheckTimeLimit(void)
return; return;
//Tagmode round end but only on the tic before the //Tagmode round end but only on the tic before the
//XD_EXITLEVEL packet is recieved by all players. //XD_EXITLEVEL packet is received by all players.
if (G_TagGametype()) if (G_TagGametype())
{ {
if (leveltime == (timelimitintics + 1)) if (leveltime == (timelimitintics + 1))
@ -1803,7 +1821,7 @@ void P_CheckTimeLimit(void)
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT)) || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
continue; continue;
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]); CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
P_AddPlayerScore(&players[i], players[i].score); P_AddPlayerScore(&players[i], players[i].score);
} }
} }

View file

@ -768,8 +768,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
} }
} }
if (tmthing->type == MT_SHELL && tmthing->threshold > TICRATE)
return true;
// damage / explode // damage / explode
if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example) if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example)
P_DamageMobj(thing, tmthing, tmthing, 1, 0); P_DamageMobj(thing, tmthing, tmthing, 1, 0);
@ -810,7 +808,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
tmthing->y = thing->y; tmthing->y = thing->y;
P_SetThingPosition(tmthing); P_SetThingPosition(tmthing);
} }
else else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
P_DamageMobj(thing, tmthing, tmthing->target, 1, 0); P_DamageMobj(thing, tmthing, tmthing->target, 1, 0);
// don't traverse any more // don't traverse any more
@ -1145,7 +1143,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
return false; return false;
tmfloorz = tmceilingz = INT32_MIN; // block while in air tmfloorz = tmceilingz = topz; // block while in air
#ifdef ESLOPE #ifdef ESLOPE
tmceilingslope = NULL; tmceilingslope = NULL;
#endif #endif
@ -1191,7 +1189,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
return false; return false;
tmfloorz = tmceilingz = INT32_MAX; // block while in air tmfloorz = tmceilingz = topz; // block while in air
#ifdef ESLOPE #ifdef ESLOPE
tmfloorslope = NULL; tmfloorslope = NULL;
#endif #endif

View file

@ -564,7 +564,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
// Adjust the player's animation speed to match their velocity. // Adjust the player's animation speed to match their velocity.
if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST))
{ {
fixed_t speed;// = FixedDiv(player->speed, mobj->scale); fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor));
if (player->panim == PA_FALL) if (player->panim == PA_FALL)
{ {
speed = FixedDiv(abs(mobj->momz), mobj->scale); speed = FixedDiv(abs(mobj->momz), mobj->scale);
@ -590,7 +590,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
} }
else else
{ {
speed = FixedDiv(player->speed, mobj->scale); speed = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor));
if (player->panim == PA_ROLL || player->panim == PA_JUMP) if (player->panim == PA_ROLL || player->panim == PA_JUMP)
{ {
if (speed > 16<<FRACBITS) if (speed > 16<<FRACBITS)
@ -1135,9 +1135,6 @@ void P_ExplodeMissile(mobj_t *mo)
explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
S_StartSound(explodemo, sfx_cybdth); S_StartSound(explodemo, sfx_cybdth);
// Hack: Release an animal.
P_DamageMobj(mo, NULL, NULL, 1, DMG_INSTAKILL);
} }
mo->flags &= ~MF_MISSILE; mo->flags &= ~MF_MISSILE;
@ -1845,7 +1842,6 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
} }
#define STOPSPEED (FRACUNIT) #define STOPSPEED (FRACUNIT)
#define FRICTION (ORIG_FRICTION) // 0.90625
// //
// P_SceneryXYFriction // P_SceneryXYFriction
@ -1878,7 +1874,6 @@ static void P_SceneryXYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
{ {
// Stolen from P_SpawnFriction // Stolen from P_SpawnFriction
mo->friction = FRACUNIT - 0x100; mo->friction = FRACUNIT - 0x100;
mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158;
} }
else else
mo->friction = ORIG_FRICTION; mo->friction = ORIG_FRICTION;
@ -1903,7 +1898,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
// spinning friction // spinning friction
if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)) if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH))
{ {
const fixed_t ns = FixedDiv(549*FRICTION,500*FRACUNIT); const fixed_t ns = FixedDiv(549*ORIG_FRICTION,500*FRACUNIT);
mo->momx = FixedMul(mo->momx, ns); mo->momx = FixedMul(mo->momx, ns);
mo->momy = FixedMul(mo->momy, ns); mo->momy = FixedMul(mo->momy, ns);
} }
@ -2192,8 +2187,39 @@ void P_XYMovement(mobj_t *mo)
} }
else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE)) else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE))
{ // try to slide along it { // try to slide along it
#ifdef ESLOPE
// Wall transfer part 1.
pslope_t *transferslope = NULL;
fixed_t transfermomz = 0;
if (oldslope && (P_MobjFlip(mo)*(predictedz - mo->z) > 0)) // Only for moving up (relative to gravity), otherwise there's a failed launch when going down slopes and hitting walls
{
transferslope = ((mo->standingslope) ? mo->standingslope : oldslope);
if (((transferslope->zangle < ANGLE_180) ? transferslope->zangle : InvAngle(transferslope->zangle)) >= ANGLE_45) // Prevent some weird stuff going on on shallow slopes.
transfermomz = P_GetWallTransferMomZ(mo, transferslope);
}
#endif
P_SlideMove(mo); P_SlideMove(mo);
xmove = ymove = 0; xmove = ymove = 0;
#ifdef ESLOPE
// Wall transfer part 2.
if (transfermomz && transferslope) // Are we "transferring onto the wall" (really just a disguised vertical launch)?
{
angle_t relation; // Scale transfer momentum based on how head-on it is to the slope.
if (mo->momx || mo->momy) // "Guess" the angle of the wall you hit using new momentum
relation = transferslope->xydirection - R_PointToAngle2(0, 0, mo->momx, mo->momy);
else // Give it for free, I guess.
relation = ANGLE_90;
transfermomz = FixedMul(transfermomz,
abs(FINESINE((relation >> ANGLETOFINESHIFT) & FINEMASK)));
if (P_MobjFlip(mo)*(transfermomz - mo->momz) > 2*FRACUNIT) // Do the actual launch!
{
mo->momz = transfermomz;
mo->standingslope = NULL;
}
}
#endif
} }
else if (mo->type == MT_SPINFIRE) else if (mo->type == MT_SPINFIRE)
{ {
@ -2423,14 +2449,16 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL);
bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL);
if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water
; ;
else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
continue; continue;
else if (rover->flags & FF_QUICKSAND) // quicksand else if (rover->flags & FF_QUICKSAND) // quicksand
; ;
else if (!((rover->flags & FF_BLOCKPLAYER && mo->player) // solid to players? else if (!( // if it's not either of the following...
|| (rover->flags & FF_BLOCKOTHERS && !mo->player))) // solid to others? (rover->flags & (FF_BLOCKPLAYER|FF_MARIO) && mo->player) // ...solid to players? (mario blocks are always solid from beneath to players)
|| (rover->flags & FF_BLOCKOTHERS && !mo->player) // ...solid to others?
)) // ...don't take it into account.
continue; continue;
if (rover->flags & FF_QUICKSAND) if (rover->flags & FF_QUICKSAND)
{ {
@ -2455,7 +2483,9 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2)); delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2));
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
if (topheight > mo->floorz && abs(delta1) < abs(delta2) if (topheight > mo->floorz && abs(delta1) < abs(delta2)
&& (rover->flags & FF_SOLID) // Non-FF_SOLID Mario blocks are only solid from bottom
&& !(rover->flags & FF_REVERSEPLATFORM) && !(rover->flags & FF_REVERSEPLATFORM)
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference) && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
{ {
@ -2463,7 +2493,7 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
} }
if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
&& !(rover->flags & FF_PLATFORM) && !(rover->flags & FF_PLATFORM)
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below && ((P_MobjFlip(mo)*mo->momz >= 0) || ((rover->flags & FF_SOLID) && !(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
{ {
mo->ceilingz = bottomheight; mo->ceilingz = bottomheight;
} }
@ -2948,7 +2978,6 @@ static boolean P_ZMovement(mobj_t *mo)
// Stolen from P_SpawnFriction // Stolen from P_SpawnFriction
mo->friction = FRACUNIT - 0x100; mo->friction = FRACUNIT - 0x100;
mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158;
} }
else if (mo->type == MT_FALLINGROCK) else if (mo->type == MT_FALLINGROCK)
{ {
@ -3403,8 +3432,13 @@ nightsdone:
if (rover->flags & FF_MARIO if (rover->flags & FF_MARIO
&& !(mo->eflags & MFE_VERTICALFLIP) // if you were flipped, your head isn't actually hitting your ceilingz is it? && !(mo->eflags & MFE_VERTICALFLIP) // if you were flipped, your head isn't actually hitting your ceilingz is it?
&& *rover->bottomheight == mo->ceilingz) // The player's head hit the bottom! && *rover->bottomheight == mo->ceilingz) // The player's head hit the bottom!
{
// DO THE MARIO! // DO THE MARIO!
EV_MarioBlock(rover->master->frontsector, node->m_sector, *rover->topheight, mo); if (rover->flags & FF_SHATTERBOTTOM) // Brick block!
EV_CrumbleChain(node->m_sector, rover);
else // Question block!
EV_MarioBlock(rover, node->m_sector, mo);
}
} }
} // Ugly ugly billions of braces! Argh! } // Ugly ugly billions of braces! Argh!
} }
@ -4565,7 +4599,15 @@ static void P_Boss1Thinker(mobj_t *mobj)
return; return;
} }
if (mobj->state != &states[mobj->info->spawnstate] && mobj->health > 0 && mobj->flags & MF_FLOAT && !(mobj->flags2 & MF2_SKULLFLY)) if (mobj->flags2 & MF2_SKULLFLY)
{
fixed_t dist = (mobj->eflags & MFE_VERTICALFLIP)
? ((mobj->ceilingz-(2*mobj->height)) - (mobj->z+mobj->height))
: (mobj->z - (mobj->floorz+(2*mobj->height)));
if (dist > 0 && P_MobjFlip(mobj)*mobj->momz > 0)
mobj->momz = FixedMul(mobj->momz, FRACUNIT - (dist>>12));
}
else if (mobj->state != &states[mobj->info->spawnstate] && mobj->health > 0 && mobj->flags & MF_FLOAT)
mobj->momz = FixedMul(mobj->momz,7*FRACUNIT/8); mobj->momz = FixedMul(mobj->momz,7*FRACUNIT/8);
if (mobj->state == &states[mobj->info->meleestate] if (mobj->state == &states[mobj->info->meleestate]
@ -6734,7 +6776,7 @@ void P_MobjThinker(mobj_t *mobj)
} }
} }
if (mobj->type == MT_GHOST && mobj->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY! if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
&& (signed)(mobj->frame >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2) && (signed)(mobj->frame >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
// fade out when nearing the end of fuse... // fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT); mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
@ -7691,13 +7733,13 @@ void P_MobjThinker(mobj_t *mobj)
P_NightsItemChase(mobj); P_NightsItemChase(mobj);
break; break;
case MT_SHELL: case MT_SHELL:
if (mobj->threshold > TICRATE) if (mobj->threshold && mobj->threshold != TICRATE)
mobj->threshold--; mobj->threshold--;
if (mobj->state != &states[S_SHELL]) if (mobj->threshold >= TICRATE)
{ {
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); mobj->angle += ((mobj->movedir == 1) ? ANGLE_22h : ANGLE_337h);
P_InstaThrust(mobj, mobj->angle, FixedMul(mobj->info->speed, mobj->scale)); P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), (mobj->info->speed*mobj->scale));
} }
break; break;
case MT_TURRET: case MT_TURRET:
@ -8269,7 +8311,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->friction = ORIG_FRICTION; mobj->friction = ORIG_FRICTION;
mobj->movefactor = ORIG_FRICTION_FACTOR; mobj->movefactor = FRACUNIT;
// All mobjs are created at 100% scale. // All mobjs are created at 100% scale.
mobj->scale = FRACUNIT; mobj->scale = FRACUNIT;
@ -9780,6 +9822,85 @@ ML_NOCLIMB : Direction not controllable
} }
break; break;
} }
case MT_PARTICLEGEN:
{
fixed_t radius, speed, bottomheight, topheight;
INT32 type, numdivisions, time, anglespeed;
angle_t angledivision;
size_t line;
const size_t mthingi = (size_t)(mthing - mapthings);
for (line = 0; line < numlines; line++)
{
if (lines[line].special == 15 && lines[line].tag == mthing->angle)
break;
}
if (line == numlines)
{
CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return;
}
if (sides[lines[line].sidenum[0]].toptexture)
type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c...
else
type = (INT32)MT_PARTICLE;
speed = abs(sides[lines[line].sidenum[0]].textureoffset);
bottomheight = lines[line].frontsector->floorheight;
topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height;
numdivisions = (mthing->options >> ZSHIFT);
if (numdivisions)
{
radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y);
anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360;
angledivision = 360/numdivisions;
}
else
{
numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler.
radius = 0;
anglespeed = 0;
angledivision = 0;
}
if ((speed) && (topheight > bottomheight))
time = (INT32)(FixedDiv((topheight - bottomheight), speed) >> FRACBITS);
else
time = 1; // There's no reasonable way to set it, so just show the object for one tic and move on.
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->z = topheight;
speed *= -1;
}
else
mobj->z = bottomheight;
CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n"
"Radius is %d\n"
"Speed is %d\n"
"Anglespeed is %d\n"
"Numdivisions is %d\n"
"Angledivision is %d\n"
"Time is %d\n"
"Type is %d\n",
sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, time, type);
mobj->angle = 0;
mobj->movefactor = speed;
mobj->lastlook = numdivisions;
mobj->movedir = angledivision*ANG1;
mobj->movecount = anglespeed*ANG1;
mobj->health = time;
mobj->friction = radius;
mobj->threshold = type;
break;
}
case MT_ROCKSPAWNER: case MT_ROCKSPAWNER:
mobj->threshold = mthing->angle; mobj->threshold = mthing->angle;
mobj->movecount = mthing->extrainfo; mobj->movecount = mthing->extrainfo;

View file

@ -974,6 +974,7 @@ typedef enum
tc_noenemies, tc_noenemies,
tc_eachtime, tc_eachtime,
tc_disappear, tc_disappear,
tc_planedisplace,
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
tc_polyrotate, // haleyjd 03/26/06: polyobjects tc_polyrotate, // haleyjd 03/26/06: polyobjects
tc_polymove, tc_polymove,
@ -1097,7 +1098,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
diff |= MD_TRACER; diff |= MD_TRACER;
if (mobj->friction != ORIG_FRICTION) if (mobj->friction != ORIG_FRICTION)
diff |= MD_FRICTION; diff |= MD_FRICTION;
if (mobj->movefactor != ORIG_FRICTION_FACTOR) if (mobj->movefactor != FRACUNIT)
diff |= MD_MOVEFACTOR; diff |= MD_MOVEFACTOR;
if (mobj->fuse) if (mobj->fuse)
diff |= MD_FUSE; diff |= MD_FUSE;
@ -1537,6 +1538,21 @@ static void SaveDisappearThinker(const thinker_t *th, const UINT8 type)
WRITEINT32(save_p, ht->exists); WRITEINT32(save_p, ht->exists);
} }
//
// SavePlaneDisplaceThinker
//
// Saves a planedisplace_t thinker
//
static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
{
const planedisplace_t *ht = (const void *)th;
WRITEUINT8(save_p, type);
WRITEINT32(save_p, ht->affectee);
WRITEINT32(save_p, ht->control);
WRITEFIXED(save_p, ht->last_height);
WRITEFIXED(save_p, ht->speed);
WRITEUINT8(save_p, ht->type);
}
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
// //
@ -1818,6 +1834,12 @@ static void P_NetArchiveThinkers(void)
SaveDisappearThinker(th, tc_disappear); SaveDisappearThinker(th, tc_disappear);
continue; continue;
} }
else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace)
{
SavePlaneDisplaceThinker(th, tc_planedisplace);
continue;
}
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
{ {
@ -2083,7 +2105,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
if (diff & MD_MOVEFACTOR) if (diff & MD_MOVEFACTOR)
mobj->movefactor = READFIXED(save_p); mobj->movefactor = READFIXED(save_p);
else else
mobj->movefactor = ORIG_FRICTION_FACTOR; mobj->movefactor = FRACUNIT;
if (diff & MD_FUSE) if (diff & MD_FUSE)
mobj->fuse = READINT32(save_p); mobj->fuse = READINT32(save_p);
if (diff & MD_WATERTOP) if (diff & MD_WATERTOP)
@ -2486,6 +2508,23 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
P_AddThinker(&ht->thinker); P_AddThinker(&ht->thinker);
} }
//
// LoadPlaneDisplaceThinker
//
// Loads a planedisplace_t thinker
//
static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
{
planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->affectee = READINT32(save_p);
ht->control = READINT32(save_p);
ht->last_height = READFIXED(save_p);
ht->speed = READFIXED(save_p);
ht->type = READUINT8(save_p);
P_AddThinker(&ht->thinker);
}
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
// //
@ -2769,6 +2808,10 @@ static void P_NetUnArchiveThinkers(void)
case tc_disappear: case tc_disappear:
LoadDisappearThinker((actionf_p1)T_Disappear); LoadDisappearThinker((actionf_p1)T_Disappear);
break; break;
case tc_planedisplace:
LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
break;
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
case tc_polyrotate: case tc_polyrotate:
LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate); LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);

View file

@ -1561,6 +1561,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
sd->text[6] = 0; sd->text[6] = 0;
break; break;
} }
case 4: // Speed pad parameters
case 414: // Play SFX case 414: // Play SFX
{ {
sd->toptexture = sd->midtexture = sd->bottomtexture = 0; sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
@ -1574,6 +1576,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
break; break;
} }
case 14: // Bustable block parameters
case 15: // Fan particle spawner parameters
case 425: // Calls P_SetMobjState on calling mobj case 425: // Calls P_SetMobjState on calling mobj
case 434: // Custom Power case 434: // Custom Power
case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors

View file

@ -804,6 +804,39 @@ void P_SlopeLaunch(mobj_t *mo)
mo->standingslope = NULL; mo->standingslope = NULL;
} }
//
// P_GetWallTransferMomZ
//
// It would be nice to have a single function that does everything necessary for slope-to-wall transfer.
// However, it needs to be seperated out in P_XYMovement to take into account momentum before and after hitting the wall.
// This just performs the necessary calculations for getting the base vertical momentum; the horizontal is already reasonably calculated by P_SlideMove.
fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
{
vector3_t slopemom, axis;
angle_t ang;
if (mo->standingslope->flags & SL_NOPHYSICS)
return 0;
// If there's physics, time for launching.
// Doesn't kill the vertical momentum as much as P_SlopeLaunch does.
ang = slope->zangle + ANG15*((slope->zangle > 0) ? 1 : -1);
if (ang > ANGLE_90 && ang < ANGLE_180)
ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards
slopemom.x = mo->momx;
slopemom.y = mo->momy;
slopemom.z = 3*(mo->momz/2);
axis.x = -slope->d.y;
axis.y = slope->d.x;
axis.z = 0;
FV3_Rotate(&slopemom, &axis, ang >> ANGLETOFINESHIFT);
return 2*(slopemom.z/3);
}
// Function to help handle landing on slopes // Function to help handle landing on slopes
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
{ {

View file

@ -37,6 +37,7 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y);
void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
void P_SlopeLaunch(mobj_t *mo); void P_SlopeLaunch(mobj_t *mo);
fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope); void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
void P_ButteredSlope(mobj_t *mo); void P_ButteredSlope(mobj_t *mo);

View file

@ -51,6 +51,9 @@ mobj_t *skyboxmo[2];
// Amount (dx, dy) vector linedef is shifted right to get scroll amount // Amount (dx, dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5 #define SCROLL_SHIFT 5
// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize.
#define MAXFLATSIZE (2048<<FRACBITS)
/** Animated texture descriptor /** Animated texture descriptor
* This keeps track of an animated texture or an animated flat. * This keeps track of an animated texture or an animated flat.
* \sa P_UpdateSpecials, P_InitPicAnims, animdef_t * \sa P_UpdateSpecials, P_InitPicAnims, animdef_t
@ -108,6 +111,7 @@ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinker
static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec); static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec);
static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer); static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer);
static void P_AddSpikeThinker(sector_t *sec, INT32 referrer); static void P_AddSpikeThinker(sector_t *sec, INT32 referrer);
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee);
//SoM: 3/7/2000: New sturcture without limits. //SoM: 3/7/2000: New sturcture without limits.
@ -2440,7 +2444,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
{ {
fixed_t sfxnum; fixed_t sfxnum;
sfxnum = sides[line->sidenum[0]].toptexture; //P_AproxDistance(line->dx, line->dy)>>FRACBITS; sfxnum = sides[line->sidenum[0]].toptexture;
if (line->tag != 0 && line->flags & ML_EFFECT5) if (line->tag != 0 && line->flags & ML_EFFECT5)
{ {
@ -3683,14 +3687,13 @@ DoneSection2:
// Process Section 3 // Process Section 3
switch (special) switch (special)
{ {
case 1: // Ice/Sludge case 1: // Unused
case 2: // Wind/Current case 2: // Wind/Current
case 3: // Ice/Sludge and Wind/Current case 3: // Unused
case 4: // Conveyor Belt case 4: // Conveyor Belt
break; break;
case 5: // Speed pad w/o spin case 5: // Speed pad
case 6: // Speed pad w/ spin
if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2)
break; break;
@ -3700,9 +3703,16 @@ DoneSection2:
{ {
angle_t lineangle; angle_t lineangle;
fixed_t linespeed; fixed_t linespeed;
fixed_t sfxnum;
lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y); linespeed = sides[lines[i].sidenum[0]].textureoffset;
if (linespeed == 0)
{
CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sector->tag);
break;
}
player->mo->angle = lineangle; player->mo->angle = lineangle;
@ -3732,7 +3742,7 @@ DoneSection2:
P_InstaThrust(player->mo, player->mo->angle, linespeed); P_InstaThrust(player->mo, player->mo->angle, linespeed);
if (GETSECSPECIAL(sector->special, 3) == 6 && (player->charability2 == CA2_SPINDASH)) if ((lines[i].flags & ML_EFFECT5) && (player->charability2 == CA2_SPINDASH)) // Roll!
{ {
if (!(player->pflags & PF_SPINNING)) if (!(player->pflags & PF_SPINNING))
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
@ -3741,19 +3751,26 @@ DoneSection2:
} }
player->powers[pw_flashing] = TICRATE/3; player->powers[pw_flashing] = TICRATE/3;
S_StartSound(player->mo, sfx_spdpad);
sfxnum = sides[lines[i].sidenum[0]].toptexture;
if (!sfxnum)
sfxnum = sfx_spdpad;
S_StartSound(player->mo, sfxnum);
} }
break; break;
case 7: // Bustable block sprite parameter case 6: // Unused
case 8: case 7: // Unused
case 9: case 8: // Unused
case 10: case 9: // Unused
case 11: case 10: // Unused
case 12: case 11: // Unused
case 13: case 12: // Unused
case 14: case 13: // Unused
case 15: case 14: // Unused
case 15: // Unused
break; break;
} }
@ -3923,8 +3940,14 @@ DoneSection2:
} }
// Grab speed and sequence values // Grab speed and sequence values
speed = abs(lines[lineindex].dx)/8; speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8;
sequence = abs(lines[lineindex].dy)>>FRACBITS; sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
if (speed == 0)
{
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
break;
}
// scan the thinkers // scan the thinkers
// to find the first waypoint // to find the first waypoint
@ -3996,8 +4019,14 @@ DoneSection2:
} }
// Grab speed and sequence values // Grab speed and sequence values
speed = -(abs(lines[lineindex].dx)/8); // Negative means reverse speed = -abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; // Negative means reverse
sequence = abs(lines[lineindex].dy)>>FRACBITS; sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
if (speed == 0)
{
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
break;
}
// scan the thinkers // scan the thinkers
// to find the last waypoint // to find the last waypoint
@ -4037,6 +4066,7 @@ DoneSection2:
player->speed = speed; player->speed = speed;
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY); player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY);
player->climbing = 0;
if (player->mo->state-states != S_PLAY_SPIN) if (player->mo->state-states != S_PLAY_SPIN)
{ {
@ -4135,8 +4165,14 @@ DoneSection2:
} }
// Grab speed and sequence values // Grab speed and sequence values
speed = abs(lines[lineindex].dx)/8; speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8;
sequence = abs(lines[lineindex].dy)>>FRACBITS; sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS;
if (speed == 0)
{
CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence);
break;
}
// Find the closest waypoint // Find the closest waypoint
// Find the preceding waypoint // Find the preceding waypoint
@ -4983,7 +5019,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
if ((flags & FF_MARIO)) if ((flags & FF_MARIO))
{ {
P_AddBlockThinker(sec2, master); if (!(flags & FF_SHATTERBOTTOM)) // Don't change the textures of a brick block, just a question block
P_AddBlockThinker(sec2, master);
CheckForMarioBlocks = true; CheckForMarioBlocks = true;
} }
@ -5083,6 +5120,33 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
} }
*/ */
/**
* Adds a plane displacement thinker.
* Whenever the "control" sector moves,
* the "affectee" sector's floor or ceiling plane moves too!
*
* \param speed Rate of movement relative to control sector
* \param control Control sector.
* \param affectee Target sector.
* \sa P_SpawnSpecials, T_PlaneDisplace
* \author Monster Iestyn
*/
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee)
{
planedisplace_t *displace;
// create and initialize new displacement thinker
displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL);
P_AddThinker(&displace->thinker);
displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace;
displace->affectee = affectee;
displace->control = control;
displace->last_height = sectors[control].floorheight;
displace->speed = speed;
displace->type = type;
}
/** Adds a Mario block thinker, which changes the block's texture between blank /** Adds a Mario block thinker, which changes the block's texture between blank
* and ? depending on whether it has contents. * and ? depending on whether it has contents.
* Needed in case objects respawn inside. * Needed in case objects respawn inside.
@ -5321,7 +5385,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
elevator->distance = FixedInt(AngleFixed(angle)); elevator->distance = FixedInt(AngleFixed(angle));
} }
static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA; static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT;
/** Flashes a laser block. /** Flashes a laser block.
* *
@ -5341,10 +5405,12 @@ void T_LaserFlash(laserthink_t *flash)
if (!ffloor || !(ffloor->flags & FF_EXISTS)) if (!ffloor || !(ffloor->flags & FF_EXISTS))
return; return;
if (leveltime & 1) if (leveltime & 2)
ffloor->flags |= FF_RENDERALL; //ffloor->flags |= FF_RENDERALL;
ffloor->alpha = 0xB0;
else else
ffloor->flags &= ~FF_RENDERALL; //ffloor->flags &= ~FF_RENDERALL;
ffloor->alpha = 0x90;
sourcesec = ffloor->master->frontsector; // Less to type! sourcesec = ffloor->master->frontsector; // Less to type!
@ -5572,32 +5638,27 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Init line EFFECTs // Init line EFFECTs
for (i = 0; i < numlines; i++) for (i = 0; i < numlines; i++)
{ {
// set line specials to 0 here too, same reason as above if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups...
if (netgame || multiplayer)
{ {
// future: nonet flag? // set line specials to 0 here too, same reason as above
} if (netgame || multiplayer)
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) {
{ // future: nonet flag?
lines[i].special = 0; }
continue; else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
}
else
{
if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
{ {
lines[i].special = 0; lines[i].special = 0;
continue; continue;
} }
if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) else
{ {
lines[i].special = 0; if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
continue; || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
} || (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)))
if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) {
{ lines[i].special = 0;
lines[i].special = 0; continue;
continue; }
} }
} }
@ -5643,47 +5704,53 @@ void P_SpawnSpecials(INT32 fromnetsave)
break; break;
#endif #endif
case 7: // Flat alignment case 7: // Flat alignment - redone by toast
if (lines[i].flags & ML_EFFECT4) // Align angle if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something...
{ {
if (!(lines[i].flags & ML_EFFECT5)) // Align floor unless ALLTRIGGER flag is set angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y));
fixed_t xoffs;
fixed_t yoffs;
if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set
{ {
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) xoffs = sides[lines[i].sidenum[0]].textureoffset;
sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); yoffs = sides[lines[i].sidenum[0]].rowoffset;
}
else // Otherwise, set calculated offsets such that line's v1 is the apparent origin
{
fixed_t cosinecomponent = FINECOSINE(flatangle>>ANGLETOFINESHIFT);
fixed_t sinecomponent = FINESINE(flatangle>>ANGLETOFINESHIFT);
xoffs = (-FixedMul(lines[i].v1->x, cosinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, sinecomponent) % MAXFLATSIZE); // No danger of overflow thanks to the strategically placed modulo operations.
yoffs = (FixedMul(lines[i].v1->x, sinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, cosinecomponent) % MAXFLATSIZE); // Ditto.
} }
if (!(lines[i].flags & ML_BOUNCY)) // Align ceiling unless BOUNCY flag is set for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
{ {
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set
sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
}
}
else // Do offsets
{
if (!(lines[i].flags & ML_BLOCKMONSTERS)) // Align floor unless BLOCKMONSTERS flag is set
{
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
{ {
sectors[s].floor_xoffs += lines[i].dx; sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle;
sectors[s].floor_yoffs += lines[i].dy; sectors[s].floor_xoffs += xoffs;
sectors[s].floor_yoffs += yoffs;
// saved for netgames // saved for netgames
sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs; sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs;
sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs; sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs;
} }
}
if (!(lines[i].flags & ML_NOCLIMB)) // Align ceiling unless NOCLIMB flag is set if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
{
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
{ {
sectors[s].ceiling_xoffs += lines[i].dx; sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle;
sectors[s].ceiling_yoffs += lines[i].dy; sectors[s].ceiling_xoffs += xoffs;
sectors[s].ceiling_yoffs += yoffs;
// saved for netgames // saved for netgames
sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs; sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs;
sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs; sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs;
} }
} }
} }
else // Otherwise, print a helpful warning. Can I do no less?
CONS_Alert(CONS_WARNING,
M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"),
lines[i].tag);
break; break;
case 8: // Sector Parameters case 8: // Sector Parameters
@ -5795,6 +5862,19 @@ void P_SpawnSpecials(INT32 fromnetsave)
P_AddBridgeThinker(&lines[i], &sectors[s]);*/ P_AddBridgeThinker(&lines[i], &sectors[s]);*/
break; break;
case 66: // Displace floor by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
break;
case 67: // Displace ceiling by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
break;
case 68: // Displace both floor AND ceiling by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s);
break;
case 100: // FOF (solid, opaque, shadows) case 100: // FOF (solid, opaque, shadows)
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers);
break; break;
@ -5809,11 +5889,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Draw the 'insides' of the block too // Draw the 'insides' of the block too
if (lines[i].flags & ML_NOCLIMB) if (lines[i].flags & ML_NOCLIMB)
{ {
ffloorflags |= FF_CUTLEVEL; ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
ffloorflags |= FF_BOTHPLANES; ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
ffloorflags |= FF_ALLSIDES;
ffloorflags &= ~FF_EXTRA;
ffloorflags &= ~FF_CUTEXTRA;
} }
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
@ -5920,11 +5997,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Draw the 'insides' of the block too // Draw the 'insides' of the block too
if (lines[i].flags & ML_EFFECT2) if (lines[i].flags & ML_EFFECT2)
{ {
ffloorflags |= FF_CUTLEVEL; ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
ffloorflags |= FF_BOTHPLANES; ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
ffloorflags |= FF_ALLSIDES;
ffloorflags &= ~FF_EXTRA;
ffloorflags &= ~FF_CUTEXTRA;
} }
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
@ -5938,11 +6012,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Draw the 'insides' of the block too // Draw the 'insides' of the block too
if (lines[i].flags & ML_EFFECT2) if (lines[i].flags & ML_EFFECT2)
{ {
ffloorflags |= FF_CUTLEVEL; ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
ffloorflags |= FF_BOTHPLANES; ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
ffloorflags |= FF_ALLSIDES;
ffloorflags &= ~FF_EXTRA;
ffloorflags &= ~FF_CUTEXTRA;
} }
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
@ -5966,11 +6037,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Draw the 'insides' of the block too // Draw the 'insides' of the block too
if (lines[i].flags & ML_EFFECT2) if (lines[i].flags & ML_EFFECT2)
{ {
ffloorflags |= FF_CUTLEVEL; ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
ffloorflags |= FF_BOTHPLANES; ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
ffloorflags |= FF_ALLSIDES;
ffloorflags &= ~FF_EXTRA;
ffloorflags &= ~FF_CUTEXTRA;
} }
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
@ -5984,11 +6052,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Draw the 'insides' of the block too // Draw the 'insides' of the block too
if (lines[i].flags & ML_EFFECT2) if (lines[i].flags & ML_EFFECT2)
{ {
ffloorflags |= FF_CUTLEVEL; ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES;
ffloorflags |= FF_BOTHPLANES; ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA);
ffloorflags |= FF_ALLSIDES;
ffloorflags &= ~FF_EXTRA;
ffloorflags &= ~FF_CUTEXTRA;
} }
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
@ -6166,7 +6231,13 @@ void P_SpawnSpecials(INT32 fromnetsave)
break; break;
case 250: // Mario Block case 250: // Mario Block
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO, secthinkers); ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO;
if (lines[i].flags & ML_NOCLIMB)
ffloorflags |= FF_SHATTERBOTTOM;
if (lines[i].flags & ML_EFFECT1)
ffloorflags &= ~(FF_SOLID|FF_RENDERALL|FF_CUTLEVEL);
P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
break; break;
case 251: // A THWOMP! case 251: // A THWOMP!
@ -6180,10 +6251,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
break; break;
case 252: // Shatter block (breaks when touched) case 252: // Shatter block (breaks when touched)
ffloorflags = FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER;
if (lines[i].flags & ML_NOCLIMB) if (lines[i].flags & ML_NOCLIMB)
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_SHATTERBOTTOM, secthinkers); ffloorflags |= FF_SOLID|FF_SHATTERBOTTOM;
else
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
break; break;
case 253: // Translucent shatter block (see 76) case 253: // Translucent shatter block (see 76)
@ -6191,10 +6263,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
break; break;
case 254: // Bustable block case 254: // Bustable block
ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP;
if (lines[i].flags & ML_NOCLIMB) if (lines[i].flags & ML_NOCLIMB)
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_ONLYKNUX, secthinkers); ffloorflags |= FF_ONLYKNUX;
else
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
break; break;
case 255: // Spin bust block (breaks when jumped or spun downwards onto) case 255: // Spin bust block (breaks when jumped or spun downwards onto)
@ -6206,10 +6279,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
break; break;
case 257: // Quicksand case 257: // Quicksand
ffloorflags = FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES;
if (lines[i].flags & ML_EFFECT5) if (lines[i].flags & ML_EFFECT5)
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES|FF_RIPPLE, secthinkers); ffloorflags |= FF_RIPPLE;
else
P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES, secthinkers); P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
break; break;
case 258: // Laser block case 258: // Laser block
@ -6970,7 +7044,6 @@ void T_Disappear(disappear_t *d)
/** Adds friction thinker. /** Adds friction thinker.
* *
* \param friction Friction value, 0xe800 is normal. * \param friction Friction value, 0xe800 is normal.
* \param movefactor Inertia factor.
* \param affectee Target sector. * \param affectee Target sector.
* \param roverfriction FOF or not * \param roverfriction FOF or not
* \sa T_Friction, P_SpawnFriction * \sa T_Friction, P_SpawnFriction
@ -7008,22 +7081,10 @@ void T_Friction(friction_t *f)
sec = sectors + f->affectee; sec = sectors + f->affectee;
// Make sure the sector type hasn't changed // Get FOF control sector
if (f->roverfriction) if (f->roverfriction)
{
referrer = sectors + f->referrer; referrer = sectors + f->referrer;
if (!(GETSECSPECIAL(referrer->special, 3) == 1
|| GETSECSPECIAL(referrer->special, 3) == 3))
return;
}
else
{
if (!(GETSECSPECIAL(sec->special, 3) == 1
|| GETSECSPECIAL(sec->special, 3) == 3))
return;
}
// Assign the friction value to players on the floor, non-floating, // Assign the friction value to players on the floor, non-floating,
// and clipped. Normally the object's friction value is kept at // and clipped. Normally the object's friction value is kept at
// ORIG_FRICTION and this thinker changes it for icy or muddy floors. // ORIG_FRICTION and this thinker changes it for icy or muddy floors.
@ -7053,14 +7114,16 @@ void T_Friction(friction_t *f)
|| (f->friction < thing->friction)) || (f->friction < thing->friction))
{ {
thing->friction = f->friction; thing->friction = f->friction;
thing->movefactor = f->movefactor; if (thing->player)
thing->movefactor = f->movefactor;
} }
} }
else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction? else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction?
|| f->friction < thing->friction)) || f->friction < thing->friction))
{ {
thing->friction = f->friction; thing->friction = f->friction;
thing->movefactor = f->movefactor; if (thing->player)
thing->movefactor = f->movefactor;
} }
} }
node = node->m_thinglist_next; node = node->m_thinglist_next;
@ -7076,33 +7139,32 @@ static void P_SpawnFriction(void)
size_t i; size_t i;
line_t *l = lines; line_t *l = lines;
register INT32 s; register INT32 s;
fixed_t length; // line length controls magnitude fixed_t strength; // frontside texture offset controls magnitude
fixed_t friction; // friction value to be applied during movement fixed_t friction; // friction value to be applied during movement
INT32 movefactor; // applied to each player move to simulate inertia INT32 movefactor; // applied to each player move to simulate inertia
for (i = 0; i < numlines; i++, l++) for (i = 0; i < numlines; i++, l++)
if (l->special == 540) if (l->special == 540)
{ {
length = P_AproxDistance(l->dx, l->dy)>>FRACBITS; strength = sides[l->sidenum[0]].textureoffset>>FRACBITS;
friction = (0x1EB8*length)/0x80 + 0xD000; if (strength > 0) // sludge
strength = strength*2; // otherwise, the maximum sludginess value is +967...
// The following might seem odd. At the time of movement,
// the move distance is multiplied by 'friction/0x10000', so a
// higher friction value actually means 'less friction'.
friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800
if (friction > FRACUNIT) if (friction > FRACUNIT)
friction = FRACUNIT; friction = FRACUNIT;
if (friction < 0) if (friction < 0)
friction = 0; friction = 0;
// The following check might seem odd. At the time of movement, movefactor = FixedDiv(ORIG_FRICTION, friction);
// the move distance is multiplied by 'friction/0x10000', so a if (movefactor < FRACUNIT)
// higher friction value actually means 'less friction'. movefactor = 8*movefactor - 7*FRACUNIT;
if (friction > ORIG_FRICTION) // ice
movefactor = ((0x10092 - friction)*(0x70))/0x158;
else else
movefactor = ((friction - 0xDB34)*(0xA))/0x80; movefactor = FRACUNIT;
// killough 8/28/98: prevent odd situations
if (movefactor < 32)
movefactor = 32;
for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;)
Add_Friction(friction, movefactor, s, -1); Add_Friction(friction, movefactor, s, -1);
@ -7352,12 +7414,10 @@ void T_Pusher(pusher_t *p)
{ {
referrer = &sectors[p->referrer]; referrer = &sectors[p->referrer];
if (!(GETSECSPECIAL(referrer->special, 3) == 2 if (GETSECSPECIAL(referrer->special, 3) != 2)
|| GETSECSPECIAL(referrer->special, 3) == 3))
return; return;
} }
else if (!(GETSECSPECIAL(sec->special, 3) == 2 else if (GETSECSPECIAL(sec->special, 3) != 2)
|| GETSECSPECIAL(sec->special, 3) == 3))
return; return;
// For constant pushers (wind/current) there are 3 situations: // For constant pushers (wind/current) there are 3 situations:

View file

@ -325,7 +325,7 @@ INT32 EV_StartCrumble(sector_t *sector, ffloor_t *rover,
INT32 EV_DoContinuousFall(sector_t *sec, sector_t *pbacksector, fixed_t spd, boolean backwards); INT32 EV_DoContinuousFall(sector_t *sec, sector_t *pbacksector, fixed_t spd, boolean backwards);
INT32 EV_MarioBlock(sector_t *sector, sector_t *roversector, fixed_t topheight, mobj_t *puncher); INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher);
void T_MoveFloor(floormove_t *movefloor); void T_MoveFloor(floormove_t *movefloor);
@ -388,7 +388,7 @@ typedef struct
{ {
thinker_t thinker; ///< Thinker structure for friction. thinker_t thinker; ///< Thinker structure for friction.
INT32 friction; ///< Friction value, 0xe800 = normal. INT32 friction; ///< Friction value, 0xe800 = normal.
INT32 movefactor; ///< Inertia factor when adding to momentum. INT32 movefactor; ///< Inertia factor when adding to momentum, FRACUNIT = normal.
INT32 affectee; ///< Number of affected sector. INT32 affectee; ///< Number of affected sector.
INT32 referrer; ///< If roverfriction == true, then this will contain the sector # of the control sector where the effect was applied. INT32 referrer; ///< If roverfriction == true, then this will contain the sector # of the control sector where the effect was applied.
UINT8 roverfriction; ///< flag for whether friction originated from a FOF or not UINT8 roverfriction; ///< flag for whether friction originated from a FOF or not
@ -450,6 +450,26 @@ void T_Disappear(disappear_t *d);
void T_Pusher(pusher_t *p); void T_Pusher(pusher_t *p);
mobj_t *P_GetPushThing(UINT32 s); mobj_t *P_GetPushThing(UINT32 s);
// Plane displacement
typedef struct
{
thinker_t thinker; ///< Thinker structure for plane displacement effect.
INT32 affectee; ///< Number of affected sector.
INT32 control; ///< Control sector used to control plane positions.
fixed_t last_height; ///< Last known height of control sector.
fixed_t speed; ///< Plane movement speed.
/** Types of plane displacement effects.
*/
enum
{
pd_floor, ///< Displace floor.
pd_ceiling, ///< Displace ceiling.
pd_both, ///< Displace both floor AND ceiling.
} type;
} planedisplace_t;
void T_PlaneDisplace(planedisplace_t *pd);
void P_CalcHeight(player_t *player); void P_CalcHeight(player_t *player);
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo); sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);

View file

@ -1624,6 +1624,12 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
// scale // scale
P_SetScale(mobj, player->mo->scale); P_SetScale(mobj, player->mo->scale);
mobj->destscale = player->mo->scale; mobj->destscale = player->mo->scale;
if (type == MT_THOK) // spintrail-specific modification for MT_THOK
{
mobj->frame = FF_TRANS70;
mobj->fuse = mobj->tics;
}
} }
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
@ -4791,6 +4797,9 @@ static void P_3dMovement(player_t *player)
acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration; acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration;
} }
if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration...
acceleration = FixedMul(acceleration<<FRACBITS, player->mo->movefactor)>>FRACBITS;
// Forward movement // Forward movement
if (player->climbing) if (player->climbing)
{ {
@ -6447,7 +6456,7 @@ static void P_SkidStuff(player_t *player)
// If your push angle is more than this close to a full 180 degrees, trigger a skid. // If your push angle is more than this close to a full 180 degrees, trigger a skid.
if (dang > ANGLE_157h) if (dang > ANGLE_157h)
{ {
player->skidtime = TICRATE/2; player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
S_StartSound(player->mo, sfx_skid); S_StartSound(player->mo, sfx_skid);
if (player->panim != PA_WALK) if (player->panim != PA_WALK)
P_SetPlayerMobjState(player->mo, S_PLAY_WALK); P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
@ -6484,6 +6493,9 @@ static void P_MovePlayer(player_t *player)
cmd = &player->cmd; cmd = &player->cmd;
runspd = FixedMul(player->runspeed, player->mo->scale); runspd = FixedMul(player->runspeed, player->mo->scale);
// Let's have some movement speed fun on low-friction surfaces, JUST for players... (high friction surfaces shouldn't have any adjustment, since the acceleration in this game is super high and that ends up cheesing high-friction surfaces.)
runspd = FixedMul(runspd, player->mo->movefactor);
// Control relinquishing stuff! // Control relinquishing stuff!
if (player->powers[pw_ingoop]) if (player->powers[pw_ingoop])
player->pflags |= PF_FULLSTASIS; player->pflags |= PF_FULLSTASIS;
@ -6674,6 +6686,7 @@ static void P_MovePlayer(player_t *player)
if (!player->mo->momx && !player->mo->momy && !player->mo->momz && player->panim == PA_WALK) if (!player->mo->momx && !player->mo->momy && !player->mo->momz && player->panim == PA_WALK)
P_SetPlayerMobjState(player->mo, S_PLAY_STND); P_SetPlayerMobjState(player->mo, S_PLAY_STND);
player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame.
////////////////// //////////////////
//GAMEPLAY STUFF// //GAMEPLAY STUFF//
@ -6895,7 +6908,7 @@ static void P_MovePlayer(player_t *player)
P_ResetScore(player); P_ResetScore(player);
// Show the "THOK!" graphic when spinning quickly across the ground. (even applies to non-spinners, in the case of zoom tubes) // Show the "THOK!" graphic when spinning quickly across the ground. (even applies to non-spinners, in the case of zoom tubes)
if (player->pflags & PF_SPINNING && player->speed > FixedMul(15<<FRACBITS, player->mo->scale) && !(player->pflags & PF_JUMPED)) if (player->pflags & PF_SPINNING && P_AproxDistance(player->speed, player->mo->momz) > FixedMul(15<<FRACBITS, player->mo->scale) && !(player->pflags & PF_JUMPED))
{ {
P_SpawnSpinMobj(player, player->spinitem); P_SpawnSpinMobj(player, player->spinitem);
if (demorecording) if (demorecording)

View file

@ -30,7 +30,7 @@
#include "f_finale.h" #include "f_finale.h"
#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself #define RUSEASM //MSC.NET can't patch itself
#endif #endif

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
#endif #endif
#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) #if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
size_t destrowbytes); size_t destrowbytes);
#define HAVE_VIDCOPY #define HAVE_VIDCOPY

View file

@ -1223,6 +1223,7 @@ int W_VerifyNMUSlumps(const char *filename)
{"COLORMAP", 8}, {"COLORMAP", 8},
{"PAL", 3}, {"PAL", 3},
{"CLM", 3}, {"CLM", 3},
{"TRANS", 5},
{NULL, 0}, {NULL, 0},
}; };
return W_VerifyFile(filename, NMUSlist, false); return W_VerifyFile(filename, NMUSlist, false);

View file

@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
static LPCSTR wClassName = "SRB2WC"; static LPCSTR wClassName = "SRB2WC";
boolean appActive = false; // app window is active INT appActive = false; // app window is active
#ifdef LOGMESSAGES #ifdef LOGMESSAGES
FILE *logstream; FILE *logstream;

View file

@ -23,7 +23,7 @@
extern HWND hWndMain; extern HWND hWndMain;
extern boolean appActive; extern INT appActive;
VOID I_GetSysMouseEvents(INT mouse_state); VOID I_GetSysMouseEvents(INT mouse_state);
extern UINT MSHWheelMessage; extern UINT MSHWheelMessage;