mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-01-29 12:40:58 +00:00
Merge branch 'master' of http://git.magicalgirl.moe/STJr/SRB2Internal.git into charabilities_mk3
# Conflicts: # src/d_clisrv.c
This commit is contained in:
commit
38c7436565
42 changed files with 3705 additions and 4646 deletions
10
src/Makefile
10
src/Makefile
|
@ -376,6 +376,14 @@ endif
|
|||
|
||||
OPTS:=-fno-exceptions $(OPTS)
|
||||
|
||||
ifdef MOBJCONSISTANCY
|
||||
OPTS+=-DMOBJCONSISTANCY
|
||||
endif
|
||||
|
||||
ifdef PACKETDROP
|
||||
OPTS+=-DPACKETDROP
|
||||
endif
|
||||
|
||||
ifdef DEBUGMODE
|
||||
|
||||
# build with debugging information
|
||||
|
@ -385,7 +393,7 @@ ifdef GCC48
|
|||
else
|
||||
CFLAGS+=-O0
|
||||
endif
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
|
||||
else
|
||||
|
||||
|
||||
|
|
1713
src/d_clisrv.c
1713
src/d_clisrv.c
File diff suppressed because it is too large
Load diff
117
src/d_clisrv.h
117
src/d_clisrv.h
|
@ -59,7 +59,7 @@ typedef enum
|
|||
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
||||
|
||||
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
|
||||
// allows HSendPacket(,true,,) to return false.
|
||||
// allows HSendPacket(*, true, *, *) to return false.
|
||||
// In addition, this packet can't occupy all the available slots.
|
||||
|
||||
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
|
||||
|
@ -76,11 +76,16 @@ typedef enum
|
|||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
// client to server packet
|
||||
// Client to server packet
|
||||
typedef struct
|
||||
{
|
||||
UINT8 client_tic;
|
||||
|
@ -89,7 +94,7 @@ typedef struct
|
|||
ticcmd_t cmd;
|
||||
} ATTRPACK clientcmd_pak;
|
||||
|
||||
// splitscreen packet
|
||||
// Splitscreen packet
|
||||
// WARNING: must have the same format of clientcmd_pak, for more easy use
|
||||
typedef struct
|
||||
{
|
||||
|
@ -110,16 +115,16 @@ typedef struct
|
|||
UINT8 starttic;
|
||||
UINT8 numtics;
|
||||
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
|
||||
ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||
} ATTRPACK servertics_pak;
|
||||
|
||||
// sent to client when all consistency data
|
||||
// Sent to client when all consistency data
|
||||
// for players has been restored
|
||||
typedef struct
|
||||
{
|
||||
UINT32 randomseed;
|
||||
|
||||
//ctf flag stuff
|
||||
// CTF flag stuff
|
||||
SINT8 flagplayer[2];
|
||||
INT32 flagloose[2];
|
||||
INT32 flagflags[2];
|
||||
|
@ -127,11 +132,11 @@ typedef struct
|
|||
fixed_t flagy[2];
|
||||
fixed_t flagz[2];
|
||||
|
||||
UINT32 ingame; // spectator bit for each player
|
||||
UINT32 ctfteam; // if not spectator, then which team?
|
||||
UINT32 ingame; // Spectator bit for each player
|
||||
INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
|
||||
|
||||
// Resynch game scores and the like all at once
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score.
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score
|
||||
INT16 numboxes[MAXPLAYERS];
|
||||
INT16 totalring[MAXPLAYERS];
|
||||
tic_t realtime[MAXPLAYERS];
|
||||
|
@ -140,14 +145,14 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
//player stuff
|
||||
// Player stuff
|
||||
UINT8 playernum;
|
||||
|
||||
// Do not send anything visual related.
|
||||
// Only send data that we need to know for physics.
|
||||
UINT8 playerstate; //playerstate_t
|
||||
UINT32 pflags; //pflags_t
|
||||
UINT8 panim; //panim_t
|
||||
UINT8 playerstate; // playerstate_t
|
||||
UINT32 pflags; // pflags_t
|
||||
UINT8 panim; // panim_t
|
||||
|
||||
angle_t aiming;
|
||||
INT32 currentweapon;
|
||||
|
@ -176,9 +181,9 @@ typedef struct
|
|||
UINT8 charability;
|
||||
UINT8 charability2;
|
||||
UINT32 charflags;
|
||||
UINT32 thokitem; //mobjtype_t
|
||||
UINT32 spinitem; //mobjtype_t
|
||||
UINT32 revitem; //mobjtype_t
|
||||
UINT32 thokitem; // mobjtype_t
|
||||
UINT32 spinitem; // mobjtype_t
|
||||
UINT32 revitem; // mobjtype_t
|
||||
fixed_t actionspd;
|
||||
fixed_t mindash;
|
||||
fixed_t maxdash;
|
||||
|
@ -234,7 +239,7 @@ typedef struct
|
|||
INT32 onconveyor;
|
||||
|
||||
//player->mo stuff
|
||||
UINT8 hasmo; //boolean
|
||||
UINT8 hasmo; // Boolean
|
||||
|
||||
INT32 health;
|
||||
angle_t angle;
|
||||
|
@ -262,10 +267,10 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
|
||||
// server launch stuffs
|
||||
// Server launch stuffs
|
||||
UINT8 serverplayer;
|
||||
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
|
||||
|
||||
|
@ -279,18 +284,18 @@ typedef struct
|
|||
|
||||
UINT8 gametype;
|
||||
UINT8 modifiedgame;
|
||||
SINT8 adminplayer; // needs to be signed
|
||||
SINT8 adminplayer; // Needs to be signed
|
||||
|
||||
char server_context[8]; // unique context id, generated at server startup.
|
||||
char server_context[8]; // Unique context id, generated at server startup.
|
||||
|
||||
UINT8 varlengthinputs[0]; // playernames and netvars
|
||||
UINT8 varlengthinputs[0]; // Playernames and netvars
|
||||
} ATTRPACK serverconfig_pak;
|
||||
|
||||
typedef struct {
|
||||
UINT8 fileid;
|
||||
UINT32 position;
|
||||
UINT16 size;
|
||||
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
|
||||
UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
|
||||
} ATTRPACK filetx_pak;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -299,14 +304,14 @@ typedef struct {
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
UINT8 localplayers;
|
||||
UINT8 mode;
|
||||
} ATTRPACK clientconfig_pak;
|
||||
|
||||
#define MAXSERVERNAME 32
|
||||
// this packet is too large
|
||||
// This packet is too large
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version;
|
||||
|
@ -372,45 +377,45 @@ typedef struct
|
|||
} ATTRPACK plrconfig;
|
||||
|
||||
//
|
||||
// Network packet data.
|
||||
// Network packet data
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
UINT32 checksum;
|
||||
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
|
||||
UINT8 ackreturn; // the return of the ack number
|
||||
UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
|
||||
UINT8 ackreturn; // The return of the ack number
|
||||
|
||||
UINT8 packettype;
|
||||
UINT8 reserved; // padding
|
||||
UINT8 reserved; // Padding
|
||||
union
|
||||
{
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
|
||||
#ifdef NEWPING
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
#endif
|
||||
} u; // this is needed to pack diff packet types data together
|
||||
} u; // This is needed to pack diff packet types data together
|
||||
} ATTRPACK doomdata_t;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#define MAXSERVERLIST 64 // depends only on the display
|
||||
#define MAXSERVERLIST 64 // Depends only on the display
|
||||
typedef struct
|
||||
{
|
||||
SINT8 node;
|
||||
|
@ -421,7 +426,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
|
|||
extern UINT32 serverlistcount;
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// points inside doomcom
|
||||
// Points inside doomcom
|
||||
extern doomdata_t *netbuffer;
|
||||
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
@ -442,7 +447,7 @@ extern consvar_t cv_playbackspeed;
|
|||
#define KICK_MSG_CUSTOM_BAN 8
|
||||
|
||||
extern boolean server;
|
||||
extern boolean dedicated; // for dedicated server
|
||||
extern boolean dedicated; // For dedicated server
|
||||
extern UINT16 software_MAXPACKETLENGTH;
|
||||
extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
|
@ -457,11 +462,11 @@ extern UINT32 playerpingtable[MAXPLAYERS];
|
|||
|
||||
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
|
||||
|
||||
// used in d_net, the only dependence
|
||||
// Used in d_net, the only dependence
|
||||
tic_t ExpandTics(INT32 low);
|
||||
void D_ClientServerInit(void);
|
||||
|
||||
// initialise the other field
|
||||
// Initialise the other field
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||
|
@ -479,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
|
|||
void CL_Reset(void);
|
||||
void CL_ClearPlayer(INT32 playernum);
|
||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||
// is there a game running
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame(void);
|
||||
|
||||
//? how many ticks to run?
|
||||
//? How many ticks to run?
|
||||
void TryRunTics(tic_t realtic);
|
||||
|
||||
// extra data for lmps
|
||||
|
|
334
src/d_net.c
334
src/d_net.c
|
@ -31,15 +31,15 @@
|
|||
//
|
||||
// NETWORKING
|
||||
//
|
||||
// gametic is the tic about to be (or currently being) run
|
||||
// server:
|
||||
// gametic is the tic about to (or currently being) run
|
||||
// Server:
|
||||
// maketic is the tic that hasn't had control made for it yet
|
||||
// nettics: is the tic for each node
|
||||
// firsttictosend: is the lowest value of nettics
|
||||
// client:
|
||||
// neededtic: is the tic needed by the client to run the game
|
||||
// firsttictosend: is used to optimize a condition
|
||||
// normally maketic >= gametic > 0
|
||||
// nettics is the tic for each node
|
||||
// firstticstosend is the lowest value of nettics
|
||||
// Client:
|
||||
// neededtic is the tic needed by the client to run the game
|
||||
// firstticstosend is used to optimize a condition
|
||||
// Normally maketic >= gametic > 0
|
||||
|
||||
#define FORCECLOSE 0x8000
|
||||
tic_t connectiontimeout = (15*TICRATE);
|
||||
|
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
|
|||
// -----------------------------------------------------------------
|
||||
// Some structs and functions for acknowledgement of packets
|
||||
// -----------------------------------------------------------------
|
||||
#define MAXACKPACKETS 96 // minimum number of nodes
|
||||
#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
|
||||
#define MAXACKTOSEND 96
|
||||
#define URGENTFREESLOTENUM 10
|
||||
#define URGENTFREESLOTNUM 10
|
||||
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
||||
|
||||
#ifndef NONET
|
||||
|
@ -139,10 +139,10 @@ typedef struct
|
|||
{
|
||||
UINT8 acknum;
|
||||
UINT8 nextacknum;
|
||||
UINT8 destinationnode;
|
||||
tic_t senttime;
|
||||
UINT16 length;
|
||||
UINT16 resentnum;
|
||||
UINT8 destinationnode; // The node to send the ack to
|
||||
tic_t senttime; // The time when the ack was sent
|
||||
UINT16 length; // The packet size
|
||||
UINT16 resentnum; // The number of
|
||||
union {
|
||||
SINT8 raw[MAXPACKETLENGTH];
|
||||
doomdata_t data;
|
||||
|
@ -212,11 +212,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
|
|||
return d;
|
||||
}
|
||||
|
||||
// return a free acknum and copy netbuffer in the ackpak table
|
||||
/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
|
||||
*
|
||||
* \param freeack The address to store the free acknum at
|
||||
* \param lowtimer ???
|
||||
* \return True if a free acknum was found
|
||||
*/
|
||||
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||
{
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
INT32 i, numfreeslote = 0;
|
||||
INT32 i, numfreeslot = 0;
|
||||
|
||||
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
|
||||
{
|
||||
|
@ -227,10 +232,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// for low priority packet, make sure let freeslotes so urgents packets can be sent
|
||||
numfreeslote++;
|
||||
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
|
||||
continue;
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
if (netbuffer->packettype >= PT_CANFAIL)
|
||||
{
|
||||
numfreeslot++;
|
||||
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||
continue;
|
||||
}
|
||||
|
||||
ackpak[i].acknum = node->nextacknum;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
|
@ -241,7 +249,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
ackpak[i].length = doomcom->datalength;
|
||||
if (lowtimer)
|
||||
{
|
||||
// lowtime mean can't be sent now so try it soon as possible
|
||||
// Lowtime means can't be sent now so try it as soon as possible
|
||||
ackpak[i].senttime = 0;
|
||||
ackpak[i].resentnum = 1;
|
||||
}
|
||||
|
@ -254,7 +262,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
|
||||
*freeack = ackpak[i].acknum;
|
||||
|
||||
sendackpacket++; // for stat
|
||||
sendackpacket++; // For stat
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -266,14 +274,14 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Get a ack to send in the queu of this node
|
||||
// Get a ack to send in the queue of this node
|
||||
static UINT8 GetAcktosend(INT32 node)
|
||||
{
|
||||
nodes[node].lasttimeacktosend_sent = I_GetTime();
|
||||
return nodes[node].firstacktosend;
|
||||
}
|
||||
|
||||
static void Removeack(INT32 i)
|
||||
static void RemoveAck(INT32 i)
|
||||
{
|
||||
INT32 node = ackpak[i].destinationnode;
|
||||
#ifndef NEWPING
|
||||
|
@ -294,27 +302,27 @@ static void Removeack(INT32 i)
|
|||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
// we have got a packet proceed the ack request and ack return
|
||||
// We have got a packet, proceed the ack request and ack return
|
||||
static boolean Processackpak(void)
|
||||
{
|
||||
INT32 i;
|
||||
boolean goodpacket = true;
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
|
||||
// received an ack return, so remove the ack in the list
|
||||
// Received an ack return, so remove the ack in the list
|
||||
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
|
||||
{
|
||||
node->remotefirstack = netbuffer->ackreturn;
|
||||
// search the ackbuffer and free it
|
||||
// Search the ackbuffer and free it
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
||||
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
|
||||
{
|
||||
Removeack(i);
|
||||
RemoveAck(i);
|
||||
}
|
||||
}
|
||||
|
||||
// received a packet with ack, queue it to send the ack back
|
||||
// Received a packet with ack, queue it to send the ack back
|
||||
if (netbuffer->ack)
|
||||
{
|
||||
UINT8 ack = netbuffer->ack;
|
||||
|
@ -323,23 +331,23 @@ static boolean Processackpak(void)
|
|||
{
|
||||
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if it is not already in the queue
|
||||
// Check if it is not already in the queue
|
||||
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
||||
if (node->acktosend[i] == ack)
|
||||
{
|
||||
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
break;
|
||||
}
|
||||
if (goodpacket)
|
||||
{
|
||||
// is a good packet so increment the acknowledge number,
|
||||
// then search for a "hole" in the queue
|
||||
// Is a good packet so increment the acknowledge number,
|
||||
// Then search for a "hole" in the queue
|
||||
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
|
||||
if (!nextfirstack)
|
||||
nextfirstack = 1;
|
||||
|
@ -383,10 +391,10 @@ static boolean Processackpak(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
else // out of order packet
|
||||
else // Out of order packet
|
||||
{
|
||||
// don't increment firsacktosend, put it in asktosend queue
|
||||
// will be incremented when the nextfirstack comes (code above)
|
||||
// Don't increment firsacktosend, put it in asktosend queue
|
||||
// Will be incremented when the nextfirstack comes (code above)
|
||||
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
|
||||
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
|
||||
if (newhead != node->acktosend_tail)
|
||||
|
@ -394,8 +402,8 @@ static boolean Processackpak(void)
|
|||
node->acktosend[node->acktosend_head] = ack;
|
||||
node->acktosend_head = newhead;
|
||||
}
|
||||
else // buffer full discard packet, sender will resend it
|
||||
{ // we can admit the packet but we will not detect the duplication after :(
|
||||
else // Buffer full discard packet, sender will resend it
|
||||
{ // We can admit the packet but we will not detect the duplication after :(
|
||||
DEBFILE("no more freeackret\n");
|
||||
goodpacket = false;
|
||||
}
|
||||
|
@ -430,25 +438,24 @@ static void GotAcks(void)
|
|||
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
||||
{
|
||||
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
||||
Removeack(i);
|
||||
else
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// when resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
RemoveAck(i);
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// When resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void Net_ConnectionTimeout(INT32 node)
|
||||
{
|
||||
// send a very special packet to self (hack the reboundstore queue)
|
||||
// main code will handle it
|
||||
// Send a very special packet to self (hack the reboundstore queue)
|
||||
// Main code will handle it
|
||||
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
|
||||
reboundstore[rebound_head].ack = 0;
|
||||
reboundstore[rebound_head].ackreturn = 0;
|
||||
|
@ -456,12 +463,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
|
|||
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
||||
rebound_head = (rebound_head+1) % MAXREBOUND;
|
||||
|
||||
// do not redo it quickly (if we do not close connection it is
|
||||
// Do not redo it quickly (if we do not close connection it is
|
||||
// for a good reason!)
|
||||
nodes[node].lasttimepacketreceived = I_GetTime();
|
||||
}
|
||||
|
||||
// resend the data if needed
|
||||
// Resend the data if needed
|
||||
void Net_AckTicker(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
|
@ -497,7 +504,7 @@ void Net_AckTicker(void)
|
|||
ackpak[i].senttime = I_GetTime();
|
||||
ackpak[i].resentnum++;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
retransmit++; // for stat
|
||||
retransmit++; // For stat
|
||||
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
|
||||
(size_t)(ackpak[i].length - BASEPACKETSIZE));
|
||||
}
|
||||
|
@ -505,11 +512,11 @@ void Net_AckTicker(void)
|
|||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
// this is something like node open flag
|
||||
// This is something like node open flag
|
||||
if (nodes[i].firstacktosend)
|
||||
{
|
||||
// we haven't sent a packet for a long time
|
||||
// acknowledge packet if needed
|
||||
// We haven't sent a packet for a long time
|
||||
// Acknowledge packet if needed
|
||||
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
||||
Net_SendAcks(i);
|
||||
|
||||
|
@ -523,9 +530,9 @@ void Net_AckTicker(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
// remove last packet received ack before resending the ackret
|
||||
// Remove last packet received ack before resending the ackreturn
|
||||
// (the higher layer doesn't have room, or something else ....)
|
||||
void Net_UnAcknowledgPacket(INT32 node)
|
||||
void Net_UnAcknowledgePacket(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
|
@ -564,20 +571,29 @@ void Net_UnAcknowledgPacket(INT32 node)
|
|||
#endif
|
||||
}
|
||||
|
||||
boolean Net_AllAckReceived(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
/** Checks if all acks have been received
|
||||
*
|
||||
* \return True if all acks have been received
|
||||
*
|
||||
*/
|
||||
static boolean Net_AllAcksReceived(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// wait for all ackreturns with timeout in seconds
|
||||
/** Waits for all ackreturns
|
||||
*
|
||||
* \param timeout Timeout in seconds
|
||||
*
|
||||
*/
|
||||
void Net_WaitAllAckReceived(UINT32 timeout)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -587,7 +603,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
timeout = tictac + timeout*NEWTICRATE;
|
||||
|
||||
HGetPacket();
|
||||
while (timeout > I_GetTime() && !Net_AllAckReceived())
|
||||
while (timeout > I_GetTime() && !Net_AllAcksReceived())
|
||||
{
|
||||
while (tictac == I_GetTime())
|
||||
I_Sleep();
|
||||
|
@ -598,18 +614,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void InitNode(INT32 node)
|
||||
static void InitNode(node_t *node)
|
||||
{
|
||||
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
|
||||
node->acktosend_head = node->acktosend_tail = 0;
|
||||
#ifndef NEWPING
|
||||
nodes[node].ping = PINGDEFAULT;
|
||||
nodes[node].varping = VARPINGDEFAULT;
|
||||
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
|
||||
node->ping = PINGDEFAULT;
|
||||
node->varping = VARPINGDEFAULT;
|
||||
node->timeout = TIMEOUT(node->ping, node->varping);
|
||||
#endif
|
||||
nodes[node].firstacktosend = 0;
|
||||
nodes[node].nextacknum = 1;
|
||||
nodes[node].remotefirstack = 0;
|
||||
nodes[node].flags = 0;
|
||||
node->firstacktosend = 0;
|
||||
node->nextacknum = 1;
|
||||
node->remotefirstack = 0;
|
||||
node->flags = 0;
|
||||
}
|
||||
|
||||
static void InitAck(void)
|
||||
|
@ -622,9 +638,14 @@ static void InitAck(void)
|
|||
#endif
|
||||
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
InitNode(i);
|
||||
InitNode(&nodes[i]);
|
||||
}
|
||||
|
||||
/** Removes all acks of a given packet type
|
||||
*
|
||||
* \param packettype The packet type to forget
|
||||
*
|
||||
*/
|
||||
void Net_AbortPacketType(UINT8 packettype)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -676,8 +697,8 @@ void Net_CloseConnection(INT32 node)
|
|||
ackpak[i].acknum = 0;
|
||||
}
|
||||
|
||||
InitNode(node);
|
||||
AbortSendFiles(node);
|
||||
InitNode(&nodes[node]);
|
||||
SV_AbortSendFiles(node);
|
||||
I_NetFreeNodenum(node);
|
||||
#endif
|
||||
}
|
||||
|
@ -729,9 +750,15 @@ static void fprintfstring(char *s, size_t len)
|
|||
}
|
||||
if (mode)
|
||||
fprintf(debugfile, "]");
|
||||
}
|
||||
|
||||
static void fprintfstringnewline(char *s, size_t len)
|
||||
{
|
||||
fprintfstring(s, len);
|
||||
fprintf(debugfile, "\n");
|
||||
}
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename packet types
|
||||
static const char *packettypename[NUMPACKETTYPE] =
|
||||
{
|
||||
"NOTHING",
|
||||
|
@ -749,15 +776,22 @@ static const char *packettypename[NUMPACKETTYPE] =
|
|||
|
||||
"ASKINFO",
|
||||
"SERVERINFO",
|
||||
"PLAYERINFO",
|
||||
"REQUESTFILE",
|
||||
"ASKINFOVIAMS",
|
||||
|
||||
"PLAYERCONFIGS",
|
||||
"RESYNCHEND",
|
||||
"RESYNCHGET",
|
||||
|
||||
"FILEFRAGMENT",
|
||||
"TEXTCMD",
|
||||
"TEXTCMD2",
|
||||
"CLIENTJOIN",
|
||||
"NODETIMEOUT",
|
||||
"RESYNCHING",
|
||||
#ifdef NEWPING
|
||||
"PING"
|
||||
#endif
|
||||
};
|
||||
|
||||
static void DebugPrintpacket(const char *header)
|
||||
|
@ -770,20 +804,29 @@ static void DebugPrintpacket(const char *header)
|
|||
{
|
||||
case PT_ASKINFO:
|
||||
case PT_ASKINFOVIAMS:
|
||||
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) );
|
||||
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
|
||||
break;
|
||||
case PT_CLIENTJOIN:
|
||||
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
|
||||
netbuffer->u.clientcfg.mode);
|
||||
break;
|
||||
case PT_SERVERTICS:
|
||||
{
|
||||
servertics_pak *serverpak = &netbuffer->u.serverpak;
|
||||
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics];
|
||||
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd;
|
||||
|
||||
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
||||
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
|
||||
netbuffer->u.serverpak.numtics,
|
||||
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
|
||||
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
|
||||
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
|
||||
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
||||
fprintfstring((char *)cmd, 3);
|
||||
if (ntxtcmd > 4)
|
||||
{
|
||||
fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]);
|
||||
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
||||
}
|
||||
fprintf(debugfile, "\n");
|
||||
break;
|
||||
}
|
||||
case PT_CLIENTCMD:
|
||||
case PT_CLIENT2CMD:
|
||||
case PT_CLIENTMIS:
|
||||
|
@ -797,7 +840,8 @@ static void DebugPrintpacket(const char *header)
|
|||
case PT_TEXTCMD:
|
||||
case PT_TEXTCMD2:
|
||||
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
|
||||
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
|
||||
fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
|
||||
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
|
||||
break;
|
||||
case PT_SERVERCFG:
|
||||
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
|
||||
|
@ -813,7 +857,7 @@ static void DebugPrintpacket(const char *header)
|
|||
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
|
||||
netbuffer->u.serverinfo.fileneedednum,
|
||||
(UINT32)LONG(netbuffer->u.serverinfo.time));
|
||||
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
|
||||
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
|
||||
break;
|
||||
|
@ -827,20 +871,100 @@ static void DebugPrintpacket(const char *header)
|
|||
break;
|
||||
case PT_REQUESTFILE:
|
||||
default: // write as a raw packet
|
||||
fprintfstring((char *)netbuffer->u.textcmd,
|
||||
fprintfstringnewline((char *)netbuffer->u.textcmd,
|
||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PACKETDROP
|
||||
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
|
||||
static INT32 packetdroprate = 0;
|
||||
|
||||
void Command_Drop(void)
|
||||
{
|
||||
INT32 packetquantity;
|
||||
const char *packetname;
|
||||
size_t i;
|
||||
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
|
||||
"drop reset: cancel all packet drops");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
|
||||
{
|
||||
memset(packetdropquantity, 0, sizeof(packetdropquantity));
|
||||
return;
|
||||
}
|
||||
|
||||
if (COM_Argc() >= 3)
|
||||
{
|
||||
packetquantity = atoi(COM_Argv(2));
|
||||
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
|
||||
{
|
||||
CONS_Printf("Invalid quantity\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
packetquantity = -1;
|
||||
|
||||
packetname = COM_Argv(1);
|
||||
|
||||
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
packetdropquantity[i] = packetquantity;
|
||||
else
|
||||
{
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
if (!stricmp(packetname, packettypename[i]))
|
||||
{
|
||||
packetdropquantity[i] = packetquantity;
|
||||
return;
|
||||
}
|
||||
|
||||
CONS_Printf("Unknown packet name\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Droprate(void)
|
||||
{
|
||||
INT32 droprate;
|
||||
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
|
||||
return;
|
||||
}
|
||||
|
||||
droprate = atoi(COM_Argv(1));
|
||||
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
|
||||
{
|
||||
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
packetdroprate = droprate;
|
||||
}
|
||||
|
||||
static boolean ShouldDropPacket(void)
|
||||
{
|
||||
return (packetdropquantity[netbuffer->packettype])
|
||||
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// HSendPacket
|
||||
//
|
||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
|
||||
{
|
||||
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
|
||||
if (node == 0) // packet is to go back to us
|
||||
if (node == 0) // Packet is to go back to us
|
||||
{
|
||||
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
|
||||
{
|
||||
|
@ -871,7 +995,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
(void)reliable;
|
||||
(void)acknum;
|
||||
#else
|
||||
// do this before GetFreeAcknum because this function backup
|
||||
// do this before GetFreeAcknum because this function backups
|
||||
// the current packet
|
||||
doomcom->remotenode = (INT16)node;
|
||||
if (doomcom->datalength <= 0)
|
||||
|
@ -884,7 +1008,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
return false;
|
||||
}
|
||||
|
||||
if (node < MAXNETNODES) // can be a broadcast
|
||||
if (node < MAXNETNODES) // Can be a broadcast
|
||||
netbuffer->ackreturn = GetAcktosend(node);
|
||||
else
|
||||
netbuffer->ackreturn = 0;
|
||||
|
@ -905,20 +1029,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
netbuffer->ack = acknum;
|
||||
|
||||
netbuffer->checksum = NetbufferChecksum();
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
// simulate internet :)
|
||||
if (true || rand()<(INT32)RAND_MAX/5)
|
||||
#ifdef PACKETDROP
|
||||
// Simulate internet :)
|
||||
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
|
||||
if (!ShouldDropPacket())
|
||||
{
|
||||
#endif
|
||||
#ifdef DEBUGFILE
|
||||
if (debugfile)
|
||||
DebugPrintpacket("SEND");
|
||||
DebugPrintpacket("SENT");
|
||||
#endif
|
||||
I_NetSend();
|
||||
#ifdef PACKETDROP
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetdropquantity[netbuffer->packettype] > 0)
|
||||
packetdropquantity[netbuffer->packettype]--;
|
||||
#ifdef DEBUGFILE
|
||||
else if (debugfile)
|
||||
DebugPrintpacket("NOTSEND");
|
||||
if (debugfile)
|
||||
DebugPrintpacket("NOT SENT");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ndef NONET
|
||||
|
@ -933,7 +1067,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
//
|
||||
boolean HGetPacket(void)
|
||||
{
|
||||
// get a packet from self
|
||||
// Get a packet from self
|
||||
if (rebound_tail != rebound_head)
|
||||
{
|
||||
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
||||
|
@ -963,11 +1097,11 @@ boolean HGetPacket(void)
|
|||
if (doomcom->remotenode == -1)
|
||||
return false;
|
||||
|
||||
getbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
if (doomcom->remotenode >= MAXNETNODES)
|
||||
{
|
||||
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
|
||||
DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1230,4 +1364,6 @@ void D_CloseConnection(void)
|
|||
netgame = false;
|
||||
addedtogame = false;
|
||||
}
|
||||
|
||||
D_ResetTiccmds();
|
||||
}
|
||||
|
|
18
src/d_net.h
18
src/d_net.h
|
@ -18,10 +18,10 @@
|
|||
#ifndef __D_NET__
|
||||
#define __D_NET__
|
||||
|
||||
// Max computers in a game.
|
||||
// Max computers in a game
|
||||
#define MAXNETNODES 32
|
||||
#define BROADCASTADDR MAXNETNODES
|
||||
#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
|
||||
#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
|
||||
|
||||
#define STATLENGTH (TICRATE*2)
|
||||
|
||||
|
@ -32,17 +32,16 @@ extern float lostpercent, duppercent, gamelostpercent;
|
|||
extern INT32 packetheaderlength;
|
||||
boolean Net_GetNetStat(void);
|
||||
extern INT32 getbytes;
|
||||
extern INT64 sendbytes; // realtime updated
|
||||
extern INT64 sendbytes; // Realtime updated
|
||||
|
||||
extern SINT8 nodetoplayer[MAXNETNODES];
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||
|
||||
void Net_AckTicker(void);
|
||||
boolean Net_AllAckReceived(void);
|
||||
|
||||
// if reliable return true if packet sent, 0 else
|
||||
// If reliable return true if packet sent, 0 else
|
||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
|
||||
size_t packetlength);
|
||||
boolean HGetPacket(void);
|
||||
|
@ -52,9 +51,10 @@ void D_SaveBan(void);
|
|||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
void Net_UnAcknowledgPacket(INT32 node);
|
||||
void Net_UnAcknowledgePacket(INT32 node);
|
||||
void Net_CloseConnection(INT32 node);
|
||||
void Net_AbortPacketType(UINT8 packettype);
|
||||
void Net_SendAcks(INT32 node);
|
||||
void Net_WaitAllAckReceived(UINT32 timeout);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -365,6 +365,35 @@ boolean splitscreen = false;
|
|||
boolean circuitmap = false;
|
||||
INT32 adminplayer = -1;
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||
const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||
{
|
||||
"NAMEANDCOLOR",
|
||||
"WEAPONPREF",
|
||||
"KICK",
|
||||
"NETVAR",
|
||||
"SAY",
|
||||
"MAP",
|
||||
"EXITLEVEL",
|
||||
"ADDFILE",
|
||||
"PAUSE",
|
||||
"ADDPLAYER",
|
||||
"TEAMCHANGE",
|
||||
"CLEARSCORES",
|
||||
"LOGIN",
|
||||
"VERIFIED",
|
||||
"RANDOMSEED",
|
||||
"RUNSOC",
|
||||
"REQADDFILE",
|
||||
"DELFILE",
|
||||
"SETMOTD",
|
||||
"SUICIDE",
|
||||
#ifdef HAVE_BLUA
|
||||
"LUACMD",
|
||||
"LUAVAR"
|
||||
#endif
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// SERVER STARTUP
|
||||
// =========================================================================
|
||||
|
@ -3960,7 +3989,7 @@ static void Command_Archivetest_f(void)
|
|||
}
|
||||
|
||||
// assign mobjnum
|
||||
i = 0;
|
||||
i = 1;
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
((mobj_t *)th)->mobjnum = i++;
|
||||
|
|
|
@ -101,7 +101,6 @@ extern consvar_t cv_recycler;
|
|||
extern consvar_t cv_itemfinder;
|
||||
|
||||
extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit;
|
||||
extern consvar_t cv_soniccd;
|
||||
extern consvar_t cv_match_scoring;
|
||||
extern consvar_t cv_overtime;
|
||||
extern consvar_t cv_startinglives;
|
||||
|
@ -162,6 +161,8 @@ typedef enum
|
|||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
||||
extern const char *netxcmdnames[MAXNETXCMD - 1];
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
|
385
src/d_netfil.c
385
src/d_netfil.c
|
@ -62,34 +62,37 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid);
|
||||
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
|
||||
|
||||
// sender structure
|
||||
// Sender structure
|
||||
typedef struct filetx_s
|
||||
{
|
||||
INT32 ram;
|
||||
char *filename; // name of the file or ptr of the data in ram
|
||||
UINT32 size;
|
||||
union {
|
||||
char *filename; // Name of the file
|
||||
char *ram; // Pointer to the data in RAM
|
||||
} id;
|
||||
UINT32 size; // Size of the file
|
||||
UINT8 fileid;
|
||||
INT32 node; // destination
|
||||
struct filetx_s *next; // a queue
|
||||
INT32 node; // Destination
|
||||
struct filetx_s *next; // Next file in the list
|
||||
} filetx_t;
|
||||
|
||||
// current transfers (one for each node)
|
||||
// Current transfers (one for each node)
|
||||
typedef struct filetran_s
|
||||
{
|
||||
filetx_t *txlist;
|
||||
UINT32 position;
|
||||
FILE *currentfile;
|
||||
filetx_t *txlist; // Linked list of all files for the node
|
||||
UINT32 position; // The current position in the file
|
||||
FILE *currentfile; // The file currently being sent/received
|
||||
} filetran_t;
|
||||
static filetran_t transfer[MAXNETNODES];
|
||||
|
||||
// read time of file: stat _stmtime
|
||||
// write time of file: utime
|
||||
// Read time of file: stat _stmtime
|
||||
// Write time of file: utime
|
||||
|
||||
// receiver structure
|
||||
INT32 fileneedednum;
|
||||
fileneeded_t fileneeded[MAX_WADFILES];
|
||||
// Receiver structure
|
||||
INT32 fileneedednum; // Number of files needed to join the server
|
||||
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
|
||||
char downloaddir[256] = "DOWNLOAD";
|
||||
|
||||
#ifdef CLIENT_LOADINGSCREEN
|
||||
|
@ -100,6 +103,7 @@ INT32 lastfilenum = 0;
|
|||
/** Fills a serverinfo packet with information about wad files loaded.
|
||||
*
|
||||
* \todo Give this function a better name since it is in global scope.
|
||||
*
|
||||
*/
|
||||
UINT8 *PutFileNeeded(void)
|
||||
{
|
||||
|
@ -111,19 +115,19 @@ UINT8 *PutFileNeeded(void)
|
|||
|
||||
for (i = 0; i < numwadfiles; i++)
|
||||
{
|
||||
// if it has only music/sound lumps, mark it as unimportant
|
||||
// If it has only music/sound lumps, mark it as unimportant
|
||||
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
|
||||
filestatus = 0;
|
||||
else
|
||||
filestatus = 1; // important
|
||||
filestatus = 1; // Important
|
||||
|
||||
// Store in the upper four bits
|
||||
if (!cv_downloading.value)
|
||||
filestatus += (2 << 4); // won't send
|
||||
filestatus += (2 << 4); // Won't send
|
||||
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
|
||||
filestatus += (0 << 4); // won't send
|
||||
filestatus += (0 << 4); // Won't send
|
||||
else
|
||||
filestatus += (1 << 4); // will send if requested
|
||||
filestatus += (1 << 4); // Will send if requested
|
||||
|
||||
bytesused += (nameonlylength(wadfilename) + 22);
|
||||
|
||||
|
@ -144,7 +148,12 @@ UINT8 *PutFileNeeded(void)
|
|||
return p;
|
||||
}
|
||||
|
||||
// parse the serverinfo packet and fill fileneeded table on client
|
||||
/** Parses the serverinfo packet and fills the fileneeded table on client
|
||||
*
|
||||
* \param fileneedednum_parm The number of files needed to join the server
|
||||
* \param fileneededstr The memory block containing the list of needed files
|
||||
*
|
||||
*/
|
||||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -155,14 +164,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
|||
p = (UINT8 *)fileneededstr;
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
{
|
||||
fileneeded[i].status = FS_NOTFOUND;
|
||||
filestatus = READUINT8(p);
|
||||
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
|
||||
filestatus = READUINT8(p); // The first byte is the file status
|
||||
fileneeded[i].important = (UINT8)(filestatus & 3);
|
||||
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
|
||||
fileneeded[i].totalsize = READUINT32(p);
|
||||
fileneeded[i].phandle = NULL;
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
|
||||
READMEM(p, fileneeded[i].md5sum, 16);
|
||||
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
|
||||
fileneeded[i].file = NULL; // The file isn't open yet
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
|
||||
READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,13 +180,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
|
|||
fileneedednum = 1;
|
||||
fileneeded[0].status = FS_REQUESTED;
|
||||
fileneeded[0].totalsize = UINT32_MAX;
|
||||
fileneeded[0].phandle = NULL;
|
||||
fileneeded[0].file = NULL;
|
||||
memset(fileneeded[0].md5sum, 0, 16);
|
||||
strcpy(fileneeded[0].filename, tmpsave);
|
||||
}
|
||||
|
||||
/** Checks the server to see if we CAN download all the files,
|
||||
* before starting to create them and requesting.
|
||||
*
|
||||
* \return True if we can download all the files
|
||||
*
|
||||
*/
|
||||
boolean CL_CheckDownloadable(void)
|
||||
{
|
||||
|
@ -239,8 +251,12 @@ boolean CL_CheckDownloadable(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
/** Send requests for files in the ::fileneeded table with a status of
|
||||
/** Sends requests for files in the ::fileneeded table with a status of
|
||||
* ::FS_NOTFOUND.
|
||||
*
|
||||
* \return True if the packet was successfully sent
|
||||
* \note Sends a PT_REQUESTFILE packet
|
||||
*
|
||||
*/
|
||||
boolean CL_SendRequestFile(void)
|
||||
{
|
||||
|
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
|
|||
if (id == 0xFF)
|
||||
break;
|
||||
READSTRINGN(p, wad, MAX_WADPATH);
|
||||
SendFile(node, wad, id);
|
||||
SV_SendFile(node, wad, id);
|
||||
}
|
||||
}
|
||||
|
||||
// client check if the fileneeded aren't already loaded or on the disk
|
||||
/** Checks if the files needed aren't already loaded or on the disk
|
||||
*
|
||||
* \return 0 if some files are missing
|
||||
* 1 if all files exist
|
||||
* 2 if some already loaded files are not requested or are in a different order
|
||||
*
|
||||
*/
|
||||
INT32 CL_CheckFiles(void)
|
||||
{
|
||||
INT32 i, j;
|
||||
|
@ -333,7 +355,7 @@ INT32 CL_CheckFiles(void)
|
|||
}
|
||||
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
|
||||
{
|
||||
// unimportant on our side. still don't care.
|
||||
// Unimportant on our side. still don't care.
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
|
@ -343,11 +365,11 @@ INT32 CL_CheckFiles(void)
|
|||
if (i >= fileneedednum || j >= numwadfiles)
|
||||
return 2;
|
||||
|
||||
// for the sake of speed, only bother with a md5 check
|
||||
// For the sake of speed, only bother with a md5 check
|
||||
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
|
||||
return 2;
|
||||
|
||||
// it's accounted for! let's keep going.
|
||||
// It's accounted for! let's keep going.
|
||||
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
|
||||
fileneeded[i].status = FS_OPEN;
|
||||
++i;
|
||||
|
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
|
|||
{
|
||||
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
|
||||
|
||||
// check in allready loaded files
|
||||
// Check in already loaded files
|
||||
for (j = 1; wadfiles[j]; j++)
|
||||
{
|
||||
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
|
||||
|
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// load it now
|
||||
// Load it now
|
||||
void CL_LoadServerFiles(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -394,7 +416,7 @@ void CL_LoadServerFiles(void)
|
|||
for (i = 1; i < fileneedednum; i++)
|
||||
{
|
||||
if (fileneeded[i].status == FS_OPEN)
|
||||
continue; // already loaded
|
||||
continue; // Already loaded
|
||||
else if (fileneeded[i].status == FS_FOUND)
|
||||
{
|
||||
P_AddWadFile(fileneeded[i].filename, NULL);
|
||||
|
@ -423,133 +445,200 @@ void CL_LoadServerFiles(void)
|
|||
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
|
||||
}
|
||||
else if (fileneeded[i].important)
|
||||
I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
|
||||
fileneeded[i].status);
|
||||
{
|
||||
const char *s;
|
||||
switch(fileneeded[i].status)
|
||||
{
|
||||
case FS_NOTFOUND:
|
||||
s = "FS_NOTFOUND";
|
||||
break;
|
||||
case FS_REQUESTED:
|
||||
s = "FS_REQUESTED";
|
||||
break;
|
||||
case FS_DOWNLOADING:
|
||||
s = "FS_DOWNLOADING";
|
||||
break;
|
||||
default:
|
||||
s = "unknown";
|
||||
break;
|
||||
}
|
||||
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
|
||||
fileneeded[i].status, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// little optimization to test if there is a file in the queue
|
||||
static INT32 filetosend = 0;
|
||||
// Number of files to send
|
||||
// Little optimization to quickly test if there is a file in the queue
|
||||
static INT32 filestosend = 0;
|
||||
|
||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||
/** Adds a file to the file list for a node
|
||||
*
|
||||
* \param node The node to send the file to
|
||||
* \param filename The file to send
|
||||
* \param fileid ???
|
||||
* \sa SV_SendRam
|
||||
*
|
||||
*/
|
||||
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||
{
|
||||
filetx_t **q;
|
||||
filetx_t *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
filetx_t *p; // The new file request
|
||||
INT32 i;
|
||||
char wadfilename[MAX_WADPATH];
|
||||
|
||||
// Find the last file in the list and set a pointer to its "next" field
|
||||
q = &transfer[node].txlist;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendFile: No more ram\n");
|
||||
p->filename = (char *)malloc(MAX_WADPATH);
|
||||
if (!p->filename)
|
||||
I_Error("SendFile: No more ram\n");
|
||||
if (!p)
|
||||
I_Error("SV_SendFile: No more memory\n");
|
||||
|
||||
// a minimum of security, can get only file in srb2 direcory
|
||||
strlcpy(p->filename, filename, MAX_WADPATH);
|
||||
nameonly(p->filename);
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
// check first in wads loaded the majority of case
|
||||
// Allocate the file name
|
||||
p->id.filename = (char *)malloc(MAX_WADPATH);
|
||||
if (!p->id.filename)
|
||||
I_Error("SV_SendFile: No more memory\n");
|
||||
|
||||
// Set the file name and get rid of the path
|
||||
strlcpy(p->id.filename, filename, MAX_WADPATH);
|
||||
nameonly(p->id.filename);
|
||||
|
||||
// Look for the requested file through all loaded files
|
||||
for (i = 0; wadfiles[i]; i++)
|
||||
{
|
||||
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
nameonly(wadfilename);
|
||||
if (!stricmp(wadfilename, p->filename))
|
||||
if (!stricmp(wadfilename, p->id.filename))
|
||||
{
|
||||
// copy filename with full path
|
||||
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
// Copy file name with full path
|
||||
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-loaded file requests
|
||||
if (!wadfiles[i])
|
||||
{
|
||||
DEBFILE(va("%s not found in wadfiles\n", filename));
|
||||
// this formerly checked if (!findfile(p->filename, NULL, true))
|
||||
// This formerly checked if (!findfile(p->id.filename, NULL, true))
|
||||
|
||||
// not found
|
||||
// don't inform client (probably hacker)
|
||||
// Not found
|
||||
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
|
||||
DEBFILE(va("Client %d request %s: not found\n", node, filename));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
|
||||
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
|
||||
{
|
||||
// too big
|
||||
// don't inform client (client sucks, man)
|
||||
// Too big
|
||||
// Don't inform client (client sucks, man)
|
||||
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
|
||||
p->ram = SF_FILE;
|
||||
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
|
||||
p->fileid = fileid;
|
||||
p->next = NULL; // end of list
|
||||
filetosend++;
|
||||
p->next = NULL; // End of list
|
||||
filestosend++;
|
||||
}
|
||||
|
||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
||||
/** Adds a memory block to the file list for a node
|
||||
*
|
||||
* \param node The node to send the memory block to
|
||||
* \param data The memory block to send
|
||||
* \param size The size of the block in bytes
|
||||
* \param freemethod How to free the block after it has been sent
|
||||
* \param fileid ???
|
||||
* \sa SV_SendFile
|
||||
*
|
||||
*/
|
||||
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
||||
{
|
||||
filetx_t **q;
|
||||
filetx_t *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
filetx_t *p; // The new file request
|
||||
|
||||
// Find the last file in the list and set a pointer to its "next" field
|
||||
q = &transfer[node].txlist;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendRam: No more ram\n");
|
||||
p->ram = freemethod;
|
||||
p->filename = data;
|
||||
if (!p)
|
||||
I_Error("SV_SendRam: No more memory\n");
|
||||
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
|
||||
p->id.ram = data;
|
||||
p->size = (UINT32)size;
|
||||
p->fileid = fileid;
|
||||
p->next = NULL; // end of list
|
||||
p->next = NULL; // End of list
|
||||
|
||||
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
|
||||
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
|
||||
|
||||
filetosend++;
|
||||
filestosend++;
|
||||
}
|
||||
|
||||
static void EndSend(INT32 node)
|
||||
/** Stops sending a file for a node, and removes the file request from the list,
|
||||
* either because the file has been fully sent or because the node was disconnected
|
||||
*
|
||||
* \param node The destination
|
||||
*
|
||||
*/
|
||||
static void SV_EndFileSend(INT32 node)
|
||||
{
|
||||
filetx_t *p = transfer[node].txlist;
|
||||
|
||||
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
|
||||
switch (p->ram)
|
||||
{
|
||||
case SF_FILE:
|
||||
case SF_FILE: // It's a file, close it and free its filename
|
||||
if (transfer[node].currentfile)
|
||||
fclose(transfer[node].currentfile);
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
break;
|
||||
case SF_Z_RAM:
|
||||
Z_Free(p->filename);
|
||||
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
|
||||
Z_Free(p->id.ram);
|
||||
break;
|
||||
case SF_RAM:
|
||||
free(p->filename);
|
||||
case SF_NOFREERAM:
|
||||
case SF_RAM: // It's a memory block allocated with malloc, use free
|
||||
free(p->id.ram);
|
||||
case SF_NOFREERAM: // Nothing to free
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the file request from the list
|
||||
transfer[node].txlist = p->next;
|
||||
transfer[node].currentfile = NULL;
|
||||
free(p);
|
||||
filetosend--;
|
||||
|
||||
// Indicate that the transmission is over
|
||||
transfer[node].currentfile = NULL;
|
||||
|
||||
filestosend--;
|
||||
}
|
||||
|
||||
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
|
||||
|
||||
void FiletxTicker(void)
|
||||
/** Handles file transmission
|
||||
*
|
||||
*
|
||||
*/
|
||||
void SV_FileSendTicker(void)
|
||||
{
|
||||
static INT32 currentnode = 0;
|
||||
filetx_pak *p;
|
||||
|
@ -557,12 +646,12 @@ void FiletxTicker(void)
|
|||
filetx_t *f;
|
||||
INT32 packetsent = PACKETPERTIC, ram, i;
|
||||
|
||||
if (!filetosend)
|
||||
if (!filestosend)
|
||||
return;
|
||||
if (!packetsent)
|
||||
packetsent++;
|
||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||
while (packetsent-- && filetosend != 0)
|
||||
while (packetsent-- && filestosend != 0)
|
||||
{
|
||||
for (i = currentnode, ram = 0; ram < MAXNETNODES;
|
||||
i = (i+1) % MAXNETNODES, ram++)
|
||||
|
@ -571,24 +660,25 @@ void FiletxTicker(void)
|
|||
goto found;
|
||||
}
|
||||
// no transfer to do
|
||||
I_Error("filetosend=%d but no filetosend found\n", filetosend);
|
||||
I_Error("filestosend=%d but no file to send found\n", filestosend);
|
||||
found:
|
||||
currentnode = (i+1) % MAXNETNODES;
|
||||
f = transfer[i].txlist;
|
||||
ram = f->ram;
|
||||
|
||||
if (!transfer[i].currentfile) // file not already open
|
||||
// Open the file if it isn't open yet, or
|
||||
if (!transfer[i].currentfile)
|
||||
{
|
||||
if (!ram)
|
||||
if (!ram) // Sending a file
|
||||
{
|
||||
long filesize;
|
||||
|
||||
transfer[i].currentfile =
|
||||
fopen(f->filename, "rb");
|
||||
fopen(f->id.filename, "rb");
|
||||
|
||||
if (!transfer[i].currentfile)
|
||||
I_Error("File %s does not exist",
|
||||
f->filename);
|
||||
f->id.filename);
|
||||
|
||||
fseek(transfer[i].currentfile, 0, SEEK_END);
|
||||
filesize = ftell(transfer[i].currentfile);
|
||||
|
@ -596,45 +686,48 @@ void FiletxTicker(void)
|
|||
// Nobody wants to transfer a file bigger
|
||||
// than 4GB!
|
||||
if (filesize >= LONG_MAX)
|
||||
I_Error("filesize of %s is too large", f->filename);
|
||||
if (-1 == filesize)
|
||||
I_Error("Error getting filesize of %s", f->filename);
|
||||
I_Error("filesize of %s is too large", f->id.filename);
|
||||
if (filesize == -1)
|
||||
I_Error("Error getting filesize of %s", f->id.filename);
|
||||
|
||||
f->size = (UINT32)filesize;
|
||||
fseek(transfer[i].currentfile, 0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
transfer[i].currentfile = (FILE *)1;
|
||||
else // Sending RAM
|
||||
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
|
||||
transfer[i].position = 0;
|
||||
}
|
||||
|
||||
// Build a packet containing a file fragment
|
||||
p = &netbuffer->u.filetxpak;
|
||||
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
|
||||
if (f->size-transfer[i].position < size)
|
||||
size = f->size-transfer[i].position;
|
||||
if (ram)
|
||||
M_Memcpy(p->data, &f->filename[transfer[i].position], size);
|
||||
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
|
||||
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
|
||||
I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
||||
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
||||
p->position = LONG(transfer[i].position);
|
||||
// put flag so receiver know the totalsize
|
||||
// Put flag so receiver knows the total size
|
||||
if (transfer[i].position + size == f->size)
|
||||
p->position |= LONG(0x80000000);
|
||||
p->fileid = f->fileid;
|
||||
p->size = SHORT((UINT16)size);
|
||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
|
||||
{ // not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
|
||||
// exit the while (can't send this one so why should i send the next?)
|
||||
break;
|
||||
|
||||
// Send the packet
|
||||
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
||||
{ // Success
|
||||
transfer[i].position = (UINT32)(transfer[i].position + size);
|
||||
if (transfer[i].position == f->size) // Finish?
|
||||
SV_EndFileSend(i);
|
||||
}
|
||||
else // success
|
||||
{
|
||||
transfer[i].position = (UINT32)(size+transfer[i].position);
|
||||
if (transfer[i].position == f->size) // finish ?
|
||||
EndSend(i);
|
||||
else
|
||||
{ // Not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
|
||||
// Exit the while (can't send this one so why should i send the next?)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,16 +739,18 @@ void Got_Filetxpak(void)
|
|||
|
||||
if (filenum >= fileneedednum)
|
||||
{
|
||||
DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
|
||||
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileneeded[filenum].status == FS_REQUESTED)
|
||||
{
|
||||
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
|
||||
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
|
||||
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
|
||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
||||
if (fileneeded[filenum].file)
|
||||
I_Error("Got_Filetxpak: already open file\n");
|
||||
fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb");
|
||||
if (!fileneeded[filenum].file)
|
||||
I_Error("Can't create file %s: %s", fileneeded[filenum].filename, strerror(errno));
|
||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
||||
fileneeded[filenum].currentsize = 0;
|
||||
fileneeded[filenum].status = FS_DOWNLOADING;
|
||||
}
|
||||
|
@ -664,24 +759,24 @@ void Got_Filetxpak(void)
|
|||
{
|
||||
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
||||
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
||||
// use a special tric to know when file is finished (not allways used)
|
||||
// WARNING: filepak can arrive out of order so don't stop now !
|
||||
// Use a special trick to know when the file is complete (not always used)
|
||||
// WARNING: file fragments can arrive out of order so don't stop yet!
|
||||
if (pos & 0x80000000)
|
||||
{
|
||||
pos &= ~0x80000000;
|
||||
fileneeded[filenum].totalsize = pos + size;
|
||||
}
|
||||
// we can receive packet in the wrong order, anyway all os support gaped file
|
||||
fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
|
||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
|
||||
// We can receive packet in the wrong order, anyway all os support gaped file
|
||||
fseek(fileneeded[filenum].file, pos, SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1)
|
||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file)));
|
||||
fileneeded[filenum].currentsize += size;
|
||||
|
||||
// finished?
|
||||
// Finished?
|
||||
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
|
||||
{
|
||||
fclose(fileneeded[filenum].phandle);
|
||||
fileneeded[filenum].phandle = NULL;
|
||||
fclose(fileneeded[filenum].file);
|
||||
fileneeded[filenum].file = NULL;
|
||||
fileneeded[filenum].status = FS_FOUND;
|
||||
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
||||
fileneeded[filenum].filename);
|
||||
|
@ -689,8 +784,8 @@ void Got_Filetxpak(void)
|
|||
}
|
||||
else
|
||||
I_Error("Received a file not requested\n");
|
||||
// send ack back quickly
|
||||
|
||||
// Send ack back quickly
|
||||
if (++filetime == 3)
|
||||
{
|
||||
Net_SendAcks(servernode);
|
||||
|
@ -702,33 +797,39 @@ void Got_Filetxpak(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
void AbortSendFiles(INT32 node)
|
||||
/** Cancels all file requests for a node
|
||||
*
|
||||
* \param node The destination
|
||||
* \sa SV_EndFileSend
|
||||
*
|
||||
*/
|
||||
void SV_AbortSendFiles(INT32 node)
|
||||
{
|
||||
while (transfer[node].txlist)
|
||||
EndSend(node);
|
||||
SV_EndFileSend(node);
|
||||
}
|
||||
|
||||
void CloseNetFile(void)
|
||||
{
|
||||
INT32 i;
|
||||
// is sending?
|
||||
// Is sending?
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
AbortSendFiles(i);
|
||||
SV_AbortSendFiles(i);
|
||||
|
||||
// receiving a file?
|
||||
// Receiving a file?
|
||||
for (i = 0; i < MAX_WADFILES; i++)
|
||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
|
||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
|
||||
{
|
||||
fclose(fileneeded[i].phandle);
|
||||
// file is not complete delete it
|
||||
fclose(fileneeded[i].file);
|
||||
// File is not complete delete it
|
||||
remove(fileneeded[i].filename);
|
||||
}
|
||||
|
||||
// remove FILEFRAGMENT from acknledge list
|
||||
// Remove PT_FILEFRAGMENT from acknowledge list
|
||||
Net_AbortPacketType(PT_FILEFRAGMENT);
|
||||
}
|
||||
|
||||
// functions cut and pasted from doomatic :)
|
||||
// Functions cut and pasted from Doomatic :)
|
||||
|
||||
void nameonly(char *s)
|
||||
{
|
||||
|
|
|
@ -29,21 +29,21 @@ typedef enum
|
|||
FS_FOUND,
|
||||
FS_REQUESTED,
|
||||
FS_DOWNLOADING,
|
||||
FS_OPEN, // is opened and used in w_wad
|
||||
FS_OPEN, // Is opened and used in w_wad
|
||||
FS_MD5SUMBAD
|
||||
} filestatus_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 important;
|
||||
UINT8 willsend; // is the server willing to send it?
|
||||
UINT8 willsend; // Is the server willing to send it?
|
||||
char filename[MAX_WADPATH];
|
||||
UINT8 md5sum[16];
|
||||
// used only for download
|
||||
FILE *phandle;
|
||||
// Used only for download
|
||||
FILE *file;
|
||||
UINT32 currentsize;
|
||||
UINT32 totalsize;
|
||||
filestatus_t status; // the value returned by recsearch
|
||||
filestatus_t status; // The value returned by recsearch
|
||||
} fileneeded_t;
|
||||
|
||||
extern INT32 fileneedednum;
|
||||
|
@ -58,28 +58,24 @@ UINT8 *PutFileNeeded(void);
|
|||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
|
||||
void CL_PrepareDownloadSaveGame(const char *tmpsave);
|
||||
|
||||
// check file list in wadfiles return 0 when a file is not found
|
||||
// 1 if all file are found
|
||||
// 2 if you cannot connect (different wad version or
|
||||
// no enought space to download files)
|
||||
INT32 CL_CheckFiles(void);
|
||||
void CL_LoadServerFiles(void);
|
||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||
UINT8 fileid);
|
||||
|
||||
void FiletxTicker(void);
|
||||
void SV_FileSendTicker(void);
|
||||
void Got_Filetxpak(void);
|
||||
|
||||
boolean CL_CheckDownloadable(void);
|
||||
boolean CL_SendRequestFile(void);
|
||||
void Got_RequestFilePak(INT32 node);
|
||||
|
||||
void AbortSendFiles(INT32 node);
|
||||
void SV_AbortSendFiles(INT32 node);
|
||||
void CloseNetFile(void);
|
||||
|
||||
boolean fileexist(char *filename, time_t ptime);
|
||||
|
||||
// search a file in the wadpath, return FS_FOUND when found
|
||||
// Search a file in the wadpath, return FS_FOUND when found
|
||||
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
|
||||
boolean completepath);
|
||||
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
||||
|
|
307
src/dehacked.c
307
src/dehacked.c
|
@ -371,7 +371,9 @@ static void clear_levels(void)
|
|||
// (no need to set num to 0, we're freeing the entire header shortly)
|
||||
Z_Free(mapheaderinfo[i]->customopts);
|
||||
|
||||
P_DeleteFlickies(i);
|
||||
P_DeleteGrades(i);
|
||||
|
||||
Z_Free(mapheaderinfo[i]);
|
||||
mapheaderinfo[i] = NULL;
|
||||
}
|
||||
|
@ -990,6 +992,34 @@ static const struct {
|
|||
{NULL, 0}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const mobjtype_t type;
|
||||
} FLICKYTYPES[] = {
|
||||
{"BLUEBIRD", MT_FLICKY_01},
|
||||
{"RABBIT", MT_FLICKY_02},
|
||||
{"CHICKEN", MT_FLICKY_03},
|
||||
{"SEAL", MT_FLICKY_04},
|
||||
{"PIG", MT_FLICKY_05},
|
||||
{"CHIPMUNK", MT_FLICKY_06},
|
||||
{"PENGUIN", MT_FLICKY_07},
|
||||
{"FISH", MT_FLICKY_08},
|
||||
{"RAM", MT_FLICKY_09},
|
||||
{"PUFFIN", MT_FLICKY_10},
|
||||
{"COW", MT_FLICKY_11},
|
||||
{"RAT", MT_FLICKY_12},
|
||||
{"BEAR", MT_FLICKY_13},
|
||||
{"DOVE", MT_FLICKY_14},
|
||||
{"CAT", MT_FLICKY_15},
|
||||
{"CANARY", MT_FLICKY_16},
|
||||
{"a", 0}, // End of normal flickies - a lower case character so will never fastcmp valid with uppercase tmp
|
||||
//{"FLICKER", MT_FLICKER},
|
||||
{"SEED", MT_SEED},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
#define MAXFLICKIES 64
|
||||
|
||||
static void readlevelheader(MYFILE *f, INT32 num)
|
||||
{
|
||||
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
|
@ -1088,8 +1118,82 @@ static void readlevelheader(MYFILE *f, INT32 num)
|
|||
// Now go to uppercase
|
||||
strupr(word2);
|
||||
|
||||
// List of flickies that are be freed in this map
|
||||
if (fastcmp(word, "FLICKYLIST") || fastcmp(word, "ANIMALLIST"))
|
||||
{
|
||||
if (fastcmp(word2, "NONE"))
|
||||
P_DeleteFlickies(num-1);
|
||||
else if (fastcmp(word2, "DEMO"))
|
||||
P_SetDemoFlickies(num-1);
|
||||
else if (fastcmp(word2, "ALL"))
|
||||
{
|
||||
mobjtype_t tmpflickies[MAXFLICKIES];
|
||||
|
||||
for (mapheaderinfo[num-1]->numFlickies = 0;
|
||||
((mapheaderinfo[num-1]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type);
|
||||
mapheaderinfo[num-1]->numFlickies++)
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type;
|
||||
|
||||
if (mapheaderinfo[num-1]->numFlickies) // just in case...
|
||||
{
|
||||
size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies;
|
||||
mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL);
|
||||
M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mobjtype_t tmpflickies[MAXFLICKIES];
|
||||
mapheaderinfo[num-1]->numFlickies = 0;
|
||||
tmp = strtok(word2,",");
|
||||
// get up to the first MAXFLICKIES flickies
|
||||
do {
|
||||
if (mapheaderinfo[num-1]->numFlickies == MAXFLICKIES) // never going to get above that number
|
||||
{
|
||||
deh_warning("Level header %d: too many flickies\n", num);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fastncmp(tmp, "MT_", 3)) // support for specified mobjtypes...
|
||||
{
|
||||
i = get_mobjtype(tmp);
|
||||
if (!i)
|
||||
{
|
||||
//deh_warning("Level header %d: unknown flicky mobj type %s\n", num, tmp); -- no need for this line as get_mobjtype complains too
|
||||
continue;
|
||||
}
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = i;
|
||||
}
|
||||
else // ...or a quick, limited selection of default flickies!
|
||||
{
|
||||
for (i = 0; FLICKYTYPES[i].name; i++)
|
||||
if (fastcmp(tmp, FLICKYTYPES[i].name))
|
||||
break;
|
||||
|
||||
if (!FLICKYTYPES[i].name)
|
||||
{
|
||||
deh_warning("Level header %d: unknown flicky selection %s\n", num, tmp);
|
||||
continue;
|
||||
}
|
||||
tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[i].type;
|
||||
}
|
||||
mapheaderinfo[num-1]->numFlickies++;
|
||||
} while ((tmp = strtok(NULL,",")) != NULL);
|
||||
|
||||
if (mapheaderinfo[num-1]->numFlickies)
|
||||
{
|
||||
size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies;
|
||||
mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL);
|
||||
// now we add them to the list!
|
||||
M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize);
|
||||
}
|
||||
else
|
||||
deh_warning("Level header %d: no valid flicky types found\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
// NiGHTS grades
|
||||
if (fastncmp(word, "GRADES", 6))
|
||||
else if (fastncmp(word, "GRADES", 6))
|
||||
{
|
||||
UINT8 mare = (UINT8)atoi(word + 6);
|
||||
|
||||
|
@ -1322,6 +1426,8 @@ static void readlevelheader(MYFILE *f, INT32 num)
|
|||
Z_Free(s);
|
||||
}
|
||||
|
||||
#undef MAXFLICKIES
|
||||
|
||||
static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
|
||||
{
|
||||
char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
|
@ -1845,6 +1951,16 @@ static actionpointer_t actionpointers[] =
|
|||
{{A_BrakLobShot}, "A_BRAKLOBSHOT"},
|
||||
{{A_NapalmScatter}, "A_NAPALMSCATTER"},
|
||||
{{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"},
|
||||
{{A_FlickySpawn}, "A_FLICKYSPAWN"},
|
||||
{{A_FlickyAim}, "A_FLICKYAIM"},
|
||||
{{A_FlickyFly}, "A_FLICKYFLY"},
|
||||
{{A_FlickySoar}, "A_FLICKYSOAR"},
|
||||
{{A_FlickyCoast}, "A_FLICKYCOAST"},
|
||||
{{A_FlickyHop}, "A_FLICKYHOP"},
|
||||
{{A_FlickyFlounder}, "A_FLICKYFLOUNDER"},
|
||||
{{A_FlickyCheck}, "A_FLICKYCHECK"},
|
||||
{{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"},
|
||||
{{A_FlickyFlutter}, "A_FLICKYFLUTTER"},
|
||||
|
||||
{{NULL}, "NONE"},
|
||||
|
||||
|
@ -3381,11 +3497,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
|
|||
{
|
||||
if (i == 0 && word2[0] != '0') // If word2 isn't a number
|
||||
i = get_mobjtype(word2); // find a thing by name
|
||||
if (i < NUMMOBJTYPES && i >= 0)
|
||||
if (i < NUMMOBJTYPES && i > 0)
|
||||
readthing(f, i);
|
||||
else
|
||||
{
|
||||
deh_warning("Thing %d out of range (0 - %d)", i, NUMMOBJTYPES-1);
|
||||
deh_warning("Thing %d out of range (1 - %d)", i, NUMMOBJTYPES-1);
|
||||
ignorelines(f);
|
||||
}
|
||||
DEH_WriteUndoline(word, word2, UNDO_HEADER);
|
||||
|
@ -5529,43 +5645,133 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SSPK4",
|
||||
"S_SSPK5",
|
||||
|
||||
// Freed Birdie
|
||||
"S_BIRD1",
|
||||
"S_BIRD2",
|
||||
"S_BIRD3",
|
||||
// Flicky-sized bubble
|
||||
"S_FLICKY_BUBBLE",
|
||||
|
||||
// Freed Bunny
|
||||
"S_BUNNY1",
|
||||
"S_BUNNY2",
|
||||
"S_BUNNY3",
|
||||
"S_BUNNY4",
|
||||
"S_BUNNY5",
|
||||
"S_BUNNY6",
|
||||
"S_BUNNY7",
|
||||
"S_BUNNY8",
|
||||
"S_BUNNY9",
|
||||
"S_BUNNY10",
|
||||
// Bluebird
|
||||
"S_FLICKY_01_OUT",
|
||||
"S_FLICKY_01_FLAP1",
|
||||
"S_FLICKY_01_FLAP2",
|
||||
"S_FLICKY_01_FLAP3",
|
||||
|
||||
// Freed Mouse
|
||||
"S_MOUSE1",
|
||||
"S_MOUSE2",
|
||||
// Rabbit
|
||||
"S_FLICKY_02_OUT",
|
||||
"S_FLICKY_02_AIM",
|
||||
"S_FLICKY_02_HOP",
|
||||
"S_FLICKY_02_UP",
|
||||
"S_FLICKY_02_DOWN",
|
||||
|
||||
// Freed Chicken
|
||||
"S_CHICKEN1",
|
||||
"S_CHICKENHOP",
|
||||
"S_CHICKENFLY1",
|
||||
"S_CHICKENFLY2",
|
||||
// Chicken
|
||||
"S_FLICKY_03_OUT",
|
||||
"S_FLICKY_03_AIM",
|
||||
"S_FLICKY_03_HOP",
|
||||
"S_FLICKY_03_UP",
|
||||
"S_FLICKY_03_FLAP1",
|
||||
"S_FLICKY_03_FLAP2",
|
||||
|
||||
// Freed Cow
|
||||
"S_COW1",
|
||||
"S_COW2",
|
||||
"S_COW3",
|
||||
"S_COW4",
|
||||
// Seal
|
||||
"S_FLICKY_04_OUT",
|
||||
"S_FLICKY_04_AIM",
|
||||
"S_FLICKY_04_HOP",
|
||||
"S_FLICKY_04_UP",
|
||||
"S_FLICKY_04_DOWN",
|
||||
"S_FLICKY_04_SWIM1",
|
||||
"S_FLICKY_04_SWIM2",
|
||||
"S_FLICKY_04_SWIM3",
|
||||
"S_FLICKY_04_SWIM4",
|
||||
|
||||
// Red Birdie in Bubble
|
||||
"S_RBIRD1",
|
||||
"S_RBIRD2",
|
||||
"S_RBIRD3",
|
||||
// Pig
|
||||
"S_FLICKY_05_OUT",
|
||||
"S_FLICKY_05_AIM",
|
||||
"S_FLICKY_05_HOP",
|
||||
"S_FLICKY_05_UP",
|
||||
"S_FLICKY_05_DOWN",
|
||||
|
||||
// Chipmunk
|
||||
"S_FLICKY_06_OUT",
|
||||
"S_FLICKY_06_AIM",
|
||||
"S_FLICKY_06_HOP",
|
||||
"S_FLICKY_06_UP",
|
||||
"S_FLICKY_06_DOWN",
|
||||
|
||||
// Penguin
|
||||
"S_FLICKY_07_OUT",
|
||||
"S_FLICKY_07_AIML",
|
||||
"S_FLICKY_07_HOPL",
|
||||
"S_FLICKY_07_UPL",
|
||||
"S_FLICKY_07_DOWNL",
|
||||
"S_FLICKY_07_AIMR",
|
||||
"S_FLICKY_07_HOPR",
|
||||
"S_FLICKY_07_UPR",
|
||||
"S_FLICKY_07_DOWNR",
|
||||
"S_FLICKY_07_SWIM1",
|
||||
"S_FLICKY_07_SWIM2",
|
||||
"S_FLICKY_07_SWIM3",
|
||||
|
||||
// Fish
|
||||
"S_FLICKY_08_OUT",
|
||||
"S_FLICKY_08_AIM",
|
||||
"S_FLICKY_08_HOP",
|
||||
"S_FLICKY_08_FLAP1",
|
||||
"S_FLICKY_08_FLAP2",
|
||||
"S_FLICKY_08_FLAP3",
|
||||
"S_FLICKY_08_FLAP4",
|
||||
"S_FLICKY_08_SWIM1",
|
||||
"S_FLICKY_08_SWIM2",
|
||||
"S_FLICKY_08_SWIM3",
|
||||
"S_FLICKY_08_SWIM4",
|
||||
|
||||
// Ram
|
||||
"S_FLICKY_09_OUT",
|
||||
"S_FLICKY_09_AIM",
|
||||
"S_FLICKY_09_HOP",
|
||||
"S_FLICKY_09_UP",
|
||||
"S_FLICKY_09_DOWN",
|
||||
|
||||
// Puffin
|
||||
"S_FLICKY_10_OUT",
|
||||
"S_FLICKY_10_FLAP1",
|
||||
"S_FLICKY_10_FLAP2",
|
||||
|
||||
// Cow
|
||||
"S_FLICKY_11_OUT",
|
||||
"S_FLICKY_11_AIM",
|
||||
"S_FLICKY_11_RUN1",
|
||||
"S_FLICKY_11_RUN2",
|
||||
"S_FLICKY_11_RUN3",
|
||||
|
||||
// Rat
|
||||
"S_FLICKY_12_OUT",
|
||||
"S_FLICKY_12_AIM",
|
||||
"S_FLICKY_12_RUN1",
|
||||
"S_FLICKY_12_RUN2",
|
||||
"S_FLICKY_12_RUN3",
|
||||
|
||||
// Bear
|
||||
"S_FLICKY_13_OUT",
|
||||
"S_FLICKY_13_AIM",
|
||||
"S_FLICKY_13_HOP",
|
||||
"S_FLICKY_13_UP",
|
||||
"S_FLICKY_13_DOWN",
|
||||
|
||||
// Dove
|
||||
"S_FLICKY_14_OUT",
|
||||
"S_FLICKY_14_FLAP1",
|
||||
"S_FLICKY_14_FLAP2",
|
||||
"S_FLICKY_14_FLAP3",
|
||||
|
||||
// Cat
|
||||
"S_FLICKY_15_OUT",
|
||||
"S_FLICKY_15_AIM",
|
||||
"S_FLICKY_15_HOP",
|
||||
"S_FLICKY_15_UP",
|
||||
"S_FLICKY_15_DOWN",
|
||||
|
||||
// Canary
|
||||
"S_FLICKY_16_OUT",
|
||||
"S_FLICKY_16_FLAP1",
|
||||
"S_FLICKY_16_FLAP2",
|
||||
"S_FLICKY_16_FLAP3",
|
||||
|
||||
"S_YELLOWSPRING",
|
||||
"S_YELLOWSPRING2",
|
||||
|
@ -6065,6 +6271,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_NIGHTOPIANHELPER6",
|
||||
"S_NIGHTOPIANHELPER7",
|
||||
"S_NIGHTOPIANHELPER8",
|
||||
"S_NIGHTOPIANHELPER9",
|
||||
|
||||
"S_CRUMBLE1",
|
||||
"S_CRUMBLE2",
|
||||
|
@ -6088,10 +6295,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SPRK16",
|
||||
|
||||
// Robot Explosion
|
||||
"S_XPLD_FLICKY",
|
||||
"S_XPLD1",
|
||||
"S_XPLD2",
|
||||
"S_XPLD3",
|
||||
"S_XPLD4",
|
||||
"S_XPLD_EGGTRAP",
|
||||
|
||||
// Underwater Explosion
|
||||
"S_WPLD1",
|
||||
|
@ -6499,13 +6706,23 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_IVSP", // Invincibility sparkles
|
||||
"MT_SUPERSPARK", // Super Sonic Spark
|
||||
|
||||
// Freed Animals
|
||||
"MT_BIRD", // Birdie freed!
|
||||
"MT_BUNNY", // Bunny freed!
|
||||
"MT_MOUSE", // Mouse
|
||||
"MT_CHICKEN", // Chicken
|
||||
"MT_COW", // Cow
|
||||
"MT_REDBIRD", // Red Birdie in Bubble
|
||||
// Flickies
|
||||
"MT_FLICKY_01", // Bluebird
|
||||
"MT_FLICKY_02", // Rabbit
|
||||
"MT_FLICKY_03", // Chicken
|
||||
"MT_FLICKY_04", // Seal
|
||||
"MT_FLICKY_05", // Pig
|
||||
"MT_FLICKY_06", // Chipmunk
|
||||
"MT_FLICKY_07", // Penguin
|
||||
"MT_FLICKY_08", // Fish
|
||||
"MT_FLICKY_09", // Ram
|
||||
"MT_FLICKY_10", // Puffin
|
||||
"MT_FLICKY_11", // Cow
|
||||
"MT_FLICKY_12", // Rat
|
||||
"MT_FLICKY_13", // Bear
|
||||
"MT_FLICKY_14", // Dove
|
||||
"MT_FLICKY_15", // Cat
|
||||
"MT_FLICKY_16", // Canary
|
||||
|
||||
// Environmental Effects
|
||||
"MT_RAIN", // Rain
|
||||
|
@ -7517,7 +7734,7 @@ static mobjtype_t get_mobjtype(const char *word)
|
|||
if (fastcmp(word, MOBJTYPE_LIST[i]+3))
|
||||
return i;
|
||||
deh_warning("Couldn't find mobjtype named 'MT_%s'",word);
|
||||
return MT_BLUECRAWLA;
|
||||
return MT_NULL;
|
||||
}
|
||||
|
||||
static statenum_t get_state(const char *word)
|
||||
|
|
|
@ -241,6 +241,10 @@ typedef struct
|
|||
UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below
|
||||
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
|
||||
|
||||
// Freed animals stuff.
|
||||
UINT8 numFlickies; ///< Internal. For freed flicky support.
|
||||
mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
|
||||
|
||||
// NiGHTS stuff.
|
||||
UINT8 numGradedMares; ///< Internal. For grade support.
|
||||
nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
|
||||
|
|
|
@ -4722,7 +4722,7 @@ void G_BeginRecording(void)
|
|||
// Don't do it.
|
||||
WRITEFIXED(demo_p, player->jumpfactor);
|
||||
|
||||
// Save netvar data (SONICCD, etc)
|
||||
// Save netvar data
|
||||
CV_SaveNetVars(&demo_p);
|
||||
|
||||
memset(&oldcmd,0,sizeof(oldcmd));
|
||||
|
|
|
@ -370,13 +370,24 @@ light_t *t_lspr[NUMSPRITES] =
|
|||
|
||||
&lspr[NOLIGHT], // SPR_GOAL
|
||||
|
||||
// Freed Animals
|
||||
&lspr[NOLIGHT], // SPR_BIRD
|
||||
&lspr[NOLIGHT], // SPR_BUNY
|
||||
&lspr[NOLIGHT], // SPR_MOUS
|
||||
&lspr[NOLIGHT], // SPR_CHIC
|
||||
&lspr[NOLIGHT], // SPR_COWZ
|
||||
&lspr[NOLIGHT], // SPR_RBRD
|
||||
// Flickies
|
||||
&lspr[NOLIGHT], // SPR_FBUB
|
||||
&lspr[NOLIGHT], // SPR_FL01
|
||||
&lspr[NOLIGHT], // SPR_FL02
|
||||
&lspr[NOLIGHT], // SPR_FL03
|
||||
&lspr[NOLIGHT], // SPR_FL04
|
||||
&lspr[NOLIGHT], // SPR_FL05
|
||||
&lspr[NOLIGHT], // SPR_FL06
|
||||
&lspr[NOLIGHT], // SPR_FL07
|
||||
&lspr[NOLIGHT], // SPR_FL08
|
||||
&lspr[NOLIGHT], // SPR_FL09
|
||||
&lspr[NOLIGHT], // SPR_FL10
|
||||
&lspr[NOLIGHT], // SPR_FL11
|
||||
&lspr[NOLIGHT], // SPR_FL12
|
||||
&lspr[NOLIGHT], // SPR_FL13
|
||||
&lspr[NOLIGHT], // SPR_FL14
|
||||
&lspr[NOLIGHT], // SPR_FL15
|
||||
&lspr[NOLIGHT], // SPR_FL16
|
||||
|
||||
// Springs
|
||||
&lspr[NOLIGHT], // SPR_SPRY
|
||||
|
|
|
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
|
||||
if (gr_backsector)
|
||||
{
|
||||
INT32 gr_toptexture, gr_bottomtexture;
|
||||
// two sided line
|
||||
if (gr_backsector->heightsec != -1)
|
||||
{
|
||||
|
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
}
|
||||
|
||||
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
||||
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
||||
|
||||
// check TOP TEXTURE
|
||||
if ((
|
||||
#ifdef ESLOPE
|
||||
worldhighslope < worldtopslope ||
|
||||
#endif
|
||||
worldhigh < worldtop
|
||||
) && texturetranslation[gr_sidedef->toptexture])
|
||||
) && gr_toptexture)
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegtop; // top
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
|
||||
grTex = HWR_GetTexture(gr_toptexture);
|
||||
|
||||
// PEGGING
|
||||
if (gr_linedef->flags & ML_DONTPEGTOP)
|
||||
|
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
texturevpegtop += gr_sidedef->rowoffset;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS;
|
||||
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
|
||||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
||||
|
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
|
||||
if (gr_frontsector->numlights)
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
|
||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
|
||||
else
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
|
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#ifdef ESLOPE
|
||||
worldlowslope > worldbottomslope ||
|
||||
#endif
|
||||
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
|
||||
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegbottom = 0; // bottom
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
|
||||
grTex = HWR_GetTexture(gr_bottomtexture);
|
||||
|
||||
// PEGGING
|
||||
#ifdef ESLOPE
|
||||
|
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
texturevpegbottom += gr_sidedef->rowoffset;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS;
|
||||
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
|
||||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
||||
|
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
|
||||
if (gr_frontsector->numlights)
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
|
||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
|
||||
else
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
||||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||
if (gr_midtexture)
|
||||
{
|
||||
FBITFIELD blendmode;
|
||||
|
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
else
|
||||
{
|
||||
// Single sided line... Deal only with the middletexture (if one exists)
|
||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
||||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||
if (gr_midtexture)
|
||||
{
|
||||
if (drawtextured)
|
||||
|
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
newline = rover->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
|
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
newline = rover->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
#ifdef ESLOPE //backsides
|
||||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||||
|
@ -4519,8 +4523,8 @@ static void HWR_SortVisSprites(void)
|
|||
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
|
||||
gr_vissprite_t *best = NULL;
|
||||
gr_vissprite_t unsorted;
|
||||
float bestdist;
|
||||
INT32 bestdispoffset;
|
||||
float bestdist = 0.0f;
|
||||
INT32 bestdispoffset = 0;
|
||||
|
||||
if (!gr_visspritecount)
|
||||
return;
|
||||
|
|
|
@ -790,6 +790,14 @@ boolean HU_Responder(event_t *ev)
|
|||
}
|
||||
else // if chat_on
|
||||
{
|
||||
// Ignore modifier keys
|
||||
// Note that we do this here so users can still set
|
||||
// their chat keys to one of these, if they so desire.
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|
||||
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|
||||
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
|
||||
return true;
|
||||
|
||||
c = (UINT8)ev->data1;
|
||||
|
||||
// use console translations
|
||||
|
|
773
src/info.c
773
src/info.c
File diff suppressed because it is too large
Load diff
218
src/info.h
218
src/info.h
|
@ -214,6 +214,16 @@ void A_BrakFireShot();
|
|||
void A_BrakLobShot();
|
||||
void A_NapalmScatter();
|
||||
void A_SpawnFreshCopy();
|
||||
void A_FlickySpawn();
|
||||
void A_FlickyAim();
|
||||
void A_FlickyFly();
|
||||
void A_FlickySoar();
|
||||
void A_FlickyCoast();
|
||||
void A_FlickyHop();
|
||||
void A_FlickyFlounder();
|
||||
void A_FlickyCheck();
|
||||
void A_FlickyHeightCheck();
|
||||
void A_FlickyFlutter();
|
||||
|
||||
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
|
||||
#define NUMMOBJFREESLOTS 256
|
||||
|
@ -449,13 +459,24 @@ typedef enum sprite
|
|||
|
||||
SPR_GOAL, // Special Stage goal (here because lol NiGHTS)
|
||||
|
||||
// Freed Animals
|
||||
SPR_BIRD, // Birdie freed!
|
||||
SPR_BUNY, // Bunny freed!
|
||||
SPR_MOUS, // Mouse
|
||||
SPR_CHIC, // Chicken
|
||||
SPR_COWZ, // Cow
|
||||
SPR_RBRD, // Red Birdie in Bubble
|
||||
// Flickies
|
||||
SPR_FBUB, // Flicky-sized bubble
|
||||
SPR_FL01, // Bluebird
|
||||
SPR_FL02, // Rabbit
|
||||
SPR_FL03, // Chicken
|
||||
SPR_FL04, // Seal
|
||||
SPR_FL05, // Pig
|
||||
SPR_FL06, // Chipmunk
|
||||
SPR_FL07, // Penguin
|
||||
SPR_FL08, // Fish
|
||||
SPR_FL09, // Ram
|
||||
SPR_FL10, // Puffin
|
||||
SPR_FL11, // Cow
|
||||
SPR_FL12, // Rat
|
||||
SPR_FL13, // Bear
|
||||
SPR_FL14, // Dove
|
||||
SPR_FL15, // Cat
|
||||
SPR_FL16, // Canary
|
||||
|
||||
// Springs
|
||||
SPR_SPRY, // yellow spring
|
||||
|
@ -2435,43 +2456,133 @@ typedef enum state
|
|||
S_SSPK4,
|
||||
S_SSPK5,
|
||||
|
||||
// Freed Birdie
|
||||
S_BIRD1,
|
||||
S_BIRD2,
|
||||
S_BIRD3,
|
||||
// Flicky-sized bubble
|
||||
S_FLICKY_BUBBLE,
|
||||
|
||||
// Freed Bunny
|
||||
S_BUNNY1,
|
||||
S_BUNNY2,
|
||||
S_BUNNY3,
|
||||
S_BUNNY4,
|
||||
S_BUNNY5,
|
||||
S_BUNNY6,
|
||||
S_BUNNY7,
|
||||
S_BUNNY8,
|
||||
S_BUNNY9,
|
||||
S_BUNNY10,
|
||||
// Bluebird
|
||||
S_FLICKY_01_OUT,
|
||||
S_FLICKY_01_FLAP1,
|
||||
S_FLICKY_01_FLAP2,
|
||||
S_FLICKY_01_FLAP3,
|
||||
|
||||
// Freed Mouse
|
||||
S_MOUSE1,
|
||||
S_MOUSE2,
|
||||
// Rabbit
|
||||
S_FLICKY_02_OUT,
|
||||
S_FLICKY_02_AIM,
|
||||
S_FLICKY_02_HOP,
|
||||
S_FLICKY_02_UP,
|
||||
S_FLICKY_02_DOWN,
|
||||
|
||||
// Freed Chicken
|
||||
S_CHICKEN1,
|
||||
S_CHICKENHOP,
|
||||
S_CHICKENFLY1,
|
||||
S_CHICKENFLY2,
|
||||
// Chicken
|
||||
S_FLICKY_03_OUT,
|
||||
S_FLICKY_03_AIM,
|
||||
S_FLICKY_03_HOP,
|
||||
S_FLICKY_03_UP,
|
||||
S_FLICKY_03_FLAP1,
|
||||
S_FLICKY_03_FLAP2,
|
||||
|
||||
// Freed Cow
|
||||
S_COW1,
|
||||
S_COW2,
|
||||
S_COW3,
|
||||
S_COW4,
|
||||
// Seal
|
||||
S_FLICKY_04_OUT,
|
||||
S_FLICKY_04_AIM,
|
||||
S_FLICKY_04_HOP,
|
||||
S_FLICKY_04_UP,
|
||||
S_FLICKY_04_DOWN,
|
||||
S_FLICKY_04_SWIM1,
|
||||
S_FLICKY_04_SWIM2,
|
||||
S_FLICKY_04_SWIM3,
|
||||
S_FLICKY_04_SWIM4,
|
||||
|
||||
// Red Birdie in Bubble
|
||||
S_RBIRD1,
|
||||
S_RBIRD2,
|
||||
S_RBIRD3,
|
||||
// Pig
|
||||
S_FLICKY_05_OUT,
|
||||
S_FLICKY_05_AIM,
|
||||
S_FLICKY_05_HOP,
|
||||
S_FLICKY_05_UP,
|
||||
S_FLICKY_05_DOWN,
|
||||
|
||||
// Chipmunk
|
||||
S_FLICKY_06_OUT,
|
||||
S_FLICKY_06_AIM,
|
||||
S_FLICKY_06_HOP,
|
||||
S_FLICKY_06_UP,
|
||||
S_FLICKY_06_DOWN,
|
||||
|
||||
// Penguin
|
||||
S_FLICKY_07_OUT,
|
||||
S_FLICKY_07_AIML,
|
||||
S_FLICKY_07_HOPL,
|
||||
S_FLICKY_07_UPL,
|
||||
S_FLICKY_07_DOWNL,
|
||||
S_FLICKY_07_AIMR,
|
||||
S_FLICKY_07_HOPR,
|
||||
S_FLICKY_07_UPR,
|
||||
S_FLICKY_07_DOWNR,
|
||||
S_FLICKY_07_SWIM1,
|
||||
S_FLICKY_07_SWIM2,
|
||||
S_FLICKY_07_SWIM3,
|
||||
|
||||
// Fish
|
||||
S_FLICKY_08_OUT,
|
||||
S_FLICKY_08_AIM,
|
||||
S_FLICKY_08_HOP,
|
||||
S_FLICKY_08_FLAP1,
|
||||
S_FLICKY_08_FLAP2,
|
||||
S_FLICKY_08_FLAP3,
|
||||
S_FLICKY_08_FLAP4,
|
||||
S_FLICKY_08_SWIM1,
|
||||
S_FLICKY_08_SWIM2,
|
||||
S_FLICKY_08_SWIM3,
|
||||
S_FLICKY_08_SWIM4,
|
||||
|
||||
// Ram
|
||||
S_FLICKY_09_OUT,
|
||||
S_FLICKY_09_AIM,
|
||||
S_FLICKY_09_HOP,
|
||||
S_FLICKY_09_UP,
|
||||
S_FLICKY_09_DOWN,
|
||||
|
||||
// Puffin
|
||||
S_FLICKY_10_OUT,
|
||||
S_FLICKY_10_FLAP1,
|
||||
S_FLICKY_10_FLAP2,
|
||||
|
||||
// Cow
|
||||
S_FLICKY_11_OUT,
|
||||
S_FLICKY_11_AIM,
|
||||
S_FLICKY_11_RUN1,
|
||||
S_FLICKY_11_RUN2,
|
||||
S_FLICKY_11_RUN3,
|
||||
|
||||
// Rat
|
||||
S_FLICKY_12_OUT,
|
||||
S_FLICKY_12_AIM,
|
||||
S_FLICKY_12_RUN1,
|
||||
S_FLICKY_12_RUN2,
|
||||
S_FLICKY_12_RUN3,
|
||||
|
||||
// Bear
|
||||
S_FLICKY_13_OUT,
|
||||
S_FLICKY_13_AIM,
|
||||
S_FLICKY_13_HOP,
|
||||
S_FLICKY_13_UP,
|
||||
S_FLICKY_13_DOWN,
|
||||
|
||||
// Dove
|
||||
S_FLICKY_14_OUT,
|
||||
S_FLICKY_14_FLAP1,
|
||||
S_FLICKY_14_FLAP2,
|
||||
S_FLICKY_14_FLAP3,
|
||||
|
||||
// Cat
|
||||
S_FLICKY_15_OUT,
|
||||
S_FLICKY_15_AIM,
|
||||
S_FLICKY_15_HOP,
|
||||
S_FLICKY_15_UP,
|
||||
S_FLICKY_15_DOWN,
|
||||
|
||||
// Canary
|
||||
S_FLICKY_16_OUT,
|
||||
S_FLICKY_16_FLAP1,
|
||||
S_FLICKY_16_FLAP2,
|
||||
S_FLICKY_16_FLAP3,
|
||||
|
||||
S_YELLOWSPRING,
|
||||
S_YELLOWSPRING2,
|
||||
|
@ -2971,6 +3082,7 @@ typedef enum state
|
|||
S_NIGHTOPIANHELPER6,
|
||||
S_NIGHTOPIANHELPER7,
|
||||
S_NIGHTOPIANHELPER8,
|
||||
S_NIGHTOPIANHELPER9,
|
||||
|
||||
S_CRUMBLE1,
|
||||
S_CRUMBLE2,
|
||||
|
@ -2994,10 +3106,10 @@ typedef enum state
|
|||
S_SPRK16,
|
||||
|
||||
// Robot Explosion
|
||||
S_XPLD_FLICKY,
|
||||
S_XPLD1,
|
||||
S_XPLD2,
|
||||
S_XPLD3,
|
||||
S_XPLD4,
|
||||
S_XPLD_EGGTRAP,
|
||||
|
||||
// Underwater Explosion
|
||||
S_WPLD1,
|
||||
|
@ -3424,13 +3536,23 @@ typedef enum mobj_type
|
|||
MT_IVSP, // Invincibility sparkles
|
||||
MT_SUPERSPARK, // Super Sonic Spark
|
||||
|
||||
// Freed Animals
|
||||
MT_BIRD, // Birdie freed!
|
||||
MT_BUNNY, // Bunny freed!
|
||||
MT_MOUSE, // Mouse
|
||||
MT_CHICKEN, // Chicken
|
||||
MT_COW, // Cow
|
||||
MT_REDBIRD, // Red Birdie in Bubble
|
||||
// Flickies
|
||||
MT_FLICKY_01, // Bluebird
|
||||
MT_FLICKY_02, // Rabbit
|
||||
MT_FLICKY_03, // Chicken
|
||||
MT_FLICKY_04, // Seal
|
||||
MT_FLICKY_05, // Pig
|
||||
MT_FLICKY_06, // Chipmunk
|
||||
MT_FLICKY_07, // Penguin
|
||||
MT_FLICKY_08, // Fish
|
||||
MT_FLICKY_09, // Ram
|
||||
MT_FLICKY_10, // Puffin
|
||||
MT_FLICKY_11, // Cow
|
||||
MT_FLICKY_12, // Rat
|
||||
MT_FLICKY_13, // Bear
|
||||
MT_FLICKY_14, // Dove
|
||||
MT_FLICKY_15, // Cat
|
||||
MT_FLICKY_16, // Canary
|
||||
|
||||
// Environmental Effects
|
||||
MT_RAIN, // Rain
|
||||
|
|
|
@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
|
|||
case sector_ceilingheight:
|
||||
lua_pushfixed(L, sector->ceilingheight);
|
||||
return 1;
|
||||
case sector_floorpic: { // floorpic
|
||||
levelflat_t *levelflat;
|
||||
INT16 i;
|
||||
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
|
||||
;
|
||||
lua_pushlstring(L, levelflat->name, 8);
|
||||
case sector_floorpic: // floorpic
|
||||
lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
|
||||
return 1;
|
||||
}
|
||||
case sector_ceilingpic: { // ceilingpic
|
||||
levelflat_t *levelflat;
|
||||
INT16 i;
|
||||
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
|
||||
;
|
||||
lua_pushlstring(L, levelflat->name, 8);
|
||||
case sector_ceilingpic: // ceilingpic
|
||||
lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
|
||||
return 1;
|
||||
}
|
||||
case sector_lightlevel:
|
||||
lua_pushinteger(L, sector->lightlevel);
|
||||
return 1;
|
||||
|
@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// help function for P_LoadSectors, find a flat in the active wad files,
|
||||
// allocate an id for it, and set the levelflat (to speedup search)
|
||||
//
|
||||
static INT32 P_AddLevelFlatRuntime(const char *flatname)
|
||||
{
|
||||
size_t i;
|
||||
levelflat_t *levelflat = levelflats;
|
||||
|
||||
//
|
||||
// first scan through the already found flats
|
||||
//
|
||||
for (i = 0; i < numlevelflats; i++, levelflat++)
|
||||
if (strnicmp(levelflat->name,flatname,8)==0)
|
||||
break;
|
||||
|
||||
// that flat was already found in the level, return the id
|
||||
if (i == numlevelflats)
|
||||
{
|
||||
// allocate new flat memory
|
||||
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
|
||||
levelflat = levelflats+i;
|
||||
|
||||
// store the name
|
||||
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
|
||||
strupr(levelflat->name);
|
||||
|
||||
// store the flat lump number
|
||||
levelflat->lumpnum = R_GetFlatNumForName(flatname);
|
||||
|
||||
#ifndef ZDEBUG
|
||||
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
|
||||
#endif
|
||||
|
||||
numlevelflats++;
|
||||
}
|
||||
|
||||
// level flat id
|
||||
return (INT32)i;
|
||||
}
|
||||
|
||||
static int sector_set(lua_State *L)
|
||||
{
|
||||
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
||||
|
|
|
@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
|
|||
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -46,41 +46,6 @@ typedef INT32 fixed_t;
|
|||
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
|
||||
|
||||
|
||||
/** \brief The TMulScale16 function
|
||||
|
||||
\param a a parameter of type fixed_t
|
||||
\param b a parameter of type fixed_t
|
||||
\param c a parameter of type fixed_t
|
||||
\param d a parameter of type fixed_t
|
||||
\param e a parameter of type fixed_t
|
||||
\param f a parameter of type fixed_t
|
||||
|
||||
\return fixed_t
|
||||
|
||||
|
||||
*/
|
||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
|
||||
{ \
|
||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
|
||||
+ ((INT64)e * (INT64)f)) >> 16); \
|
||||
}
|
||||
|
||||
/** \brief The DMulScale16 function
|
||||
|
||||
\param a a parameter of type fixed_t
|
||||
\param b a parameter of type fixed_t
|
||||
\param c a parameter of type fixed_t
|
||||
\param d a parameter of type fixed_t
|
||||
|
||||
\return fixed_t
|
||||
|
||||
|
||||
*/
|
||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
|
||||
{ \
|
||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
|
||||
}
|
||||
|
||||
#if defined (__WATCOMC__) && FRACBITS == 16
|
||||
#pragma aux FixedMul = \
|
||||
"imul ebx", \
|
||||
|
@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x != INT32_MIN)
|
||||
return x-f; // return largest integral value not greater than argument
|
||||
{ // return rounded down to nearest whole number
|
||||
if (x > 0)
|
||||
return x-f;
|
||||
else
|
||||
return x-(FRACUNIT-f);
|
||||
}
|
||||
return INT32_MIN;
|
||||
}
|
||||
|
||||
|
@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (x != INT32_MIN)
|
||||
{ // return rounded to nearest whole number, towards zero
|
||||
if (x > 0)
|
||||
|
@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x == INT32_MIN)
|
||||
return INT32_MIN;
|
||||
else if (x < FixedFloor(INT32_MAX))
|
||||
return x+(FRACUNIT-f); // return smallest integral value not less than argument
|
||||
{ // return rounded up to nearest whole number
|
||||
if (x > 0)
|
||||
return x+(FRACUNIT-f);
|
||||
else
|
||||
return x+f;
|
||||
}
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
|
@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x == INT32_MIN)
|
||||
return INT32_MIN;
|
||||
else if (x < FixedFloor(INT32_MAX))
|
||||
|
|
401
src/p_enemy.c
401
src/p_enemy.c
|
@ -242,6 +242,16 @@ void A_BrakFireShot(mobj_t *actor);
|
|||
void A_BrakLobShot(mobj_t *actor);
|
||||
void A_NapalmScatter(mobj_t *actor);
|
||||
void A_SpawnFreshCopy(mobj_t *actor);
|
||||
void A_FlickySpawn(mobj_t *actor);
|
||||
void A_FlickyAim(mobj_t *actor);
|
||||
void A_FlickyFly(mobj_t *actor);
|
||||
void A_FlickySoar(mobj_t *actor);
|
||||
void A_FlickyCoast(mobj_t *actor);
|
||||
void A_FlickyHop(mobj_t *actor);
|
||||
void A_FlickyFlounder(mobj_t *actor);
|
||||
void A_FlickyCheck(mobj_t *actor);
|
||||
void A_FlickyHeightCheck(mobj_t *actor);
|
||||
void A_FlickyFlutter(mobj_t *actor);
|
||||
|
||||
//
|
||||
// ENEMY THINKING
|
||||
|
@ -7831,7 +7841,7 @@ void A_SetObjectFlags(mobj_t *actor)
|
|||
else if (locvar2 == 1)
|
||||
locvar1 = actor->flags & ~locvar1;
|
||||
|
||||
if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
||||
if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
||||
unlinkthings = true;
|
||||
|
||||
if (unlinkthings) {
|
||||
|
@ -10339,3 +10349,392 @@ void A_SpawnFreshCopy(mobj_t *actor)
|
|||
if (newObject->info->seesound)
|
||||
S_StartSound(newObject, newObject->info->seesound);
|
||||
}
|
||||
|
||||
// Internal Flicky spawning function.
|
||||
mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers)
|
||||
{
|
||||
mobj_t *flicky;
|
||||
|
||||
if (!flickytype)
|
||||
{
|
||||
if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service.
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies);
|
||||
flickytype = mapheaderinfo[gamemap-1]->flickies[prandom];
|
||||
}
|
||||
}
|
||||
|
||||
flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype);
|
||||
flicky->angle = actor->angle;
|
||||
|
||||
if (flickytype == MT_SEED)
|
||||
flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2;
|
||||
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
|
||||
|
||||
P_SetObjectMomZ(flicky, momz, false);
|
||||
flicky->movedir = (P_RandomChance(FRACUNIT/2) ? -1 : 1);
|
||||
flicky->fuse = P_RandomRange(595, 700); // originally 300, 350
|
||||
flicky->threshold = 0;
|
||||
|
||||
if (lookforplayers)
|
||||
P_LookForPlayers(flicky, true, false, 0);
|
||||
|
||||
return flicky;
|
||||
}
|
||||
|
||||
// Function: A_FlickySpawn
|
||||
//
|
||||
// Description: Flicky spawning function.
|
||||
//
|
||||
// var1:
|
||||
// lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
|
||||
// upper 16 bits: if 0, no sound is played. Else, A_Scream is called.
|
||||
// var2 = upwards thrust for spawned flicky. If zero, default value is provided.
|
||||
//
|
||||
void A_FlickySpawn(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickySpawn", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (locvar1 >> 16) {
|
||||
A_Scream(actor); // A shortcut for the truly lazy.
|
||||
locvar1 &= 65535;
|
||||
}
|
||||
|
||||
P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true);
|
||||
}
|
||||
|
||||
// Internal Flicky bubbling function.
|
||||
void P_InternalFlickyBubble(mobj_t *actor)
|
||||
{
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
mobj_t *overlay;
|
||||
|
||||
if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer)
|
||||
return;
|
||||
|
||||
overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
|
||||
P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate);
|
||||
P_SetTarget(&actor->tracer, overlay);
|
||||
P_SetTarget(&overlay->target, actor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actor->tracer || P_MobjWasRemoved(actor->tracer))
|
||||
return;
|
||||
|
||||
P_RemoveMobj(actor->tracer);
|
||||
P_SetTarget(&actor->tracer, NULL);
|
||||
}
|
||||
|
||||
// Function: A_FlickyAim
|
||||
//
|
||||
// Description: Flicky aiming function.
|
||||
//
|
||||
// var1 = how far around the target (in angle constants) the flicky should look
|
||||
// var2 = distance from target to aim for
|
||||
//
|
||||
void A_FlickyAim(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
boolean flickyhitwall = false;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyAim", actor))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (actor->momx == actor->momy && actor->momy == 0)
|
||||
flickyhitwall = true;
|
||||
|
||||
P_InternalFlickyBubble(actor);
|
||||
P_InstaThrust(actor, 0, 0);
|
||||
|
||||
if (!actor->target)
|
||||
{
|
||||
P_LookForPlayers(actor, true, false, 0);
|
||||
actor->angle = P_RandomKey(36)*ANG10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (actor->fuse > 2*TICRATE)
|
||||
{
|
||||
angle_t posvar;
|
||||
fixed_t chasevar, chasex, chasey;
|
||||
|
||||
if (flickyhitwall)
|
||||
actor->movedir *= -1;
|
||||
|
||||
posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK;
|
||||
chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2;
|
||||
|
||||
chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar);
|
||||
chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar);
|
||||
|
||||
if (P_AproxDistance(chasex - actor->x, chasey - actor->y))
|
||||
actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey);
|
||||
}
|
||||
else if (flickyhitwall)
|
||||
{
|
||||
actor->angle += ANGLE_180;
|
||||
actor->threshold = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Internal Flicky flying function. Also usuable as an underwater swim thrust.
|
||||
void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez)
|
||||
{
|
||||
angle_t vertangle;
|
||||
|
||||
flyspeed = FixedMul(flyspeed, actor->scale);
|
||||
actor->flags |= MF_NOGRAVITY;
|
||||
|
||||
var1 = ANG30;
|
||||
var2 = 32*FRACUNIT;
|
||||
A_FlickyAim(actor);
|
||||
|
||||
chasez *= 8;
|
||||
if (!actor->target || !(actor->fuse > 2*TICRATE))
|
||||
chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT);
|
||||
else
|
||||
{
|
||||
fixed_t add = actor->target->z + (actor->target->height - actor->height)/2;
|
||||
if (add > (actor->ceilingz - 24*actor->scale - actor->height))
|
||||
add = actor->ceilingz - 24*actor->scale - actor->height;
|
||||
else if (add < (actor->floorz + 24*actor->scale))
|
||||
add = actor->floorz + 24*actor->scale;
|
||||
chasez += add;
|
||||
}
|
||||
|
||||
if (!targetdist)
|
||||
targetdist = 16*FRACUNIT; //Default!
|
||||
|
||||
if (actor->target && abs(chasez - actor->z) > targetdist)
|
||||
targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
|
||||
|
||||
vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK;
|
||||
P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed));
|
||||
actor->momz = FixedMul(FINESINE(vertangle), flyspeed);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFly
|
||||
//
|
||||
// Description: Flicky flying function.
|
||||
//
|
||||
// var1 = how fast to fly
|
||||
// var2 = how far ahead the target should be considered
|
||||
//
|
||||
void A_FlickyFly(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFly", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyFly(actor, var1, var2,
|
||||
FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK)
|
||||
);
|
||||
}
|
||||
|
||||
// Function: A_FlickySoar
|
||||
//
|
||||
// Description: Flicky soaring function - specific to puffin.
|
||||
//
|
||||
// var1 = how fast to fly
|
||||
// var2 = how far ahead the target should be considered
|
||||
//
|
||||
void A_FlickySoar(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickySoar", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyFly(actor, var1, var2,
|
||||
2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK)))
|
||||
);
|
||||
|
||||
if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10)
|
||||
actor->frame = 3;
|
||||
}
|
||||
|
||||
//Function: A_FlickyCoast
|
||||
//
|
||||
// Description: Flicky swim-coasting function.
|
||||
//
|
||||
// var1 = speed to change state upon reaching
|
||||
// var2 = state to change to upon slowing down
|
||||
// the spawnstate of the mobj = state to change to when above water
|
||||
//
|
||||
void A_FlickyCoast(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyCoast", actor))
|
||||
return;
|
||||
#endif
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
actor->momx = (11*actor->momx)/12;
|
||||
actor->momy = (11*actor->momy)/12;
|
||||
actor->momz = (11*actor->momz)/12;
|
||||
|
||||
if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
actor->flags &= ~MF_NOGRAVITY;
|
||||
P_SetMobjState(actor, mobjinfo[actor->type].spawnstate);
|
||||
}
|
||||
|
||||
// Internal Flicky hopping function.
|
||||
void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle)
|
||||
{
|
||||
if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
|
||||
|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
|
||||
{
|
||||
if (momz)
|
||||
{
|
||||
if (actor->eflags & MFE_UNDERWATER)
|
||||
momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
|
||||
P_SetObjectMomZ(actor, momz, false);
|
||||
}
|
||||
P_InstaThrust(actor, angle, FixedMul(momh, actor->scale));
|
||||
}
|
||||
}
|
||||
|
||||
// Function: A_FlickyHop
|
||||
//
|
||||
// Description: Flicky hopping function.
|
||||
//
|
||||
// var1 = vertical thrust
|
||||
// var2 = horizontal thrust
|
||||
//
|
||||
void A_FlickyHop(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyHop instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyHop", actor))
|
||||
return;
|
||||
#endif
|
||||
P_InternalFlickyHop(actor, var1, var2, actor->angle);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFlounder
|
||||
//
|
||||
// Description: Flicky floundering function.
|
||||
//
|
||||
// var1 = intended vertical thrust
|
||||
// var2 = intended horizontal thrust
|
||||
//
|
||||
void A_FlickyFlounder(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
angle_t hopangle;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFlounder", actor))
|
||||
return;
|
||||
#endif
|
||||
locvar1 *= (P_RandomKey(2) + 1);
|
||||
locvar2 *= (P_RandomKey(2) + 1);
|
||||
hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2);
|
||||
P_InternalFlickyHop(actor, locvar1, locvar2, hopangle);
|
||||
}
|
||||
|
||||
// Function: A_FlickyCheck
|
||||
//
|
||||
// Description: Flicky airtime check function.
|
||||
//
|
||||
// var1 = state to change to upon touching the floor
|
||||
// var2 = state to change to upon falling
|
||||
// the meleestate of the mobj = state to change to when underwater
|
||||
//
|
||||
void A_FlickyCheck(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyCheck", actor))
|
||||
return;
|
||||
#endif
|
||||
if (locvar2 && P_MobjFlip(actor)*actor->momz < 1)
|
||||
P_SetMobjState(actor, locvar2);
|
||||
else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
|
||||
|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
|
||||
P_SetMobjState(actor, locvar1);
|
||||
else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER))
|
||||
P_SetMobjState(actor, mobjinfo[actor->type].meleestate);
|
||||
P_InternalFlickyBubble(actor);
|
||||
}
|
||||
|
||||
// Function: A_FlickyHeightCheck
|
||||
//
|
||||
// Description: Flicky height check function.
|
||||
//
|
||||
// var1 = state to change to when falling below height relative to target
|
||||
// var2 = height relative to target to change state at
|
||||
//
|
||||
void A_FlickyHeightCheck(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyHeightCheck", actor))
|
||||
return;
|
||||
#endif
|
||||
if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1
|
||||
&& ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2)
|
||||
|| (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz)))
|
||||
P_SetMobjState(actor, locvar1);
|
||||
P_InternalFlickyBubble(actor);
|
||||
}
|
||||
|
||||
// Function: A_FlickyFlutter
|
||||
//
|
||||
// Description: Flicky fluttering function - specific to chicken.
|
||||
//
|
||||
// var1 = state to change to upon touching the floor
|
||||
// var2 = state to change to upon falling
|
||||
// the meleestate of the mobj = state to change to when underwater
|
||||
//
|
||||
void A_FlickyFlutter(mobj_t *actor)
|
||||
{
|
||||
// We're not setting up locvars here - it passes var1 and var2 through to A_FlickyCheck instead.
|
||||
//INT32 locvar1 = var1;
|
||||
//INT32 locvar2 = var2;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_FlickyFlutter", actor))
|
||||
return;
|
||||
#endif
|
||||
A_FlickyCheck(actor);
|
||||
|
||||
var1 = ANG30;
|
||||
var2 = 32*FRACUNIT;
|
||||
A_FlickyAim(actor);
|
||||
|
||||
P_InstaThrust(actor, actor->angle, 2*actor->scale);
|
||||
if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2)
|
||||
actor->momz = -P_MobjFlip(actor)*actor->scale/2;
|
||||
}
|
||||
|
||||
#undef FLICKYHITWALL
|
||||
|
|
108
src/p_inter.c
108
src/p_inter.c
|
@ -2052,7 +2052,6 @@ boolean P_CheckRacers(void)
|
|||
*/
|
||||
void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
|
||||
{
|
||||
mobjtype_t item;
|
||||
mobj_t *mo;
|
||||
|
||||
if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL))
|
||||
|
@ -2268,81 +2267,80 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
if (source && target && target->player && source->player)
|
||||
P_PlayVictorySound(source); // Killer laughs at you. LAUGHS! BWAHAHAHA!
|
||||
|
||||
#ifdef OLDANIMALSPAWNING
|
||||
// Drop stuff.
|
||||
// This determines the kind of object spawned
|
||||
// during the death frame of a thing.
|
||||
if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001
|
||||
&& target->flags & MF_ENEMY)
|
||||
{
|
||||
if (cv_soniccd.value)
|
||||
item = MT_SEED;
|
||||
else
|
||||
mobjtype_t item;
|
||||
INT32 prandom;
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
INT32 prandom;
|
||||
case MT_REDCRAWLA:
|
||||
case MT_GOLDBUZZ:
|
||||
case MT_SKIM:
|
||||
case MT_UNIDUS:
|
||||
item = MT_FLICKY_02/*MT_BUNNY*/;
|
||||
break;
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_REDCRAWLA:
|
||||
case MT_GOLDBUZZ:
|
||||
case MT_SKIM:
|
||||
case MT_UNIDUS:
|
||||
item = MT_BUNNY;
|
||||
break;
|
||||
case MT_BLUECRAWLA:
|
||||
case MT_JETTBOMBER:
|
||||
case MT_GFZFISH:
|
||||
item = MT_FLICKY_01/*MT_BIRD*/;
|
||||
break;
|
||||
|
||||
case MT_BLUECRAWLA:
|
||||
case MT_JETTBOMBER:
|
||||
case MT_GFZFISH:
|
||||
item = MT_BIRD;
|
||||
break;
|
||||
case MT_JETTGUNNER:
|
||||
case MT_CRAWLACOMMANDER:
|
||||
case MT_REDBUZZ:
|
||||
case MT_DETON:
|
||||
item = MT_FLICKY_12/*MT_MOUSE*/;
|
||||
break;
|
||||
|
||||
case MT_JETTGUNNER:
|
||||
case MT_CRAWLACOMMANDER:
|
||||
case MT_REDBUZZ:
|
||||
case MT_DETON:
|
||||
item = MT_MOUSE;
|
||||
break;
|
||||
case MT_GSNAPPER:
|
||||
case MT_EGGGUARD:
|
||||
case MT_SPRINGSHELL:
|
||||
item = MT_FLICKY_11/*MT_COW*/;
|
||||
break;
|
||||
|
||||
case MT_GSNAPPER:
|
||||
case MT_EGGGUARD:
|
||||
case MT_SPRINGSHELL:
|
||||
item = MT_COW;
|
||||
break;
|
||||
case MT_MINUS:
|
||||
case MT_VULTURE:
|
||||
case MT_POINTY:
|
||||
case MT_YELLOWSHELL:
|
||||
item = MT_FLICKY_03/*MT_CHICKEN*/;
|
||||
break;
|
||||
|
||||
case MT_MINUS:
|
||||
case MT_VULTURE:
|
||||
case MT_POINTY:
|
||||
case MT_YELLOWSHELL:
|
||||
item = MT_CHICKEN;
|
||||
break;
|
||||
case MT_AQUABUZZ:
|
||||
item = MT_FLICKY_01/*MT_REDBIRD*/;
|
||||
break;
|
||||
|
||||
case MT_AQUABUZZ:
|
||||
item = MT_REDBIRD;
|
||||
break;
|
||||
default:
|
||||
if (target->info->doomednum)
|
||||
prandom = target->info->doomednum%5; // "Random" animal for new enemies.
|
||||
else
|
||||
prandom = P_RandomKey(5); // No placable object, just use a random number.
|
||||
|
||||
default:
|
||||
if (target->info->doomednum)
|
||||
prandom = target->info->doomednum%5; // "Random" animal for new enemies.
|
||||
else
|
||||
prandom = P_RandomKey(5); // No placable object, just use a random number.
|
||||
|
||||
switch(prandom)
|
||||
{
|
||||
default: item = MT_BUNNY; break;
|
||||
case 1: item = MT_BIRD; break;
|
||||
case 2: item = MT_MOUSE; break;
|
||||
case 3: item = MT_COW; break;
|
||||
case 4: item = MT_CHICKEN; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch(prandom)
|
||||
{
|
||||
default: item = MT_FLICKY_02/*MT_BUNNY*/; break;
|
||||
case 1: item = MT_FLICKY_01/*MT_BIRD*/; break;
|
||||
case 2: item = MT_FLICKY_12/*MT_MOUSE*/; break;
|
||||
case 3: item = MT_FLICKY_11/*MT_COW*/; break;
|
||||
case 4: item = MT_FLICKY_03/*MT_CHICKEN*/; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mo = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2) - FixedMul(mobjinfo[item].height / 2, target->scale), item);
|
||||
mo->destscale = target->scale;
|
||||
P_SetScale(mo, mo->destscale);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// Other death animation effects
|
||||
else switch(target->type)
|
||||
switch(target->type)
|
||||
{
|
||||
case MT_BOUNCEPICKUP:
|
||||
case MT_RAILPICKUP:
|
||||
|
|
|
@ -296,6 +296,11 @@ boolean P_CheckMissileRange(mobj_t *actor);
|
|||
void P_NewChaseDir(mobj_t *actor);
|
||||
boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist);
|
||||
|
||||
mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers);
|
||||
void P_InternalFlickyBubble(mobj_t *actor);
|
||||
void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez);
|
||||
void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle);
|
||||
|
||||
//
|
||||
// P_MAP
|
||||
//
|
||||
|
|
|
@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
|||
side_t *side = &sides[linedef->sidenum[0]];
|
||||
fixed_t textop, texbottom, texheight;
|
||||
fixed_t texmid, delta1, delta2;
|
||||
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
|
||||
|
||||
// Get the midtexture's height
|
||||
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
|
||||
if (texnum) {
|
||||
// Get the midtexture's height
|
||||
texheight = textures[texnum]->height << FRACBITS;
|
||||
|
||||
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
||||
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
||||
#if 0 // #ifdef POLYOBJECTS
|
||||
// don't remove this code unless solid midtextures
|
||||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
// don't remove this code unless solid midtextures
|
||||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
{
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
|
||||
delta1 = abs(mobj->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
delta1 = abs(mobj->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
78
src/p_mobj.c
78
src/p_mobj.c
|
@ -3519,17 +3519,14 @@ static boolean P_SceneryZMovement(mobj_t *mo)
|
|||
if ((!(mo->eflags & MFE_VERTICALFLIP) && mo->z <= mo->floorz)
|
||||
|| (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height >= mo->ceilingz))
|
||||
{
|
||||
// DO NOT use random numbers here.
|
||||
// SonicCD mode is console togglable and
|
||||
// affects demos.
|
||||
UINT8 rltime = (leveltime & 4);
|
||||
|
||||
if (!rltime)
|
||||
P_SpawnMobj(mo->x, mo->y, mo->floorz, MT_GFZFLOWER3);
|
||||
else if (rltime == 2)
|
||||
P_SpawnMobj(mo->x, mo->y, mo->floorz, MT_GFZFLOWER2);
|
||||
else
|
||||
P_SpawnMobj(mo->x, mo->y, mo->floorz, MT_GFZFLOWER1);
|
||||
mobjtype_t flowertype = ((P_RandomChance(FRACUNIT/2)) ? MT_GFZFLOWER1 : MT_GFZFLOWER3);
|
||||
mobj_t *flower = P_SpawnMobjFromMobj(mo, 0, 0, 0, flowertype);
|
||||
if (flower)
|
||||
{
|
||||
P_SetScale(flower, mo->scale/16);
|
||||
flower->destscale = mo->scale;
|
||||
flower->scalespeed = mo->scale/8;
|
||||
}
|
||||
|
||||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
|
@ -4980,7 +4977,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
|||
{
|
||||
INT32 s;
|
||||
mobj_t *base = mobj, *seg;
|
||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
||||
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||
while ((base = base->tracer))
|
||||
{
|
||||
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
|
||||
|
@ -4994,7 +4991,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
|||
{
|
||||
INT32 s;
|
||||
mobj_t *base = mobj, *seg;
|
||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
||||
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||
while ((base = base->tracer))
|
||||
{
|
||||
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
|
||||
|
@ -5110,7 +5107,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
INT32 i, arm;
|
||||
mobj_t *seg, *base = mobj;
|
||||
// First frame init, spawn all the things.
|
||||
mobj->spawnpoint->z = mobj->z>>FRACBITS;
|
||||
mobj->watertop = mobj->z;
|
||||
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
|
||||
for (arm = 0; arm <3 ; arm++)
|
||||
{
|
||||
|
@ -5166,7 +5163,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
case 3:
|
||||
{
|
||||
fixed_t z;
|
||||
if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS)
|
||||
if (mobj->z < mobj->watertop+(512<<FRACBITS))
|
||||
mobj->momz = 8*FRACUNIT;
|
||||
else
|
||||
{
|
||||
|
@ -5175,7 +5172,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
}
|
||||
mobj->movecount += 400<<(FRACBITS>>1);
|
||||
mobj->movecount %= 360*FRACUNIT;
|
||||
z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
||||
z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
||||
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
|
||||
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
|
||||
else
|
||||
|
@ -5185,13 +5182,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
// Pinch phase!
|
||||
case 4:
|
||||
{
|
||||
if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS)
|
||||
if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
|
||||
mobj->momz = 8*FRACUNIT;
|
||||
else
|
||||
mobj->momz = 0;
|
||||
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
|
||||
mobj->movecount %= 360*FRACUNIT;
|
||||
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
||||
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
||||
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
P_SupermanLook4Players(mobj);
|
||||
|
@ -7096,7 +7093,8 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
case MT_SEED:
|
||||
mobj->momz = mobj->info->speed;
|
||||
if (P_MobjFlip(mobj)*mobj->momz < mobj->info->speed)
|
||||
mobj->momz = P_MobjFlip(mobj)*mobj->info->speed;
|
||||
break;
|
||||
case MT_ROCKCRUMBLE1:
|
||||
case MT_ROCKCRUMBLE2:
|
||||
|
@ -7245,14 +7243,14 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7)
|
||||
&& (mobj->fuse & 3))
|
||||
{
|
||||
INT32 i,j;
|
||||
INT32 i;
|
||||
fixed_t x,y,z;
|
||||
fixed_t ns;
|
||||
mobj_t *mo2;
|
||||
mobj_t *flicky;
|
||||
|
||||
i = P_RandomByte();
|
||||
z = mobj->subsector->sector->floorheight + ((P_RandomByte()&63)*FRACUNIT);
|
||||
for (j = 0; j < 2; j++)
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
const angle_t fa = (P_RandomByte()*FINEANGLES/16) & FINEMASK;
|
||||
ns = 64 * FRACUNIT;
|
||||
|
@ -7260,25 +7258,22 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
y = mobj->y + FixedMul(FINECOSINE(fa),ns);
|
||||
|
||||
mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE);
|
||||
P_SetMobjStateNF(mo2, S_XPLD_EGGTRAP); // so the flickies don't lose their target if they spawn
|
||||
ns = 4 * FRACUNIT;
|
||||
mo2->momx = FixedMul(FINESINE(fa),ns);
|
||||
mo2->momy = FixedMul(FINECOSINE(fa),ns);
|
||||
mo2->angle = fa << ANGLETOFINESHIFT;
|
||||
|
||||
i = P_RandomByte();
|
||||
|
||||
if (i % 5 == 0)
|
||||
P_SpawnMobj(x, y, z, MT_CHICKEN);
|
||||
else if (i % 4 == 0)
|
||||
P_SpawnMobj(x, y, z, MT_COW);
|
||||
else if (i % 3 == 0)
|
||||
{
|
||||
P_SpawnMobj(x, y, z, MT_BIRD);
|
||||
if (P_RandomChance(FRACUNIT/4)) // I filled a spreadsheet trying to get the equivalent chance to the original P_RandomByte hack!
|
||||
S_StartSound(mo2, mobj->info->deathsound);
|
||||
}
|
||||
else if ((i & 1) == 0)
|
||||
P_SpawnMobj(x, y, z, MT_BUNNY);
|
||||
else
|
||||
P_SpawnMobj(x, y, z, MT_MOUSE);
|
||||
|
||||
flicky = P_InternalFlickySpawn(mo2, 0, 8*FRACUNIT, false);
|
||||
if (!flicky)
|
||||
break;
|
||||
|
||||
P_SetTarget(&flicky->target, mo2);
|
||||
flicky->momx = mo2->momx;
|
||||
flicky->momy = mo2->momy;
|
||||
}
|
||||
|
||||
mobj->fuse--;
|
||||
|
@ -7339,6 +7334,8 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
case MT_AQUABUZZ:
|
||||
P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn
|
||||
// no break here on purpose
|
||||
case MT_BIGAIRMINE:
|
||||
{
|
||||
if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0
|
||||
|
@ -8449,13 +8446,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
// Special condition for the 2nd boss.
|
||||
mobj->watertop = mobj->info->speed;
|
||||
break;
|
||||
case MT_BIRD:
|
||||
case MT_BUNNY:
|
||||
case MT_MOUSE:
|
||||
case MT_CHICKEN:
|
||||
case MT_COW:
|
||||
case MT_REDBIRD:
|
||||
mobj->fuse = P_RandomRange(300, 350);
|
||||
case MT_FLICKY_08:
|
||||
mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA);
|
||||
break;
|
||||
case MT_REDRING: // Make MT_REDRING red by default
|
||||
mobj->color = skincolor_redring;
|
||||
|
|
|
@ -470,6 +470,7 @@ static void P_NetUnArchivePlayers(void)
|
|||
#define SD_TAG 0x10
|
||||
#define SD_FLOORANG 0x20
|
||||
#define SD_CEILANG 0x40
|
||||
#define SD_TAGLIST 0x80
|
||||
|
||||
#define LD_FLAG 0x01
|
||||
#define LD_SPECIAL 0x02
|
||||
|
@ -519,10 +520,9 @@ static void P_NetArchiveWorld(void)
|
|||
//
|
||||
// flats
|
||||
//
|
||||
// P_AddLevelFlat should not add but just return the number
|
||||
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
|
||||
if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
|
||||
diff |= SD_FLOORPIC;
|
||||
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
|
||||
if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
|
||||
diff |= SD_CEILPIC;
|
||||
|
||||
if (ss->lightlevel != SHORT(ms->lightlevel))
|
||||
|
@ -545,6 +545,8 @@ static void P_NetArchiveWorld(void)
|
|||
|
||||
if (ss->tag != SHORT(ms->tag))
|
||||
diff2 |= SD_TAG;
|
||||
if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
|
||||
diff2 |= SD_TAGLIST;
|
||||
|
||||
// Check if any of the sector's FOFs differ from how they spawned
|
||||
if (ss->ffloors)
|
||||
|
@ -592,16 +594,17 @@ static void P_NetArchiveWorld(void)
|
|||
WRITEFIXED(put, ss->ceiling_xoffs);
|
||||
if (diff2 & SD_CYOFFS)
|
||||
WRITEFIXED(put, ss->ceiling_yoffs);
|
||||
if (diff2 & SD_TAG)
|
||||
{
|
||||
if (diff2 & SD_TAG) // save only the tag
|
||||
WRITEINT16(put, ss->tag);
|
||||
WRITEINT32(put, ss->firsttag);
|
||||
WRITEINT32(put, ss->nexttag);
|
||||
}
|
||||
if (diff2 & SD_FLOORANG)
|
||||
WRITEANGLE(put, ss->floorpic_angle);
|
||||
if (diff2 & SD_CEILANG)
|
||||
WRITEANGLE(put, ss->ceilingpic_angle);
|
||||
if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
|
||||
{ // either of these could be changed even if tag isn't
|
||||
WRITEINT32(put, ss->firsttag);
|
||||
WRITEINT32(put, ss->nexttag);
|
||||
}
|
||||
|
||||
// Special case: save the stats of all modified ffloors along with their ffloor "number"s
|
||||
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
|
||||
|
@ -762,12 +765,12 @@ static void P_NetUnArchiveWorld(void)
|
|||
sectors[i].ceilingheight = READFIXED(get);
|
||||
if (diff & SD_FLOORPIC)
|
||||
{
|
||||
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
|
||||
sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
|
||||
get += 8;
|
||||
}
|
||||
if (diff & SD_CEILPIC)
|
||||
{
|
||||
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
|
||||
sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
|
||||
get += 8;
|
||||
}
|
||||
if (diff & SD_LIGHT)
|
||||
|
@ -784,12 +787,11 @@ static void P_NetUnArchiveWorld(void)
|
|||
if (diff2 & SD_CYOFFS)
|
||||
sectors[i].ceiling_yoffs = READFIXED(get);
|
||||
if (diff2 & SD_TAG)
|
||||
sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
|
||||
if (diff2 & SD_TAGLIST)
|
||||
{
|
||||
INT16 tag;
|
||||
tag = READINT16(get);
|
||||
sectors[i].firsttag = READINT32(get);
|
||||
sectors[i].nexttag = READINT32(get);
|
||||
P_ChangeSectorTag(i, tag);
|
||||
}
|
||||
if (diff2 & SD_FLOORANG)
|
||||
sectors[i].floorpic_angle = READANGLE(get);
|
||||
|
@ -2628,6 +2630,7 @@ static void P_NetUnArchiveThinkers(void)
|
|||
thinker_t *next;
|
||||
UINT8 tclass;
|
||||
UINT8 restoreNum = false;
|
||||
UINT32 i;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
|
||||
I_Error("Bad $$$.sav at archive block Thinkers");
|
||||
|
@ -2648,6 +2651,12 @@ static void P_NetUnArchiveThinkers(void)
|
|||
iquetail = iquehead = 0;
|
||||
P_InitThinkers();
|
||||
|
||||
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
|
||||
}
|
||||
|
||||
// read in saved thinkers
|
||||
for (;;)
|
||||
{
|
||||
|
@ -3306,7 +3315,7 @@ void P_SaveNetGame(void)
|
|||
{
|
||||
thinker_t *th;
|
||||
mobj_t *mobj;
|
||||
INT32 i = 0;
|
||||
INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
|
||||
|
||||
CV_SaveNetVars(&save_p);
|
||||
P_NetArchiveMisc();
|
||||
|
|
|
@ -160,6 +160,33 @@ FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg)
|
|||
I_Error("Invalid or corrupt map.\nLook in log file or text console for technical details.");
|
||||
}
|
||||
|
||||
/** Sets a header's flickies to be equivalent to the original Freed Animals
|
||||
*
|
||||
* \param i The header to set flickies for
|
||||
*/
|
||||
void P_SetDemoFlickies(INT16 i)
|
||||
{
|
||||
mapheaderinfo[i]->numFlickies = 5;
|
||||
mapheaderinfo[i]->flickies = Z_Realloc(mapheaderinfo[i]->flickies, 5*sizeof(mobjtype_t), PU_STATIC, NULL);
|
||||
mapheaderinfo[i]->flickies[0] = MT_FLICKY_02/*MT_BUNNY*/;
|
||||
mapheaderinfo[i]->flickies[1] = MT_FLICKY_01/*MT_BIRD*/;
|
||||
mapheaderinfo[i]->flickies[2] = MT_FLICKY_12/*MT_MOUSE*/;
|
||||
mapheaderinfo[i]->flickies[3] = MT_FLICKY_11/*MT_COW*/;
|
||||
mapheaderinfo[i]->flickies[4] = MT_FLICKY_03/*MT_CHICKEN*/;
|
||||
}
|
||||
|
||||
/** Clears a header's flickies
|
||||
*
|
||||
* \param i The header to clear flickies for
|
||||
*/
|
||||
void P_DeleteFlickies(INT16 i)
|
||||
{
|
||||
if (mapheaderinfo[i]->flickies)
|
||||
Z_Free(mapheaderinfo[i]->flickies);
|
||||
mapheaderinfo[i]->flickies = NULL;
|
||||
mapheaderinfo[i]->numFlickies = 0;
|
||||
}
|
||||
|
||||
#define NUMLAPS_DEFAULT 4
|
||||
|
||||
/** Clears the data from a single map header.
|
||||
|
@ -223,6 +250,12 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
|
|||
mapheaderinfo[num]->levelflags = 0;
|
||||
DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE);
|
||||
mapheaderinfo[num]->menuflags = 0;
|
||||
// Flickies. Nope, no delfile support here either
|
||||
#if 1 // equivalent to "FlickyList = DEMO"
|
||||
P_SetDemoFlickies(num);
|
||||
#else // equivalent to "FlickyList = NONE"
|
||||
P_DeleteFlickies(num);
|
||||
#endif
|
||||
// TODO grades support for delfile (pfft yeah right)
|
||||
P_DeleteGrades(num);
|
||||
// an even further impossibility, delfile custom opts support
|
||||
|
@ -241,6 +274,7 @@ void P_AllocMapHeader(INT16 i)
|
|||
if (!mapheaderinfo[i])
|
||||
{
|
||||
mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL);
|
||||
mapheaderinfo[i]->flickies = NULL;
|
||||
mapheaderinfo[i]->grades = NULL;
|
||||
}
|
||||
P_ClearSingleMapHeaderInfo(i + 1);
|
||||
|
@ -574,6 +608,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
|
|||
return (INT32)i;
|
||||
}
|
||||
|
||||
// help function for Lua and $$$.sav reading
|
||||
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
|
||||
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
|
||||
//
|
||||
INT32 P_AddLevelFlatRuntime(const char *flatname)
|
||||
{
|
||||
size_t i;
|
||||
levelflat_t *levelflat = levelflats;
|
||||
|
||||
//
|
||||
// first scan through the already found flats
|
||||
//
|
||||
for (i = 0; i < numlevelflats; i++, levelflat++)
|
||||
if (strnicmp(levelflat->name,flatname,8)==0)
|
||||
break;
|
||||
|
||||
// that flat was already found in the level, return the id
|
||||
if (i == numlevelflats)
|
||||
{
|
||||
// allocate new flat memory
|
||||
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
|
||||
levelflat = levelflats+i;
|
||||
|
||||
// store the name
|
||||
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
|
||||
strupr(levelflat->name);
|
||||
|
||||
// store the flat lump number
|
||||
levelflat->lumpnum = R_GetFlatNumForName(flatname);
|
||||
|
||||
#ifndef ZDEBUG
|
||||
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
|
||||
#endif
|
||||
|
||||
numlevelflats++;
|
||||
}
|
||||
|
||||
// level flat id
|
||||
return (INT32)i;
|
||||
}
|
||||
|
||||
// help function for $$$.sav checking
|
||||
// this simply returns the flat # for the name given
|
||||
//
|
||||
INT32 P_CheckLevelFlat(const char *flatname)
|
||||
{
|
||||
size_t i;
|
||||
levelflat_t *levelflat = levelflats;
|
||||
|
||||
//
|
||||
// scan through the already found flats
|
||||
//
|
||||
for (i = 0; i < numlevelflats; i++, levelflat++)
|
||||
if (strnicmp(levelflat->name,flatname,8)==0)
|
||||
break;
|
||||
|
||||
if (i == numlevelflats)
|
||||
return 0; // ??? flat was not found, this should not happen!
|
||||
|
||||
// level flat id
|
||||
return (INT32)i;
|
||||
}
|
||||
|
||||
static void P_LoadSectors(lumpnum_t lumpnum)
|
||||
{
|
||||
UINT8 *data;
|
||||
|
@ -614,6 +711,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
|
|||
ss->special = SHORT(ms->special);
|
||||
ss->tag = SHORT(ms->tag);
|
||||
ss->nexttag = ss->firsttag = -1;
|
||||
ss->spawn_nexttag = ss->spawn_firsttag = -1;
|
||||
|
||||
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
|
||||
ss->validcount = 0;
|
||||
|
|
|
@ -47,6 +47,8 @@ typedef struct
|
|||
extern size_t numlevelflats;
|
||||
extern levelflat_t *levelflats;
|
||||
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
|
||||
INT32 P_AddLevelFlatRuntime(const char *flatname);
|
||||
INT32 P_CheckLevelFlat(const char *flatname);
|
||||
|
||||
extern size_t nummapthings;
|
||||
extern mapthing_t *mapthings;
|
||||
|
@ -66,6 +68,9 @@ void P_WriteThings(lumpnum_t lump);
|
|||
size_t P_PrecacheLevelFlats(void);
|
||||
void P_AllocMapHeader(INT16 i);
|
||||
|
||||
void P_SetDemoFlickies(INT16 i);
|
||||
void P_DeleteFlickies(INT16 i);
|
||||
|
||||
// Needed for NiGHTS
|
||||
void P_ReloadRings(void);
|
||||
void P_DeleteGrades(INT16 i);
|
||||
|
|
|
@ -1519,6 +1519,8 @@ static inline void P_InitTagLists(void)
|
|||
size_t j = (unsigned)sectors[i].tag % numsectors;
|
||||
sectors[i].nexttag = sectors[j].firsttag;
|
||||
sectors[j].firsttag = (INT32)i;
|
||||
sectors[i].spawn_nexttag = sectors[i].nexttag;
|
||||
sectors[j].spawn_firsttag = sectors[j].firsttag;
|
||||
}
|
||||
|
||||
for (i = numlines - 1; i != (size_t)-1; i--)
|
||||
|
@ -5339,6 +5341,10 @@ void T_LaserFlash(laserthink_t *flash)
|
|||
&& thing->flags & MF_BOSS)
|
||||
continue; // Don't hurt bosses
|
||||
|
||||
// Don't endlessly kill egg guard shields (or anything else for that matter)
|
||||
if (thing->health <= 0)
|
||||
continue;
|
||||
|
||||
top = P_GetSpecialTopZ(thing, sourcesec, sector);
|
||||
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
|
||||
|
||||
|
|
10
src/p_user.c
10
src/p_user.c
|
@ -5699,11 +5699,13 @@ static void P_DoNiGHTSCapsule(player_t *player)
|
|||
}
|
||||
else
|
||||
{
|
||||
fixed_t z;
|
||||
|
||||
z = player->capsule->z + player->capsule->height/2;
|
||||
for (i = 0; i < 16; i++)
|
||||
P_SpawnMobj(player->capsule->x, player->capsule->y, z, MT_BIRD);
|
||||
{
|
||||
mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true);
|
||||
flicky->z += player->capsule->height/2;
|
||||
flicky->angle = (i*(ANGLE_MAX/16));
|
||||
P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].mare == player->mare)
|
||||
|
|
67
src/r_bsp.c
67
src/r_bsp.c
|
@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
|
|||
static sector_t tempsec; // Deep water hack
|
||||
extracolormap_t *floorcolormap;
|
||||
extracolormap_t *ceilingcolormap;
|
||||
fixed_t floorcenterz, ceilingcenterz;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
if (num >= numsubsectors)
|
||||
|
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
|
|||
|
||||
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
|
||||
|
||||
floorcenterz =
|
||||
#ifdef ESLOPE
|
||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->floorheight;
|
||||
|
||||
ceilingcenterz =
|
||||
#ifdef ESLOPE
|
||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->ceilingheight;
|
||||
|
||||
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
|
||||
if (frontsector->ffloors)
|
||||
{
|
||||
|
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
|
|||
sub->sector->moved = frontsector->moved = false;
|
||||
}
|
||||
|
||||
light = R_GetPlaneLight(frontsector,
|
||||
#ifdef ESLOPE
|
||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->floorheight, false);
|
||||
light = R_GetPlaneLight(frontsector, floorcenterz, false);
|
||||
if (frontsector->floorlightsec == -1)
|
||||
floorlightlevel = *frontsector->lightlist[light].lightlevel;
|
||||
floorcolormap = frontsector->lightlist[light].extra_colormap;
|
||||
light = R_GetPlaneLight(frontsector,
|
||||
#ifdef ESLOPE
|
||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->ceilingheight, false);
|
||||
light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
|
||||
if (frontsector->ceilinglightsec == -1)
|
||||
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
|
||||
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
|
||||
|
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
|
|||
{
|
||||
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
|
||||
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, frontsector->f_slope
|
||||
#endif
|
||||
|
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
|
|||
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
|
||||
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
||||
ceilingcolormap, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, frontsector->c_slope
|
||||
#endif
|
||||
|
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
|
|||
if (frontsector->ffloors)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
|
||||
fixed_t heightcheck, planecenterz;
|
||||
|
||||
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
|
||||
{
|
||||
|
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = NULL;
|
||||
ffloor[numffloors].polyobj = NULL;
|
||||
|
||||
floorcenterz =
|
||||
#ifdef ESLOPE
|
||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->floorheight;
|
||||
|
||||
ceilingcenterz =
|
||||
#ifdef ESLOPE
|
||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||
#endif
|
||||
frontsector->ceilingheight;
|
||||
|
||||
heightcheck =
|
||||
#ifdef ESLOPE
|
||||
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
|
||||
|
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
|
||||
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
|
||||
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, *rover->b_slope
|
||||
#endif
|
||||
|
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
|
||||
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
|
||||
frontsector->lightlist[light].extra_colormap, rover
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, *rover->t_slope
|
||||
#endif
|
||||
|
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
|
|||
polysec = po->lines[0]->backsector;
|
||||
ffloor[numffloors].plane = NULL;
|
||||
|
||||
if (polysec->floorheight <= frontsector->ceilingheight
|
||||
&& polysec->floorheight >= frontsector->floorheight
|
||||
if (polysec->floorheight <= ceilingcenterz
|
||||
&& polysec->floorheight >= floorcenterz
|
||||
&& (viewz < polysec->floorheight))
|
||||
{
|
||||
fixed_t xoff, yoff;
|
||||
|
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
|
|||
polysec->floorpic_angle-po->angle,
|
||||
NULL,
|
||||
NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, po
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, NULL // will ffloors be slopable eventually?
|
||||
#endif
|
||||
);
|
||||
//ffloor[numffloors].plane->polyobj = po;
|
||||
|
||||
ffloor[numffloors].height = polysec->floorheight;
|
||||
ffloor[numffloors].polyobj = po;
|
||||
|
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
|
|||
|
||||
ffloor[numffloors].plane = NULL;
|
||||
|
||||
if (polysec->ceilingheight >= frontsector->floorheight
|
||||
&& polysec->ceilingheight <= frontsector->ceilingheight
|
||||
if (polysec->ceilingheight >= floorcenterz
|
||||
&& polysec->ceilingheight <= ceilingcenterz
|
||||
&& (viewz > polysec->ceilingheight))
|
||||
{
|
||||
fixed_t xoff, yoff;
|
||||
|
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
|
|||
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
|
||||
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
|
||||
NULL, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, po
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, NULL // will ffloors be slopable eventually?
|
||||
#endif
|
||||
);
|
||||
//ffloor[numffloors].plane->polyobj = po;
|
||||
|
||||
ffloor[numffloors].polyobj = po;
|
||||
ffloor[numffloors].height = polysec->ceilingheight;
|
||||
|
|
26
src/r_data.c
26
src/r_data.c
|
@ -360,6 +360,32 @@ done:
|
|||
return blocktex;
|
||||
}
|
||||
|
||||
//
|
||||
// R_GetTextureNum
|
||||
//
|
||||
// Returns the actual texture id that we should use.
|
||||
// This can either be texnum, the current frame for texnum's anim (if animated),
|
||||
// or 0 if not valid.
|
||||
//
|
||||
INT32 R_GetTextureNum(INT32 texnum)
|
||||
{
|
||||
if (texnum < 0 || texnum >= numtextures)
|
||||
return 0;
|
||||
return texturetranslation[texnum];
|
||||
}
|
||||
|
||||
//
|
||||
// R_CheckTextureCache
|
||||
//
|
||||
// Use this if you need to make sure the texture is cached before R_GetColumn calls
|
||||
// e.g.: midtextures and FOF walls
|
||||
//
|
||||
void R_CheckTextureCache(INT32 tex)
|
||||
{
|
||||
if (!texturecache[tex])
|
||||
R_GenerateTexture(tex);
|
||||
}
|
||||
|
||||
//
|
||||
// R_GetColumn
|
||||
//
|
||||
|
|
|
@ -67,6 +67,9 @@ extern CV_PossibleValue_t Color_cons_t[];
|
|||
void R_LoadTextures(void);
|
||||
void R_FlushTextureCache(void);
|
||||
|
||||
INT32 R_GetTextureNum(INT32 texnum);
|
||||
void R_CheckTextureCache(INT32 tex);
|
||||
|
||||
// Retrieve column data for span blitting.
|
||||
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
|
||||
|
||||
|
|
11
src/r_defs.h
11
src/r_defs.h
|
@ -203,6 +203,7 @@ typedef struct r_lightlist_s
|
|||
fixed_t heightstep;
|
||||
fixed_t botheight;
|
||||
fixed_t botheightstep;
|
||||
fixed_t startheight; // for repeating midtextures
|
||||
INT16 lightlevel;
|
||||
extracolormap_t *extra_colormap;
|
||||
lighttable_t *rcolormap;
|
||||
|
@ -224,15 +225,6 @@ typedef struct linechain_s
|
|||
|
||||
|
||||
|
||||
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
|
||||
typedef struct secplane_t
|
||||
{
|
||||
// the plane is defined as a*x + b*y + c*z + d = 0
|
||||
// ic is 1/c, for faster Z calculations
|
||||
|
||||
fixed_t a, b, c, d, ic;
|
||||
} secplane_t;
|
||||
|
||||
// Slopes
|
||||
#ifdef ESLOPE
|
||||
typedef enum {
|
||||
|
@ -392,6 +384,7 @@ typedef struct sector_s
|
|||
#endif
|
||||
|
||||
// these are saved for netgames, so do not let Lua touch these!
|
||||
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
|
||||
|
||||
// offsets sector spawned with (via linedef type 7)
|
||||
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
|
||||
|
|
65
src/r_main.c
65
src/r_main.c
|
@ -148,7 +148,6 @@ consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo,
|
|||
consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
@ -366,69 +365,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
|
|||
return R_PointToDist2(viewx, viewy, x, y);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
*** Zdoom C++ to Legacy C conversion ***
|
||||
****************************************/
|
||||
|
||||
// Utility to find the Z height at an XY location in a sector (for slopes)
|
||||
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
|
||||
{
|
||||
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
|
||||
}
|
||||
|
||||
// Returns the value of z at (x,y) if d is equal to dist
|
||||
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
|
||||
{
|
||||
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
|
||||
}
|
||||
|
||||
// Flips the plane's vertical orientiation, so that if it pointed up,
|
||||
// it will point down, and vice versa.
|
||||
void R_SecplaneFlipVert(secplane_t *secplane)
|
||||
{
|
||||
secplane->a = -secplane->a;
|
||||
secplane->b = -secplane->b;
|
||||
secplane->c = -secplane->c;
|
||||
secplane->d = -secplane->d;
|
||||
secplane->ic = -secplane->ic;
|
||||
}
|
||||
|
||||
// Returns true if 2 planes are the same
|
||||
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
|
||||
{
|
||||
return original->a == other->a && original->b == other->b
|
||||
&& original->c == other->c && original->d == other->d;
|
||||
}
|
||||
|
||||
// Returns true if 2 planes are different
|
||||
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
|
||||
{
|
||||
return original->a != other->a || original->b != other->b
|
||||
|| original->c != other->c || original->d != other->d;
|
||||
}
|
||||
|
||||
// Moves a plane up/down by hdiff units
|
||||
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
|
||||
{
|
||||
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
|
||||
}
|
||||
|
||||
// Returns how much this plane's height would change if d were set to oldd
|
||||
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
|
||||
{
|
||||
return FixedMul(oldd - secplane->d, secplane->ic);
|
||||
}
|
||||
|
||||
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
|
||||
}
|
||||
|
||||
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
|
||||
}
|
||||
|
||||
//
|
||||
// R_ScaleFromGlobalAngle
|
||||
// Returns the texture mapping scale for the current line (horizontal span)
|
||||
|
@ -1424,7 +1360,6 @@ void R_RegisterEngineStuff(void)
|
|||
{
|
||||
CV_RegisterVar(&cv_gravity);
|
||||
CV_RegisterVar(&cv_tailspickup);
|
||||
CV_RegisterVar(&cv_soniccd);
|
||||
CV_RegisterVar(&cv_allowmlook);
|
||||
CV_RegisterVar(&cv_homremoval);
|
||||
CV_RegisterVar(&cv_flipcam);
|
||||
|
|
12
src/r_main.h
12
src/r_main.h
|
@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
|
|||
fixed_t R_PointToDist(fixed_t x, fixed_t y);
|
||||
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
|
||||
|
||||
// ZDoom C++ to Legacy C conversion Tails 04-29-2002
|
||||
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
|
||||
fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
|
||||
fixed_t dist);
|
||||
void R_SecplaneFlipVert(secplane_t *secplane);
|
||||
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
|
||||
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
|
||||
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
|
||||
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
|
||||
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
|
||||
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
|
||||
|
||||
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
|
||||
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
|
||||
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
|
||||
|
|
|
@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
|
|||
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
||||
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
|
||||
ffloor_t *pfloor
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, polyobj_t *polyobj
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, pslope_t *slope
|
||||
#endif
|
||||
|
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
|||
#ifdef POLYOBJECTS_PLANES
|
||||
if (check->polyobj && pfloor)
|
||||
continue;
|
||||
if (polyobj != check->polyobj)
|
||||
continue;
|
||||
#endif
|
||||
if (height == check->height && picnum == check->picnum
|
||||
&& lightlevel == check->lightlevel
|
||||
|
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
|||
check->viewangle = viewangle;
|
||||
check->plangle = plangle;
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
check->polyobj = NULL;
|
||||
check->polyobj = polyobj;
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
check->slope = slope;
|
||||
|
@ -720,7 +725,11 @@ void R_DrawPlanes(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (pl->ffloor != NULL)
|
||||
if (pl->ffloor != NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
|| pl->polyobj != NULL
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
R_DrawSinglePlane(pl);
|
||||
|
|
|
@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
|
|||
void R_DrawPlanes(void);
|
||||
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
|
||||
extracolormap_t *planecolormap, ffloor_t *ffloor
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, polyobj_t *polyobj
|
||||
#endif
|
||||
#ifdef ESLOPE
|
||||
, pslope_t *slope
|
||||
#endif
|
||||
|
|
123
src/r_segs.c
123
src/r_segs.c
|
@ -309,7 +309,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
curline = ds->curline;
|
||||
frontsector = curline->frontsector;
|
||||
backsector = curline->backsector;
|
||||
texnum = texturetranslation[curline->sidedef->midtexture];
|
||||
texnum = R_GetTextureNum(curline->sidedef->midtexture);
|
||||
windowbottom = windowtop = sprbotscreen = INT32_MAX;
|
||||
|
||||
// hack translucent linedef types (900-909 for transtables 1-9)
|
||||
|
@ -353,6 +353,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
rw_scalestep = ds->scalestep;
|
||||
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
||||
|
||||
// Texture must be cached before setting colfunc_2s,
|
||||
// otherwise texture[texnum]->holes may be false when it shouldn't be
|
||||
R_CheckTextureCache(texnum);
|
||||
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
||||
// are not stored per-column with post info in SRB2
|
||||
if (textures[texnum]->holes)
|
||||
|
@ -408,6 +411,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
|
||||
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
|
||||
#endif
|
||||
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
|
||||
rlight->lightlevel = *light->lightlevel;
|
||||
rlight->extra_colormap = light->extra_colormap;
|
||||
rlight->flags = light->flags;
|
||||
|
@ -501,6 +505,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
{
|
||||
rw_scalestep = ds->scalestep;
|
||||
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
||||
if (dc_numlights)
|
||||
{ // reset all lights to their starting heights
|
||||
for (i = 0; i < dc_numlights; i++)
|
||||
{
|
||||
rlight = &dc_lightlist[i];
|
||||
rlight->height = rlight->startheight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ESLOPE
|
||||
|
@ -771,7 +783,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
curline = ds->curline;
|
||||
backsector = pfloor->target;
|
||||
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
|
||||
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
|
||||
|
||||
colfunc = wallcolfunc;
|
||||
|
||||
|
@ -779,7 +791,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
{
|
||||
size_t linenum = curline->linedef-backsector->lines[0];
|
||||
newline = pfloor->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
|
||||
if (pfloor->flags & FF_TRANSLUCENT)
|
||||
|
@ -1049,6 +1061,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
|
||||
dc_texturemid += offsetvalue;
|
||||
|
||||
// Texture must be cached before setting colfunc_2s,
|
||||
// otherwise texture[texnum]->holes may be false when it shouldn't be
|
||||
R_CheckTextureCache(texnum);
|
||||
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
||||
// are not stored per-column with post info anymore in Doom Legacy
|
||||
if (textures[texnum]->holes)
|
||||
|
@ -1969,14 +1984,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
|
||||
if (!backsector)
|
||||
{
|
||||
fixed_t texheight;
|
||||
// single sided line
|
||||
midtexture = texturetranslation[sidedef->midtexture];
|
||||
midtexture = R_GetTextureNum(sidedef->midtexture);
|
||||
texheight = textureheight[midtexture];
|
||||
// a single sided line is terminal, so it must mark ends
|
||||
markfloor = markceiling = true;
|
||||
#ifdef ESLOPE
|
||||
if (linedef->flags & ML_EFFECT2) {
|
||||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
|
||||
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
|
||||
else
|
||||
rw_midtexturemid = frontsector->ceilingheight - viewz;
|
||||
}
|
||||
|
@ -1985,10 +2002,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
|
||||
rw_midtexturemid = worldbottom + texheight;
|
||||
rw_midtextureslide = floorfrontslide;
|
||||
#else
|
||||
vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
|
||||
vtop = frontsector->floorheight + texheight;
|
||||
// bottom of texture at bottom
|
||||
rw_midtexturemid = vtop - viewz;
|
||||
#endif
|
||||
|
@ -2220,76 +2237,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
fixed_t texheight;
|
||||
// top texture
|
||||
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
|
||||
&& linedef->sidenum[1] != 0xffff)
|
||||
{
|
||||
// Special case... use offsets from 2nd side but only if it has a texture.
|
||||
side_t *def = &sides[linedef->sidenum[1]];
|
||||
toptexture = texturetranslation[def->toptexture];
|
||||
toptexture = R_GetTextureNum(def->toptexture);
|
||||
|
||||
if (!toptexture) //Second side has no texture, use the first side's instead.
|
||||
toptexture = texturetranslation[sidedef->toptexture];
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
||||
else
|
||||
rw_toptexturemid = backsector->ceilingheight - viewz;
|
||||
} else
|
||||
#endif
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
{
|
||||
// top of texture at top
|
||||
rw_toptexturemid = worldtop;
|
||||
#ifdef ESLOPE
|
||||
rw_toptextureslide = ceilingfrontslide;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
|
||||
rw_toptextureslide = ceilingbackslide;
|
||||
#else
|
||||
vtop = backsector->ceilingheight + textureheight[def->toptexture];
|
||||
// bottom of texture
|
||||
rw_toptexturemid = vtop - viewz;
|
||||
#endif
|
||||
}
|
||||
toptexture = R_GetTextureNum(sidedef->toptexture);
|
||||
texheight = textureheight[toptexture];
|
||||
}
|
||||
else
|
||||
{
|
||||
toptexture = texturetranslation[sidedef->toptexture];
|
||||
|
||||
toptexture = R_GetTextureNum(sidedef->toptexture);
|
||||
texheight = textureheight[toptexture];
|
||||
}
|
||||
#ifdef ESLOPE
|
||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
||||
else
|
||||
rw_toptexturemid = backsector->ceilingheight - viewz;
|
||||
} else
|
||||
#endif
|
||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
{
|
||||
// top of texture at top
|
||||
rw_toptexturemid = worldtop;
|
||||
#ifdef ESLOPE
|
||||
rw_toptextureslide = ceilingfrontslide;
|
||||
#endif
|
||||
}
|
||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
||||
else
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
|
||||
rw_toptextureslide = ceilingbackslide;
|
||||
#else
|
||||
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
|
||||
// bottom of texture
|
||||
rw_toptexturemid = vtop - viewz;
|
||||
rw_toptexturemid = backsector->ceilingheight - viewz;
|
||||
} else
|
||||
#endif
|
||||
if (linedef->flags & ML_DONTPEGTOP)
|
||||
{
|
||||
// top of texture at top
|
||||
rw_toptexturemid = worldtop;
|
||||
#ifdef ESLOPE
|
||||
rw_toptextureslide = ceilingfrontslide;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
rw_toptexturemid = worldhigh + texheight;
|
||||
rw_toptextureslide = ceilingbackslide;
|
||||
#else
|
||||
vtop = backsector->ceilingheight + texheight;
|
||||
// bottom of texture
|
||||
rw_toptexturemid = vtop - viewz;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// check BOTTOM TEXTURE
|
||||
|
@ -2300,7 +2291,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
) //seulement si VISIBLE!!!
|
||||
{
|
||||
// bottom texture
|
||||
bottomtexture = texturetranslation[sidedef->bottomtexture];
|
||||
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||
|
@ -2585,7 +2576,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
|
||||
ds_p->numthicksides = numthicksides = i;
|
||||
}
|
||||
if (sidedef->midtexture)
|
||||
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
|
||||
{
|
||||
// masked midtexture
|
||||
if (!ds_p->thicksidecol)
|
||||
|
@ -3197,12 +3188,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
|
||||
{
|
||||
ds_p->silhouette |= SIL_TOP;
|
||||
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
|
||||
ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
|
||||
}
|
||||
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
|
||||
{
|
||||
ds_p->silhouette |= SIL_BOTTOM;
|
||||
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
|
||||
ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
|
||||
}
|
||||
ds_p++;
|
||||
}
|
||||
|
|
|
@ -1885,21 +1885,25 @@ static void R_CreateDrawNodes(void)
|
|||
entry->ffloor = ds->thicksides[i];
|
||||
}
|
||||
}
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
// Check for a polyobject plane, but only if this is a front line
|
||||
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
|
||||
plane = ds->curline->polyseg->visplane;
|
||||
R_PlaneBounds(plane);
|
||||
|
||||
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
|
||||
;
|
||||
else {
|
||||
// Put it in!
|
||||
entry = R_CreateDrawNode(&nodehead);
|
||||
entry->plane = plane;
|
||||
entry->seg = ds;
|
||||
}
|
||||
ds->curline->polyseg->visplane = NULL;
|
||||
}
|
||||
#endif
|
||||
if (ds->maskedtexturecol)
|
||||
{
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
// Check for a polyobject plane, but only if this is a front line
|
||||
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
|
||||
// Put it in!
|
||||
|
||||
entry = R_CreateDrawNode(&nodehead);
|
||||
entry->plane = ds->curline->polyseg->visplane;
|
||||
entry->seg = ds;
|
||||
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
|
||||
ds->curline->polyseg->visplane = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
entry = R_CreateDrawNode(&nodehead);
|
||||
entry->seg = ds;
|
||||
}
|
||||
|
@ -1942,6 +1946,29 @@ static void R_CreateDrawNodes(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
// find all the remaining polyobject planes and add them on the end of the list
|
||||
// probably this is a terrible idea if we wanted them to be sorted properly
|
||||
// but it works getting them in for now
|
||||
for (i = 0; i < numPolyObjects; i++)
|
||||
{
|
||||
if (!PolyObjects[i].visplane)
|
||||
continue;
|
||||
plane = PolyObjects[i].visplane;
|
||||
R_PlaneBounds(plane);
|
||||
|
||||
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
|
||||
{
|
||||
PolyObjects[i].visplane = NULL;
|
||||
continue;
|
||||
}
|
||||
entry = R_CreateDrawNode(&nodehead);
|
||||
entry->plane = plane;
|
||||
// note: no seg is set, for what should be obvious reasons
|
||||
PolyObjects[i].visplane = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (visspritecount == 0)
|
||||
return;
|
||||
|
||||
|
@ -1998,13 +2025,16 @@ static void R_CreateDrawNodes(void)
|
|||
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
|
||||
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
|
||||
|
||||
for (i = x1; i <= x2; i++)
|
||||
if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
|
||||
{
|
||||
if (r2->seg->frontscale[i] > rover->sortscale)
|
||||
break;
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (r2->seg->frontscale[i] > rover->sortscale)
|
||||
break;
|
||||
}
|
||||
if (i > x2)
|
||||
continue;
|
||||
}
|
||||
if (i > x2)
|
||||
continue;
|
||||
|
||||
entry = R_CreateDrawNode(NULL);
|
||||
(entry->prev = r2->prev)->next = entry;
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
|
||||
#include <tchar.h>
|
||||
#ifndef HAVE_SDL
|
||||
#include "win_main.h"
|
||||
#endif
|
||||
#include "../doomdef.h" //just for VERSION
|
||||
#include "win_dbg.h"
|
||||
#include "../m_argv.h" //print the parameter in the log
|
||||
|
|
Loading…
Reference in a new issue