as re-released 2008-09-04

This commit is contained in:
archive 2008-09-04 00:00:00 +00:00
commit 3e67144fa1
86 changed files with 58040 additions and 0 deletions

90
Heretic Source/AM_DATA.H Normal file
View File

@ -0,0 +1,90 @@
// AM_data.h : The vector graphics for the automap
#ifndef __AMDATA_H__
#define __AMDATA_H__
#pragma once
// a line drawing of the player pointing right, starting from the middle.
#define R ((8*PLAYERRADIUS)/7)
mline_t player_arrow[] = {
{ { -R+R/4, 0 }, { 0, 0} }, // center line.
{ { -R+R/4, R/8 }, { R, 0} }, // blade
{ { -R+R/4, -R/8 }, { R, 0 } },
{ { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
{ { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
{ { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors
{ { -R+R/8, R/4 }, { -R+R/4, R/4} },
{ { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel
{ { -R-R/4, R/8 }, { -R+R/8, R/8 } },
{ { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
};
mline_t keysquare[] = {
{ { 0, 0 }, { R/4, -R/2 } },
{ { R/4, -R/2 }, { R/2, -R/2 } },
{ { R/2, -R/2 }, { R/2, R/2 } },
{ { R/2, R/2 }, { R/4, R/2 } },
{ { R/4, R/2 }, { 0, 0 } }, // handle part type thing
{ { 0, 0 }, { -R, 0 } }, // stem
{ { -R, 0 }, { -R, -R/2 } }, // end lockpick part
{ { -3*R/4, 0 }, { -3*R/4, -R/4 } }
};
/*mline_t player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/4 } }, // ----->
{ { R, 0 }, { R-R/2, -R/4 } },
{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
};
*/
#undef R
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
#define NUMKEYSQUARELINES (sizeof(keysquare)/sizeof(mline_t))
#define R ((8*PLAYERRADIUS)/7)
mline_t cheat_player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/6 } }, // ----->
{ { R, 0 }, { R-R/2, -R/6 } },
{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
{ { -R/6, -R/6 }, { 0, -R/6 } },
{ { 0, -R/6 }, { 0, R/4 } },
{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
};
#undef R
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
#define R (FRACUNIT)
mline_t triangle_guy[] = {
{ { -.867*R, -.5*R }, { .867*R, -.5*R } },
{ { .867*R, -.5*R } , { 0, R } },
{ { 0, R }, { -.867*R, -.5*R } }
};
#undef R
#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
#define R (FRACUNIT)
mline_t thintriangle_guy[] = {
{ { -.5*R, -.7*R }, { R, 0 } },
{ { R, 0 }, { -.5*R, .7*R } },
{ { -.5*R, .7*R }, { -.5*R, -.7*R } }
};
#undef R
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
#endif

1352
Heretic Source/AM_MAP.C Normal file

File diff suppressed because it is too large Load Diff

121
Heretic Source/AM_MAP.H Normal file
View File

@ -0,0 +1,121 @@
#ifndef __AMMAP_H__
#define __AMMAP_H__
#pragma once
// For use if I do walls with outsides/insides
#define REDS 12*8
#define REDRANGE 1//16
#define BLUES (256-4*16+8)
#define BLUERANGE 1//8
#define GREENS (33*8)
#define GREENRANGE 1//16
#define GRAYS (5*8)
#define GRAYSRANGE 1//16
#define BROWNS (14*8)
#define BROWNRANGE 1//16
#define YELLOWS 10*8
#define YELLOWRANGE 1
#define BLACK 0
#define WHITE 4*8
#define PARCH 13*8-1
#define BLOODRED 150
#define BLUEKEY 197
#define YELLOWKEY 144
#define GREENKEY 220
// Automap colors
#define BACKGROUND PARCH
#define YOURCOLORS WHITE
#define YOURRANGE 0
#define WALLCOLORS REDS
#define WALLRANGE REDRANGE
#define TSWALLCOLORS GRAYS
#define TSWALLRANGE GRAYSRANGE
#define FDWALLCOLORS BROWNS
#define FDWALLRANGE BROWNRANGE
#define CDWALLCOLORS YELLOWS
#define CDWALLRANGE YELLOWRANGE
#define THINGCOLORS GREENS
#define THINGRANGE GREENRANGE
#define SECRETWALLCOLORS WALLCOLORS
#define SECRETWALLRANGE WALLRANGE
#define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
#define GRIDRANGE 0
#define XHAIRCOLORS GRAYS
// drawing stuff
#define FB 0
#define KEY_TAB 9
#define AM_PANDOWNKEY KEY_DOWNARROW
#define AM_PANUPKEY KEY_UPARROW
#define AM_PANRIGHTKEY KEY_RIGHTARROW
#define AM_PANLEFTKEY KEY_LEFTARROW
//#define AM_PANDOWNKEY SC_DOWNARROW
//#define AM_PANUPKEY SC_UPARROW
//#define AM_PANRIGHTKEY SC_RIGHTARROW
//#define AM_PANLEFTKEY SC_LEFTARROW
#define AM_ZOOMINKEY '='
//#define AM_ZOOMINKEY 13
//#define AM_ZOOMOUTKEY 12
#define AM_ZOOMOUTKEY '-'
#define AM_STARTKEY KEY_TAB
#define AM_ENDKEY KEY_TAB
#define AM_GOBIGKEY '0'
//#define AM_GOBIGKEY 11
//#define AM_FOLLOWKEY 33
//#define AM_GRIDKEY 34
#define AM_FOLLOWKEY 'f'
#define AM_GRIDKEY 'g'
#define AM_NUMMARKPOINTS 10
#define AM_MSGHEADER (('a'<<24)+('m'<<16))
#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
#define INITSCALEMTOF (.2*FRACUNIT) // scale on entry
// how much the automap moves window per tic in frame-buffer coordinates
#define F_PANINC 4 // moves 140 pixels in 1 second
// how much zoom-in per tic
#define M_ZOOMIN ((int) (1.02*FRACUNIT)) // goes to 2x in 1 second
// how much zoom-out per tic
#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // pulls out to 0.5x in 1 second
// translates between frame-buffer and map distances
#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
// translates between frame-buffer and map coordinates
#define CXMTOF(x) (f_x + MTOF((x)-m_x))
#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
// the following is crap
#define LINE_NEVERSEE ML_DONTDRAW
typedef struct
{
int x, y;
} fpoint_t;
typedef struct
{
fpoint_t a, b;
} fline_t;
typedef vertex_t mpoint_t;
typedef struct
{
mpoint_t a, b;
} mline_t;
typedef struct
{
fixed_t slp, islp;
} islope_t;
// extern int f_x, f_y, f_w, f_h;
#endif

BIN
Heretic Source/COLORMAP.LMP Normal file

Binary file not shown.

462
Heretic Source/CT_CHAT.C Normal file
View File

@ -0,0 +1,462 @@
//
// Chat mode
//
#include <string.h>
#include <ctype.h>
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
#define QUEUESIZE 128
#define MESSAGESIZE 128
#define MESSAGELEN 265
#define CT_PLR_GREEN 1
#define CT_PLR_YELLOW 2
#define CT_PLR_RED 3
#define CT_PLR_BLUE 4
#define CT_PLR_ALL 5
#define CT_KEY_GREEN 'g'
#define CT_KEY_YELLOW 'y'
#define CT_KEY_RED 'r'
#define CT_KEY_BLUE 'b'
#define CT_KEY_ALL 't'
#define CT_ESCAPE 6
// Public data
void CT_Init(void);
void CT_Drawer(void);
boolean CT_Responder(event_t *ev);
void CT_Ticker(void);
char CT_dequeueChatChar(void);
boolean chatmodeon;
// Private data
void CT_queueChatChar(char ch);
void CT_ClearChatMessage(int player);
void CT_AddChar(int player, char c);
void CT_BackSpace(int player);
int head;
int tail;
byte ChatQueue[QUEUESIZE];
int chat_dest[MAXPLAYERS];
char chat_msg[MAXPLAYERS][MESSAGESIZE];
char plr_lastmsg[MAXPLAYERS][MESSAGESIZE+9]; // add in the length of the pre-string
int msgptr[MAXPLAYERS];
int msglen[MAXPLAYERS];
boolean cheated;
static int FontABaseLump;
char *CT_FromPlrText[MAXPLAYERS] =
{
"GREEN: ",
"YELLOW: ",
"RED: ",
"BLUE: "
};
char *chat_macros[10];
boolean altdown;
boolean shiftdown;
//===========================================================================
//
// CT_Init
//
// Initialize chat mode data
//===========================================================================
void CT_Init(void)
{
int i;
head = 0; //initialize the queue index
tail = 0;
chatmodeon = false;
memset(ChatQueue, 0, QUEUESIZE);
for(i = 0; i < MAXPLAYERS; i++)
{
chat_dest[i] = 0;
msgptr[i] = 0;
memset(plr_lastmsg[i], 0, MESSAGESIZE);
memset(chat_msg[i], 0, MESSAGESIZE);
}
FontABaseLump = W_GetNumForName("FONTA_S")+1;
return;
}
//===========================================================================
//
// CT_Stop
//
//===========================================================================
void CT_Stop(void)
{
chatmodeon = false;
return;
}
//===========================================================================
//
// CT_Responder
//
//===========================================================================
boolean CT_Responder(event_t *ev)
{
char *macro;
int sendto;
if(!netgame)
{
return false;
}
if(ev->data1 == KEY_LALT || ev->data2 == KEY_RALT)
{
altdown = (ev->type == ev_keydown);
return false;
}
if(ev->data1 == KEY_RSHIFT)
{
shiftdown = (ev->type == ev_keydown);
return false;
}
if(ev->type != ev_keydown)
{
return false;
}
if(!chatmodeon)
{
sendto = 0;
if(ev->data1 == CT_KEY_ALL)
{
sendto = CT_PLR_ALL;
}
else if(ev->data1 == CT_KEY_GREEN)
{
sendto = CT_PLR_GREEN;
}
else if(ev->data1 == CT_KEY_YELLOW)
{
sendto = CT_PLR_YELLOW;
}
else if(ev->data1 == CT_KEY_RED)
{
sendto = CT_PLR_RED;
}
else if(ev->data1 == CT_KEY_BLUE)
{
sendto = CT_PLR_BLUE;
}
if(sendto == 0 || (sendto != CT_PLR_ALL && !playeringame[sendto-1])
|| sendto == consoleplayer+1)
{
return false;
}
CT_queueChatChar(sendto);
chatmodeon = true;
return true;
}
else
{
if(altdown)
{
if(ev->data1 >= '0' && ev->data1 <= '9')
{
if(ev->data1 == '0')
{ // macro 0 comes after macro 9
ev->data1 = '9'+1;
}
macro = chat_macros[ev->data1-'1'];
CT_queueChatChar(KEY_ENTER); //send old message
CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest.
while(*macro)
{
CT_queueChatChar(toupper(*macro++));
}
CT_queueChatChar(KEY_ENTER); //send it off...
CT_Stop();
return true;
}
}
if(ev->data1 == KEY_ENTER)
{
CT_queueChatChar(KEY_ENTER);
CT_Stop();
return true;
}
else if(ev->data1 == KEY_ESCAPE)
{
CT_queueChatChar(CT_ESCAPE);
CT_Stop();
return true;
}
else if(ev->data1 >= 'a' && ev->data1 <= 'z')
{
CT_queueChatChar(ev->data1-32);
return true;
}
else if(shiftdown)
{
if(ev->data1 == '1')
{
CT_queueChatChar('!');
return true;
}
else if(ev->data1 == '/')
{
CT_queueChatChar('?');
return true;
}
}
else
{
if(ev->data1 == ' ' || ev->data1 == ',' || ev->data1 == '.'
|| (ev->data1 >= '0' && ev->data1 <= '9') || ev->data1 == '\''
|| ev->data1 == KEY_BACKSPACE || ev->data1 == '-' || ev->data1 == '=')
{
CT_queueChatChar(ev->data1);
return true;
}
}
}
return false;
}
//===========================================================================
//
// CT_Ticker
//
//===========================================================================
void CT_Ticker(void)
{
int i;
int j;
char c;
int numplayers;
for(i=0; i < MAXPLAYERS; i++)
{
if(!playeringame[i])
{
continue;
}
if((c = players[i].cmd.chatchar) != 0)
{
if(c <= 5)
{
chat_dest[i] = c;
continue;
}
else if(c == CT_ESCAPE)
{
CT_ClearChatMessage(i);
}
else if(c == KEY_ENTER)
{
numplayers = 0;
for(j = 0; j < MAXPLAYERS; j++)
{
numplayers += playeringame[j];
}
CT_AddChar(i, 0); // set the end of message character
if(numplayers > 2)
{
strcpy(plr_lastmsg[i], CT_FromPlrText[i]);
strcat(plr_lastmsg[i], chat_msg[i]);
}
else
{
strcpy(plr_lastmsg[i], chat_msg[i]);
}
if(i != consoleplayer && (chat_dest[i] == consoleplayer+1
|| chat_dest[i] == CT_PLR_ALL) && *chat_msg[i])
{
P_SetMessage(&players[consoleplayer], plr_lastmsg[i],
true);
S_StartSound(NULL, sfx_chat);
}
else if(i == consoleplayer && (*chat_msg[i]))
{
if(numplayers > 1)
{
P_SetMessage(&players[consoleplayer], "-MESSAGE SENT-",
true);
S_StartSound(NULL, sfx_chat);
}
else
{
P_SetMessage(&players[consoleplayer],
"THERE ARE NO OTHER PLAYERS IN THE GAME!", true);
S_StartSound(NULL, sfx_chat);
}
}
CT_ClearChatMessage(i);
}
else if(c == KEY_BACKSPACE)
{
CT_BackSpace(i);
}
else
{
CT_AddChar(i, c);
}
}
}
return;
}
//===========================================================================
//
// CT_Drawer
//
//===========================================================================
void CT_Drawer(void)
{
int i;
int x;
patch_t *patch;
if(chatmodeon)
{
x = 25;
for(i = 0; i < msgptr[consoleplayer]; i++)
{
if(chat_msg[consoleplayer][i] < 33)
{
x += 6;
}
else
{
patch=W_CacheLumpNum(FontABaseLump+
chat_msg[consoleplayer][i]-33, PU_CACHE);
V_DrawPatch(x, 10, patch);
x += patch->width;
}
}
V_DrawPatch(x, 10, W_CacheLumpName("FONTA59", PU_CACHE));
BorderTopRefresh = true;
UpdateState |= I_MESSAGES;
}
}
//===========================================================================
//
// CT_queueChatChar
//
//===========================================================================
void CT_queueChatChar(char ch)
{
if((tail+1)&(QUEUESIZE-1) == head)
{ // the queue is full
return;
}
ChatQueue[tail] = ch;
tail = (tail+1)&(QUEUESIZE-1);
}
//===========================================================================
//
// CT_dequeueChatChar
//
//===========================================================================
char CT_dequeueChatChar(void)
{
byte temp;
if(head == tail)
{ // queue is empty
return 0;
}
temp = ChatQueue[head];
head = (head+1)&(QUEUESIZE-1);
return temp;
}
//===========================================================================
//
// CT_AddChar
//
//===========================================================================
void CT_AddChar(int player, char c)
{
patch_t *patch;
if(msgptr[player]+1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN)
{ // full.
return;
}
chat_msg[player][msgptr[player]] = c;
msgptr[player]++;
if(c < 33)
{
msglen[player] += 6;
}
else
{
patch = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
msglen[player] += patch->width;
}
}
//===========================================================================
//
// CT_BackSpace
//
// Backs up a space, when the user hits (obviously) backspace
//===========================================================================
void CT_BackSpace(int player)
{
patch_t *patch;
char c;
if(msgptr[player] == 0)
{ // message is already blank
return;
}
msgptr[player]--;
c = chat_msg[player][msgptr[player]];
if(c < 33)
{
msglen[player] -= 6;
}
else
{
patch = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
msglen[player] -= patch->width;
}
chat_msg[player][msgptr[player]] = 0;
}
//===========================================================================
//
// CT_ClearChatMessage
//
// Clears out the data for the chat message, but the player's message
// is still saved in plrmsg.
//===========================================================================
void CT_ClearChatMessage(int player)
{
memset(chat_msg[player], 0, MESSAGESIZE);
msgptr[player] = 0;
msglen[player] = 0;
}

15
Heretic Source/CT_CHAT.H Normal file
View File

@ -0,0 +1,15 @@
//
// Chat mode stuff
//
#define CT_PLR_GREEN 1
#define CT_PLR_YELLOW 2
#define CT_PLR_RED 3
#define CT_PLR_BLUE 4
#define CT_PLR_ALL 5
#define CT_KEY_GREEN 'g'
#define CT_KEY_YELLOW 'y'
#define CT_KEY_RED 'r'
#define CT_KEY_BLUE 'b'
#define CT_KEY_ALL 't'

51
Heretic Source/DEFS.INC Normal file
View File

@ -0,0 +1,51 @@
SKIPPRIMITIVES = 0 ; set to 1 to skip unwound drawing
SCREEN = 0a0000h
SCREENWIDTH = 320
SCREENHEIGHT = 200
PLANEWIDTH = 80
PLANESIZE = 80*200
PEL_WRITE_ADR = 03c8h
PEL_DATA = 03c9h
SC_INDEX = 03C4h
SC_MAPMASK = 2
OP_RET = 0c3h
OP_MOVAL = 08ah
OP_MOVDEST = 088h
.DATA
EXTRN _dc_colormap:DWORD
EXTRN _dc_x:DWORD
EXTRN _dc_yl:DWORD
EXTRN _dc_yh:DWORD
EXTRN _dc_iscale:DWORD
EXTRN _dc_texturemid:DWORD
EXTRN _dc_source:DWORD
EXTRN _ylookup:DWORD
EXTRN _columnofs:DWORD
EXTRN _ds_y:DWORD
EXTRN _ds_x1:DWORD
EXTRN _ds_x2:DWORD
EXTRN _ds_colormap:DWORD
EXTRN _ds_xfrac:DWORD
EXTRN _ds_yfrac:DWORD
EXTRN _ds_xstep:DWORD
EXTRN _ds_ystep:DWORD
EXTRN _ds_source:DWORD
PUSHR MACRO
pushad
ENDM
POPR MACRO
popad
ENDM

BIN
Heretic Source/DEMO1.LMP Normal file

Binary file not shown.

195
Heretic Source/DOOMDATA.H Normal file
View File

@ -0,0 +1,195 @@
// DoomData.h
// all external data is defined here
// most of the data is loaded into different structures at run time
#ifndef __DOOMDATA__
#define __DOOMDATA__
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum {false, true} boolean;
typedef unsigned char byte;
#endif
/*
===============================================================================
map level types
===============================================================================
*/
// lump order in a map wad
enum {ML_LABEL, ML_THINGS, ML_LINEDEFS, ML_SIDEDEFS, ML_VERTEXES, ML_SEGS,
ML_SSECTORS, ML_NODES, ML_SECTORS , ML_REJECT, ML_BLOCKMAP};
typedef struct
{
short x,y;
} mapvertex_t;
typedef struct
{
short textureoffset;
short rowoffset;
char toptexture[8], bottomtexture[8], midtexture[8];
short sector; // on viewer's side
} mapsidedef_t;
typedef struct
{
short v1, v2;
short flags;
short special, tag;
short sidenum[2]; // sidenum[1] will be -1 if one sided
} maplinedef_t;
#define ML_BLOCKING 1
#define ML_BLOCKMONSTERS 2
#define ML_TWOSIDED 4 // backside will not be present at all
// if not two sided
// if a texture is pegged, the texture will have the end exposed to air held
// constant at the top or bottom of the texture (stairs or pulled down things)
// and will move with a height change of one of the neighbor sectors
// Unpegged textures allways have the first row of the texture at the top
// pixel of the line for both top and bottom textures (windows)
#define ML_DONTPEGTOP 8
#define ML_DONTPEGBOTTOM 16
#define ML_SECRET 32 // don't map as two sided: IT'S A SECRET!
#define ML_SOUNDBLOCK 64 // don't let sound cross two of these
#define ML_DONTDRAW 128 // don't draw on the automap
#define ML_MAPPED 256 // set if allready drawn in automap
typedef struct
{
short floorheight, ceilingheight;
char floorpic[8], ceilingpic[8];
short lightlevel;
short special, tag;
} mapsector_t;
typedef struct
{
short numsegs;
short firstseg; // segs are stored sequentially
} mapsubsector_t;
typedef struct
{
short v1, v2;
short angle;
short linedef, side;
short offset;
} mapseg_t;
enum {BOXTOP,BOXBOTTOM,BOXLEFT,BOXRIGHT}; // bbox coordinates
#define NF_SUBSECTOR 0x8000
typedef struct
{
short x,y,dx,dy; // partition line
short bbox[2][4]; // bounding box for each child
unsigned short children[2]; // if NF_SUBSECTOR its a subsector
} mapnode_t;
typedef struct
{
short x,y;
short angle;
short type;
short options;
} mapthing_t;
#define MTF_EASY 1
#define MTF_NORMAL 2
#define MTF_HARD 4
#define MTF_AMBUSH 8
/*
===============================================================================
texture definition
===============================================================================
*/
typedef struct
{
short originx;
short originy;
short patch;
short stepdir;
short colormap;
} mappatch_t;
typedef struct
{
char name[8];
boolean masked;
short width;
short height;
void **columndirectory; // OBSOLETE
short patchcount;
mappatch_t patches[1];
} maptexture_t;
/*
===============================================================================
graphics
===============================================================================
*/
// posts are runs of non masked source pixels
typedef struct
{
byte topdelta; // -1 is the last post in a column
byte length;
// length data bytes follows
} post_t;
// column_t is a list of 0 or more post_t, (byte)-1 terminated
typedef post_t column_t;
// a patch holds one or more columns
// patches are used for sprites and all masked pictures
typedef struct
{
short width; // bounding box size
short height;
short leftoffset; // pixels to the left of origin
short topoffset; // pixels below the origin
int columnofs[8]; // only [width] used
// the [0] is &columnofs[width]
} patch_t;
// a pic is an unmasked block of pixels
typedef struct
{
byte width,height;
byte data;
} pic_t;
/*
===============================================================================
status
===============================================================================
*/
#endif // __DOOMDATA__

1182
Heretic Source/DOOMDEF.H Normal file

File diff suppressed because it is too large Load Diff

18
Heretic Source/DRCOORD.H Normal file
View File

@ -0,0 +1,18 @@
#import <appkit/appkit.h>
@interface DRCoord:Object
{
id players_i;
id console_i;
id skill_i;
id episode_i;
id map_i;
}
- newGame: sender;
- scale1: sender;
- scale2: sender;
- scale4: sender;
@end

406
Heretic Source/DSTRINGS.BAK Normal file
View File

@ -0,0 +1,406 @@
// DStrings.h
//---------------------------------------------------------------------------
//
// M_menu.c
//
//---------------------------------------------------------------------------
#define PRESSKEY "press a key."
#define PRESSYN "press y or n."
#define TXT_PAUSED "PAUSED"
#define QUITMSG "are you sure you want to\nquit this great game?"
#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
#define QLPROMPT "do you want to quickload the game named"\
"\n\n'%s'?\n\n"PRESSYN
#define NEWGAME "you can't start a new game\n"\
"while in a network game.\n\n"PRESSKEY
#define NIGHTMARE "are you sure? this skill level\n"\
"isn't even remotely fair.\n\n"PRESSYN
#define SWSTRING "this is the shareware version of doom.\n\n"\
"you need to order the entire trilogy.\n\n"PRESSKEY
#define MSGOFF "Messages OFF"
#define MSGON "Messages ON"
#define NETEND "you can't end a netgame!\n\n"PRESSKEY
#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
#define DOSY "(press y to quit to dos.)"
#define DETAILHI "High detail"
#define DETAILLO "Low detail"
#define GAMMALVL0 "Gamma correction OFF"
#define GAMMALVL1 "Gamma correction level 1"
#define GAMMALVL2 "Gamma correction level 2"
#define GAMMALVL3 "Gamma correction level 3"
#define GAMMALVL4 "Gamma correction level 4"
#define EMPTYSTRING "empty slot"
//---------------------------------------------------------------------------
//
// P_inter.c
//
//---------------------------------------------------------------------------
// Keys
#define TXT_GOTBLUEKEY "BLUE KEY"
#define TXT_GOTYELLOWKEY "YELLOW KEY"
#define TXT_GOTGREENKEY "GREEN KEY"
// Artifacts
#define TXT_ARTIHEALTH "QUARTZ FLASK"
#define TXT_ARTIFLY "WINGS OF WRATH"
#define TXT_ARTIINVULNERABILITY "RING OF INVINCIBILITY"
#define TXT_ARTITOMEOFPOWER "TOME OF POWER"
#define TXT_ARTIINVISIBILITY "SHADOWSPHERE"
#define TXT_ARTIEGG "MORPH OVUM"
#define TXT_ARTISUPERHEALTH "MYSTIC URN"
#define TXT_ARTITORCH "TORCH"
#define TXT_ARTIFIREBOMB "TIME BOMB OF THE ANCIENTS"
#define TXT_ARTITELEPORT "CHAOS DEVICE"
// Items
#define TXT_ITEMHEALTH "CRYSTAL VIAL"
#define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING"
#define TXT_ITEMSHIELD1 "SILVER SHIELD"
#define TXT_ITEMSHIELD2 "ENCHANTED SHIELD"
#define TXT_ITEMSUPERMAP "MAP SCROLL"
// Ammo
#define TXT_AMMOGOLDWAND1 "WAND CRYSTAL"
#define TXT_AMMOGOLDWAND2 "CRYSTAL GEODE"
#define TXT_AMMOMACE1 "MACE SPHERES"
#define TXT_AMMOMACE2 "PILE OF MACE SPHERES"
#define TXT_AMMOCROSSBOW1 "ETHEREAL ARROWS"
#define TXT_AMMOCROSSBOW2 "QUIVER OF ETHEREAL ARROWS"
#define TXT_AMMOBLASTER1 "CLAW ORB"
#define TXT_AMMOBLASTER2 "ENERGY ORB"
#define TXT_AMMOSKULLROD1 "LESSER RUNES"
#define TXT_AMMOSKULLROD2 "GREATER RUNES"
#define TXT_AMMOPHOENIXROD1 "FLAME ORB"
#define TXT_AMMOPHOENIXROD2 "INFERNO ORB"
// Weapons
#define TXT_WPNMACE "FIREMACE"
#define TXT_WPNCROSSBOW "ETHEREAL CROSSBOW"
#define TXT_WPNBLASTER "DRAGON CLAW"
#define TXT_WPNSKULLROD "HELLSTAFF"
#define TXT_WPNPHOENIXROD "PHOENIX ROD"
#define TXT_WPNGAUNTLETS "GAUNTLETS OF THE NECROMANCER"
//---------------------------------------------------------------------------
//
// SB_bar.c
//
//---------------------------------------------------------------------------
#define TXT_CHEATGODON "GOD MODE ON"
#define TXT_CHEATGODOFF "GOD MODE OFF"
#define TXT_CHEATNOCLIPON "NO CLIPPING ON"
#define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF"
#define TXT_CHEATWEAPONS "ALL WEAPONS"
#define TXT_CHEATFLIGHTON "FLIGHT ON"
#define TXT_CHEATFLIGHTOFF "FLIGHT OFF"
#define TXT_CHEATPOWERON "POWER ON"
#define TXT_CHEATPOWEROFF "POWER OFF"
#define TXT_CHEATHEALTH "FULL HEALTH"
#define TXT_CHEATKEYS "ALL KEYS"
#define TXT_CHEATSOUNDON "SOUND DEBUG ON"
#define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF"
#define TXT_CHEATTICKERON "TICKER ON"
#define TXT_CHEATTICKEROFF "TICKER OFF"
#define TXT_CHEATARTIFACTS1 "CHOOSE AN ARTIFACT ( A - J )"
#define TXT_CHEATARTIFACTS2 "HOW MANY ( 1 - 9 )"
#define TXT_CHEATARTIFACTS3 "YOU GOT IT"
#define TXT_CHEATARTIFACTSFAIL "BAD INPUT"
#define TXT_CHEATWARP "LEVEL WARP"
#define TXT_CHEATSCREENSHOT "SCREENSHOT"
#define TXT_CHEATCHICKENON "CHICKEN ON"
#define TXT_CHEATCHICKENOFF "CHICKEN OFF"
#define TXT_CHEATMASSACRE "MASSACRE"
#define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!"
#define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS"
//---------------------------------------------------------------------------
//
// P_doors.c
//
//---------------------------------------------------------------------------
#define TXT_NEEDBLUEKEY "YOU NEED A BLUE KEY TO OPEN THIS DOOR"
#define TXT_NEEDGREENKEY "YOU NEED A GREEN KEY TO OPEN THIS DOOR"
#define TXT_NEEDYELLOWKEY "YOU NEED A YELLOW KEY TO OPEN THIS DOOR"
//---------------------------------------------------------------------------
//
// G_game.c
//
//---------------------------------------------------------------------------
#define TXT_GAMESAVED "GAME SAVED"
//---------------------------------------------------------------------------
//
// HU_stuff.c
//
//---------------------------------------------------------------------------
#define HUSTR_E1M1 "E1M1: Hangar"
#define HUSTR_E1M2 "E1M2: Nuclear Plant"
#define HUSTR_E1M3 "E1M3: Toxin Refinery"
#define HUSTR_E1M4 "E1M4: Command Control"
#define HUSTR_E1M5 "E1M5: Phobos Lab"
#define HUSTR_E1M6 "E1M6: Central Processing"
#define HUSTR_E1M7 "E1M7: Computer Station"
#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
#define HUSTR_E1M9 "E1M9: Military Base"
#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
#define HUSTR_E2M2 "E2M2: Containment Area"
#define HUSTR_E2M3 "E2M3: Refinery"
#define HUSTR_E2M4 "E2M4: Deimos Lab"
#define HUSTR_E2M5 "E2M5: Command Center"
#define HUSTR_E2M6 "E2M6: Halls of the Damned"
#define HUSTR_E2M7 "E2M7: Spawning Vats"
#define HUSTR_E2M8 "E2M8: Tower of Babel"
#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
#define HUSTR_E3M1 "E3M1: Hell Keep"
#define HUSTR_E3M2 "E3M2: Slough of Despair"
#define HUSTR_E3M3 "E3M3: Pandemonium"
#define HUSTR_E3M4 "E3M4: House of Pain"
#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
#define HUSTR_E3M6 "E3M6: Mt. Erebus"
#define HUSTR_E3M7 "E3M7: Limbo"
#define HUSTR_E3M8 "E3M8: Dis"
#define HUSTR_E3M9 "E3M9: Warrens"
#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
#define HUSTR_CHATMACRO2 "I'm OK."
#define HUSTR_CHATMACRO3 "I'm not looking too good!"
#define HUSTR_CHATMACRO4 "Help!"
#define HUSTR_CHATMACRO5 "You suck!"
#define HUSTR_CHATMACRO6 "Next time, scumbag..."
#define HUSTR_CHATMACRO7 "Come here!"
#define HUSTR_CHATMACRO8 "I'll take care of it."
#define HUSTR_CHATMACRO9 "Yes"
#define HUSTR_CHATMACRO0 "No"
#define HUSTR_TALKTOSELF1 "You mumble to yourself"
#define HUSTR_TALKTOSELF2 "Who's there?"
#define HUSTR_TALKTOSELF3 "You scare yourself"
#define HUSTR_TALKTOSELF4 "You start to rave"
#define HUSTR_TALKTOSELF5 "You've lost it..."
#define HUSTR_MESSAGESENT "[Message Sent]"
// The following should NOT be changed unless it seems
// just AWFULLY necessary
#define HUSTR_PLRGREEN "Green: "
#define HUSTR_PLRINDIGO "Indigo: "
#define HUSTR_PLRBROWN "Brown: "
#define HUSTR_PLRRED "Red: "
#define HUSTR_KEYGREEN 'g'
#define HUSTR_KEYINDIGO 'i'
#define HUSTR_KEYBROWN 'b'
#define HUSTR_KEYRED 'r'
//---------------------------------------------------------------------------
//
// AM_map.c
//
//---------------------------------------------------------------------------
#define AMSTR_FOLLOWON "FOLLOW MODE ON"
#define AMSTR_FOLLOWOFF "FOLLOW MODE OFF"
#define AMSTR_GRIDON "Grid ON"
#define AMSTR_GRIDOFF "Grid OFF"
#define AMSTR_MARKEDSPOT "Marked Spot"
#define AMSTR_MARKSCLEARED "All Marks Cleared"
//---------------------------------------------------------------------------
//
// ST_stuff.c
//
//---------------------------------------------------------------------------
#define STSTR_DQDON "Degreelessness Mode On"
#define STSTR_DQDOFF "Degreelessness Mode Off"
#define STSTR_KFAADDED "Very Happy Ammo Added"
#define STSTR_NCON "No Clipping Mode ON"
#define STSTR_NCOFF "No Clipping Mode OFF"
#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
#define STSTR_BEHOLDX "Power-up Toggled"
#define STSTR_CHOPPERS "... doesn't suck - GM"
#define STSTR_CLEV "Changing Level..."
//---------------------------------------------------------------------------
//
// F_finale.c
//
//---------------------------------------------------------------------------
#define E1TEXT "with the destruction of the iron\n"\
"liches and their minions, the last\n"\
"of the undead are cleared from this\n"\
"plane of existence.\n\n"\
"those creatures had to come from\n"\
"somewhere, though, and you have the\n"\
"sneaky suspicion that the fiery\n"\
"portal of hell's maw opens onto\n"\
"their home dimension.\n\n"\
"to make sure that more undead\n"\
"(or even worse things) don't come\n"\
"through, you'll have to seal hell's\n"\
"maw from the other side. of course\n"\
"this means you may get stuck in a\n"\
"very unfriendly world, but no one\n"\
"ever said being a Heretic was easy!"
#define E2TEXT "the mighty maulotaurs have proved\n"\
"to be no match for you, and as\n"\
"their steaming corpses slide to the\n"\
"ground you feel a sense of grim\n"\
"satisfaction that they have been\n"\
"destroyed.\n\n"\
"the gateways which they guarded\n"\
"have opened, revealing what you\n"\
"hope is the way home. but as you\n"\
"step through, mocking laughter\n"\
"rings in your ears.\n\n"\
"was some other force controlling\n"\
"the maulotaurs? could there be even\n"\
"more horrific beings through this\n"\
"gate? the sweep of a crystal dome\n"\
"overhead where the sky should be is\n"\
"certainly not a good sign...."
#define E3TEXT "the death of d'sparil has loosed\n"\
"the magical bonds holding his\n"\
"creatures on this plane, their\n"\
"dying screams overwhelming his own\n"\
"cries of agony.\n\n"\
"your oath of vengeance fulfilled,\n"\
"you enter the portal to your own\n"\
"world, mere moments before the dome\n"\
"shatters into a million pieces.\n\n"\
"but if d'sparil's power is broken\n"\
"forever, why don't you feel safe?\n"\
"was it that last shout just before\n"\
"his death, the one that sounded\n"\
"like a curse? or a summoning? you\n"\
"can't really be sure, but it might\n"\
"just have been a scream.\n\n"\
"then again, what about the other\n"\
"serpent riders?"
#define E4TEXT "you thought you would return to your\n"\
"own world after d'sparil died, but\n"\
"his final act banished you to his\n"\
"own plane. here you entered the\n"\
"shattered remnants of lands\n"\
"conquered by d'sparil. you defeated\n"\
"the last guardians of these lands,\n"\
"but now you stand before the gates\n"\
"to d'sparil's stronghold. until this\n"\
"moment you had no doubts about your\n"\
"ability to face anything you might\n"\
"encounter, but beyond this portal\n"\
"lies the very heart of the evil\n"\
"which invaded your world. d'sparil\n"\
"might be dead, but the pit where he\n"\
"was spawned remains. now you must\n"\
"enter that pit in the hopes of\n"\
"finding a way out. and somewhere,\n"\
"in the darkest corner of d'sparil's\n"\
"demesne, his personal bodyguards\n"\
"await your arrival ..."
#define E5TEXT "as the final maulotaur bellows his\n"\
"death-agony, you realize that you\n"\
"have never come so close to your own\n"\
"destruction. not even the fight with\n"\
"d'sparil and his disciples had been\n"\
"this desperate. grimly you stare at\n"\
"the gates which open before you,\n"\
"wondering if they lead home, or if\n"\
"they open onto some undreamed-of\n"\
"horror. you find yourself wondering\n"\
"if you have the strength to go on,\n"\
"if nothing but death and pain await\n"\
"you. but what else can you do, if\n"\
"the will to fight is gone? can you\n"\
"force yourself to continue in the\n"\
"face of such despair? do you have\n"\
"the courage? you find, in the end,\n"\
"that it is not within you to\n"\
"surrender without a fight. eyes\n"\
"wide, you go to meet your fate."
/*
#define E1TEXT "Once you beat the big badasses and\n"\
"clean out the moon base you're supposed\n"\
"to win, aren't you? Aren't you? Where's\n"\
"your fat reward and ticket home? What\n"\
"the hell is this? It's not supposed to\n"\
"end this way!\n"\
"\n" \
"It stinks like rotten meat, but looks\n"\
"like the lost Deimos base. Looks like\n"\
"you're stuck on The Shores of Hell.\n"\
"The only way out is through.\n"\
"\n"\
"To continue the DOOM experience, play\n"\
"The Shores of Hell and its amazing\n"\
"sequel, Inferno!\n"
#define E2TEXT "You've done it! The hideous cyber-\n"\
"demon lord that ruled the lost Deimos\n"\
"moon base has been slain and you\n"\
"are triumphant! But ... where are\n"\
"you? You clamber to the edge of the\n"\
"moon and look down to see the awful\n"\
"truth.\n" \
"\n"\
"Deimos floats above Hell itself!\n"\
"You've never heard of anyone escaping\n"\
"from Hell, but you'll make the bastards\n"\
"sorry they ever heard of you! Quickly,\n"\
"you rappel down to the surface of\n"\
"Hell.\n"\
"\n" \
"Now, it's on to the final chapter of\n"\
"DOOM! -- Inferno."
#define E3TEXT "The loathsome spiderdemon that\n"\
"masterminded the invasion of the moon\n"\
"bases and caused so much death has had\n"\
"its ass kicked for all time.\n"\
"\n"\
"A hidden doorway opens and you enter.\n"\
"You've proven too tough for Hell to\n"\
"contain, and now Hell at last plays\n"\
"fair -- for you emerge from the door\n"\
"to see the green fields of Earth!\n"\
"Home at last.\n" \
"\n"\
"You wonder what's been happening on\n"\
"Earth while you were battling evil\n"\
"unleashed. It's good that no Hell-\n"\
"spawn could have come through that\n"\
"door with you ..."
*/

406
Heretic Source/DSTRINGS.H Normal file
View File

@ -0,0 +1,406 @@
// DStrings.h
//---------------------------------------------------------------------------
//
// M_menu.c
//
//---------------------------------------------------------------------------
#define PRESSKEY "press a key."
#define PRESSYN "press y or n."
#define TXT_PAUSED "PAUSED"
#define QUITMSG "are you sure you want to\nquit this great game?"
#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
#define QLPROMPT "do you want to quickload the game named"\
"\n\n'%s'?\n\n"PRESSYN
#define NEWGAME "you can't start a new game\n"\
"while in a network game.\n\n"PRESSKEY
#define NIGHTMARE "are you sure? this skill level\n"\
"isn't even remotely fair.\n\n"PRESSYN
#define SWSTRING "this is the shareware version of doom.\n\n"\
"you need to order the entire trilogy.\n\n"PRESSKEY
#define MSGOFF "Messages OFF"
#define MSGON "Messages ON"
#define NETEND "you can't end a netgame!\n\n"PRESSKEY
#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
#define DOSY "(press y to quit to dos.)"
#define DETAILHI "High detail"
#define DETAILLO "Low detail"
#define GAMMALVL0 "Gamma correction OFF"
#define GAMMALVL1 "Gamma correction level 1"
#define GAMMALVL2 "Gamma correction level 2"
#define GAMMALVL3 "Gamma correction level 3"
#define GAMMALVL4 "Gamma correction level 4"
#define EMPTYSTRING "empty slot"
//---------------------------------------------------------------------------
//
// P_inter.c
//
//---------------------------------------------------------------------------
// Keys
#define TXT_GOTBLUEKEY "BLUE KEY"
#define TXT_GOTYELLOWKEY "YELLOW KEY"
#define TXT_GOTGREENKEY "GREEN KEY"
// Artifacts
#define TXT_ARTIHEALTH "QUARTZ FLASK"
#define TXT_ARTIFLY "WINGS OF WRATH"
#define TXT_ARTIINVULNERABILITY "RING OF INVINCIBILITY"
#define TXT_ARTITOMEOFPOWER "TOME OF POWER"
#define TXT_ARTIINVISIBILITY "SHADOWSPHERE"
#define TXT_ARTIEGG "MORPH OVUM"
#define TXT_ARTISUPERHEALTH "MYSTIC URN"
#define TXT_ARTITORCH "TORCH"
#define TXT_ARTIFIREBOMB "TIME BOMB OF THE ANCIENTS"
#define TXT_ARTITELEPORT "CHAOS DEVICE"
// Items
#define TXT_ITEMHEALTH "CRYSTAL VIAL"
#define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING"
#define TXT_ITEMSHIELD1 "SILVER SHIELD"
#define TXT_ITEMSHIELD2 "ENCHANTED SHIELD"
#define TXT_ITEMSUPERMAP "MAP SCROLL"
// Ammo
#define TXT_AMMOGOLDWAND1 "WAND CRYSTAL"
#define TXT_AMMOGOLDWAND2 "CRYSTAL GEODE"
#define TXT_AMMOMACE1 "MACE SPHERES"
#define TXT_AMMOMACE2 "PILE OF MACE SPHERES"
#define TXT_AMMOCROSSBOW1 "ETHEREAL ARROWS"
#define TXT_AMMOCROSSBOW2 "QUIVER OF ETHEREAL ARROWS"
#define TXT_AMMOBLASTER1 "CLAW ORB"
#define TXT_AMMOBLASTER2 "ENERGY ORB"
#define TXT_AMMOSKULLROD1 "LESSER RUNES"
#define TXT_AMMOSKULLROD2 "GREATER RUNES"
#define TXT_AMMOPHOENIXROD1 "FLAME ORB"
#define TXT_AMMOPHOENIXROD2 "INFERNO ORB"
// Weapons
#define TXT_WPNMACE "FIREMACE"
#define TXT_WPNCROSSBOW "ETHEREAL CROSSBOW"
#define TXT_WPNBLASTER "DRAGON CLAW"
#define TXT_WPNSKULLROD "HELLSTAFF"
#define TXT_WPNPHOENIXROD "PHOENIX ROD"
#define TXT_WPNGAUNTLETS "GAUNTLETS OF THE NECROMANCER"
//---------------------------------------------------------------------------
//
// SB_bar.c
//
//---------------------------------------------------------------------------
#define TXT_CHEATGODON "GOD MODE ON"
#define TXT_CHEATGODOFF "GOD MODE OFF"
#define TXT_CHEATNOCLIPON "NO CLIPPING ON"
#define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF"
#define TXT_CHEATWEAPONS "ALL WEAPONS"
#define TXT_CHEATFLIGHTON "FLIGHT ON"
#define TXT_CHEATFLIGHTOFF "FLIGHT OFF"
#define TXT_CHEATPOWERON "POWER ON"
#define TXT_CHEATPOWEROFF "POWER OFF"
#define TXT_CHEATHEALTH "FULL HEALTH"
#define TXT_CHEATKEYS "ALL KEYS"
#define TXT_CHEATSOUNDON "SOUND DEBUG ON"
#define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF"
#define TXT_CHEATTICKERON "TICKER ON"
#define TXT_CHEATTICKEROFF "TICKER OFF"
#define TXT_CHEATARTIFACTS1 "CHOOSE AN ARTIFACT ( A - J )"
#define TXT_CHEATARTIFACTS2 "HOW MANY ( 1 - 9 )"
#define TXT_CHEATARTIFACTS3 "YOU GOT IT"
#define TXT_CHEATARTIFACTSFAIL "BAD INPUT"
#define TXT_CHEATWARP "LEVEL WARP"
#define TXT_CHEATSCREENSHOT "SCREENSHOT"
#define TXT_CHEATCHICKENON "CHICKEN ON"
#define TXT_CHEATCHICKENOFF "CHICKEN OFF"
#define TXT_CHEATMASSACRE "MASSACRE"
#define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!"
#define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS"
//---------------------------------------------------------------------------
//
// P_doors.c
//
//---------------------------------------------------------------------------
#define TXT_NEEDBLUEKEY "YOU NEED A BLUE KEY TO OPEN THIS DOOR"
#define TXT_NEEDGREENKEY "YOU NEED A GREEN KEY TO OPEN THIS DOOR"
#define TXT_NEEDYELLOWKEY "YOU NEED A YELLOW KEY TO OPEN THIS DOOR"
//---------------------------------------------------------------------------
//
// G_game.c
//
//---------------------------------------------------------------------------
#define TXT_GAMESAVED "GAME SAVED"
//---------------------------------------------------------------------------
//
// HU_stuff.c
//
//---------------------------------------------------------------------------
#define HUSTR_E1M1 "E1M1: Hangar"
#define HUSTR_E1M2 "E1M2: Nuclear Plant"
#define HUSTR_E1M3 "E1M3: Toxin Refinery"
#define HUSTR_E1M4 "E1M4: Command Control"
#define HUSTR_E1M5 "E1M5: Phobos Lab"
#define HUSTR_E1M6 "E1M6: Central Processing"
#define HUSTR_E1M7 "E1M7: Computer Station"
#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
#define HUSTR_E1M9 "E1M9: Military Base"
#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
#define HUSTR_E2M2 "E2M2: Containment Area"
#define HUSTR_E2M3 "E2M3: Refinery"
#define HUSTR_E2M4 "E2M4: Deimos Lab"
#define HUSTR_E2M5 "E2M5: Command Center"
#define HUSTR_E2M6 "E2M6: Halls of the Damned"
#define HUSTR_E2M7 "E2M7: Spawning Vats"
#define HUSTR_E2M8 "E2M8: Tower of Babel"
#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
#define HUSTR_E3M1 "E3M1: Hell Keep"
#define HUSTR_E3M2 "E3M2: Slough of Despair"
#define HUSTR_E3M3 "E3M3: Pandemonium"
#define HUSTR_E3M4 "E3M4: House of Pain"
#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
#define HUSTR_E3M6 "E3M6: Mt. Erebus"
#define HUSTR_E3M7 "E3M7: Limbo"
#define HUSTR_E3M8 "E3M8: Dis"
#define HUSTR_E3M9 "E3M9: Warrens"
#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
#define HUSTR_CHATMACRO2 "I'm OK."
#define HUSTR_CHATMACRO3 "I'm not looking too good!"
#define HUSTR_CHATMACRO4 "Help!"
#define HUSTR_CHATMACRO5 "You suck!"
#define HUSTR_CHATMACRO6 "Next time, scumbag..."
#define HUSTR_CHATMACRO7 "Come here!"
#define HUSTR_CHATMACRO8 "I'll take care of it."
#define HUSTR_CHATMACRO9 "Yes"
#define HUSTR_CHATMACRO0 "No"
#define HUSTR_TALKTOSELF1 "You mumble to yourself"
#define HUSTR_TALKTOSELF2 "Who's there?"
#define HUSTR_TALKTOSELF3 "You scare yourself"
#define HUSTR_TALKTOSELF4 "You start to rave"
#define HUSTR_TALKTOSELF5 "You've lost it..."
#define HUSTR_MESSAGESENT "[Message Sent]"
// The following should NOT be changed unless it seems
// just AWFULLY necessary
#define HUSTR_PLRGREEN "Green: "
#define HUSTR_PLRINDIGO "Indigo: "
#define HUSTR_PLRBROWN "Brown: "
#define HUSTR_PLRRED "Red: "
#define HUSTR_KEYGREEN 'g'
#define HUSTR_KEYINDIGO 'i'
#define HUSTR_KEYBROWN 'b'
#define HUSTR_KEYRED 'r'
//---------------------------------------------------------------------------
//
// AM_map.c
//
//---------------------------------------------------------------------------
#define AMSTR_FOLLOWON "FOLLOW MODE ON"
#define AMSTR_FOLLOWOFF "FOLLOW MODE OFF"
#define AMSTR_GRIDON "Grid ON"
#define AMSTR_GRIDOFF "Grid OFF"
#define AMSTR_MARKEDSPOT "Marked Spot"
#define AMSTR_MARKSCLEARED "All Marks Cleared"
//---------------------------------------------------------------------------
//
// ST_stuff.c
//
//---------------------------------------------------------------------------
#define STSTR_DQDON "Degreelessness Mode On"
#define STSTR_DQDOFF "Degreelessness Mode Off"
#define STSTR_KFAADDED "Very Happy Ammo Added"
#define STSTR_NCON "No Clipping Mode ON"
#define STSTR_NCOFF "No Clipping Mode OFF"
#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
#define STSTR_BEHOLDX "Power-up Toggled"
#define STSTR_CHOPPERS "... doesn't suck - GM"
#define STSTR_CLEV "Changing Level..."
//---------------------------------------------------------------------------
//
// F_finale.c
//
//---------------------------------------------------------------------------
#define E1TEXT "with the destruction of the iron\n"\
"liches and their minions, the last\n"\
"of the undead are cleared from this\n"\
"plane of existence.\n\n"\
"those creatures had to come from\n"\
"somewhere, though, and you have the\n"\
"sneaky suspicion that the fiery\n"\
"portal of hell's maw opens onto\n"\
"their home dimension.\n\n"\
"to make sure that more undead\n"\
"(or even worse things) don't come\n"\
"through, you'll have to seal hell's\n"\
"maw from the other side. of course\n"\
"this means you may get stuck in a\n"\
"very unfriendly world, but no one\n"\
"ever said being a Heretic was easy!"
#define E2TEXT "the mighty maulotaurs have proved\n"\
"to be no match for you, and as\n"\
"their steaming corpses slide to the\n"\
"ground you feel a sense of grim\n"\
"satisfaction that they have been\n"\
"destroyed.\n\n"\
"the gateways which they guarded\n"\
"have opened, revealing what you\n"\
"hope is the way home. but as you\n"\
"step through, mocking laughter\n"\
"rings in your ears.\n\n"\
"was some other force controlling\n"\
"the maulotaurs? could there be even\n"\
"more horrific beings through this\n"\
"gate? the sweep of a crystal dome\n"\
"overhead where the sky should be is\n"\
"certainly not a good sign...."
#define E3TEXT "the death of d'sparil has loosed\n"\
"the magical bonds holding his\n"\
"creatures on this plane, their\n"\
"dying screams overwhelming his own\n"\
"cries of agony.\n\n"\
"your oath of vengeance fulfilled,\n"\
"you enter the portal to your own\n"\
"world, mere moments before the dome\n"\
"shatters into a million pieces.\n\n"\
"but if d'sparil's power is broken\n"\
"forever, why don't you feel safe?\n"\
"was it that last shout just before\n"\
"his death, the one that sounded\n"\
"like a curse? or a summoning? you\n"\
"can't really be sure, but it might\n"\
"just have been a scream.\n\n"\
"then again, what about the other\n"\
"serpent riders?"
#define E4TEXT "you thought you would return to your\n"\
"own world after d'sparil died, but\n"\
"his final act banished you to his\n"\
"own plane. here you entered the\n"\
"shattered remnants of lands\n"\
"conquered by d'sparil. you defeated\n"\
"the last guardians of these lands,\n"\
"but now you stand before the gates\n"\
"to d'sparil's stronghold. until this\n"\
"moment you had no doubts about your\n"\
"ability to face anything you might\n"\
"encounter, but beyond this portal\n"\
"lies the very heart of the evil\n"\
"which invaded your world. d'sparil\n"\
"might be dead, but the pit where he\n"\
"was spawned remains. now you must\n"\
"enter that pit in the hopes of\n"\
"finding a way out. and somewhere,\n"\
"in the darkest corner of d'sparil's\n"\
"demesne, his personal bodyguards\n"\
"await your arrival ..."
#define E5TEXT "as the final maulotaur bellows his\n"\
"death-agony, you realize that you\n"\
"have never come so close to your own\n"\
"destruction. not even the fight with\n"\
"d'sparil and his disciples had been\n"\
"this desperate. grimly you stare at\n"\
"the gates which open before you,\n"\
"wondering if they lead home, or if\n"\
"they open onto some undreamed-of\n"\
"horror. you find yourself wondering\n"\
"if you have the strength to go on,\n"\
"if nothing but death and pain await\n"\
"you. but what else can you do, if\n"\
"the will to fight is gone? can you\n"\
"force yourself to continue in the\n"\
"face of such despair? do you have\n"\
"the courage? you find, in the end,\n"\
"that it is not within you to\n"\
"surrender without a fight. eyes\n"\
"wide, you go to meet your fate."
/*
#define E1TEXT "Once you beat the big badasses and\n"\
"clean out the moon base you're supposed\n"\
"to win, aren't you? Aren't you? Where's\n"\
"your fat reward and ticket home? What\n"\
"the hell is this? It's not supposed to\n"\
"end this way!\n"\
"\n" \
"It stinks like rotten meat, but looks\n"\
"like the lost Deimos base. Looks like\n"\
"you're stuck on The Shores of Hell.\n"\
"The only way out is through.\n"\
"\n"\
"To continue the DOOM experience, play\n"\
"The Shores of Hell and its amazing\n"\
"sequel, Inferno!\n"
#define E2TEXT "You've done it! The hideous cyber-\n"\
"demon lord that ruled the lost Deimos\n"\
"moon base has been slain and you\n"\
"are triumphant! But ... where are\n"\
"you? You clamber to the edge of the\n"\
"moon and look down to see the awful\n"\
"truth.\n" \
"\n"\
"Deimos floats above Hell itself!\n"\
"You've never heard of anyone escaping\n"\
"from Hell, but you'll make the bastards\n"\
"sorry they ever heard of you! Quickly,\n"\
"you rappel down to the surface of\n"\
"Hell.\n"\
"\n" \
"Now, it's on to the final chapter of\n"\
"DOOM! -- Inferno."
#define E3TEXT "The loathsome spiderdemon that\n"\
"masterminded the invasion of the moon\n"\
"bases and caused so much death has had\n"\
"its ass kicked for all time.\n"\
"\n"\
"A hidden doorway opens and you enter.\n"\
"You've proven too tough for Hell to\n"\
"contain, and now Hell at last plays\n"\
"fair -- for you emerge from the door\n"\
"to see the green fields of Earth!\n"\
"Home at last.\n" \
"\n"\
"You wonder what's been happening on\n"\
"Earth while you were battling evil\n"\
"unleashed. It's good that no Hell-\n"\
"spawn could have come through that\n"\
"door with you ..."
*/

1040
Heretic Source/D_MAIN.C Normal file

File diff suppressed because it is too large Load Diff

784
Heretic Source/D_NET.C Normal file
View File

@ -0,0 +1,784 @@
// d_net.c
// This version has the fixed ticdup code
#include "DoomDef.h"
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000
#define NCMD_SETUP 0x20000000
#define NCMD_KILL 0x10000000 // kill game
#define NCMD_CHECKSUM 0x0fffffff
doomcom_t *doomcom;
doomdata_t *netbuffer; // points inside doomcom
/*
==============================================================================
NETWORKING
gametic is the tic about to (or currently being) run
maketic is the tick that hasn't had control made for it yet
nettics[] has the maketics for all players
a gametic cannot be run until nettics[] > gametic for all players
==============================================================================
*/
#define RESENDCOUNT 10
#define PL_DRONE 0x80 // bit flag in doomdata->player
ticcmd_t localcmds[BACKUPTICS];
ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
int nettics[MAXNETNODES];
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
boolean remoteresend[MAXNETNODES]; // set when local needs tics
int resendto[MAXNETNODES]; // set when remote needs tics
int resendcount[MAXNETNODES];
int nodeforplayer[MAXPLAYERS];
int maketic;
int lastnettic, skiptics;
int ticdup;
int maxsend; // BACKUPTICS/(2*ticdup)-1
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t *cmd);
void D_DoAdvanceDemo (void);
boolean reboundpacket;
doomdata_t reboundstore;
int NetbufferSize (void)
{
return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
}
unsigned NetbufferChecksum (void)
{
unsigned c;
int i,l;
c = 0x1234567;
#if defined(NeXT) || defined(NORMALUNIX)
return 0; // byte order problems
#endif
l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
for (i=0 ; i<l ; i++)
c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
return c & NCMD_CHECKSUM;
}
int ExpandTics (int low)
{
int delta;
delta = low - (maketic&0xff);
if (delta >= -64 && delta <= 64)
return (maketic&~0xff) + low;
if (delta > 64)
return (maketic&~0xff) - 256 + low;
if (delta < -64)
return (maketic&~0xff) + 256 + low;
I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
return 0;
}
//============================================================================
/*
==============
=
= HSendPacket
=
==============
*/
void HSendPacket (int node, int flags)
{
netbuffer->checksum = NetbufferChecksum () | flags;
if (!node)
{
reboundstore = *netbuffer;
reboundpacket = true;
return;
}
if (demoplayback)
return;
if (!netgame)
I_Error ("Tried to transmit to another node");
doomcom->command = CMD_SEND;
doomcom->remotenode = node;
doomcom->datalength = NetbufferSize ();
if (debugfile)
{
int i;
int realretrans;
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"send (%i + %i, R %i) [%i] "
,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
I_NetCmd ();
}
/*
==============
=
= HGetPacket
=
= Returns false if no packet is waiting
=
==============
*/
boolean HGetPacket (void)
{
if (reboundpacket)
{
*netbuffer = reboundstore;
doomcom->remotenode = 0;
reboundpacket = false;
return true;
}
if (!netgame)
return false;
if (demoplayback)
return false;
doomcom->command = CMD_GET;
I_NetCmd ();
if (doomcom->remotenode == -1)
return false;
if (doomcom->datalength != NetbufferSize ())
{
if (debugfile)
fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
return false;
}
if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
{
if (debugfile)
fprintf (debugfile,"bad packet checksum\n");
return false;
}
if (debugfile)
{
int realretrans;
int i;
if (netbuffer->checksum & NCMD_SETUP)
fprintf (debugfile,"setup packet\n");
else
{
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
}
return true;
}
/*
===================
=
= GetPackets
=
===================
*/
char exitmsg[80];
void GetPackets (void)
{
int netconsole;
int netnode;
ticcmd_t *src, *dest;
int realend;
int realstart;
while (HGetPacket ())
{
if (netbuffer->checksum & NCMD_SETUP)
continue; // extra setup packet
netconsole = netbuffer->player & ~PL_DRONE;
netnode = doomcom->remotenode;
//
// to save bytes, only the low byte of tic numbers are sent
// Figure out what the rest of the bytes are
//
realstart = ExpandTics (netbuffer->starttic);
realend = (realstart+netbuffer->numtics);
//
// check for exiting the game
//
if (netbuffer->checksum & NCMD_EXIT)
{
if (!nodeingame[netnode])
continue;
nodeingame[netnode] = false;
playeringame[netconsole] = false;
strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
exitmsg[7] += netconsole;
players[consoleplayer].message = exitmsg;
// if (demorecording)
// G_CheckDemoStatus ();
continue;
}
//
// check for a remote game kill
//
if (netbuffer->checksum & NCMD_KILL)
I_Error ("Killed by network driver");
nodeforplayer[netconsole] = netnode;
//
// check for retransmit request
//
if ( resendcount[netnode] <= 0
&& (netbuffer->checksum & NCMD_RETRANSMIT) )
{
resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
if (debugfile)
fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
resendcount[netnode] = RESENDCOUNT;
}
else
resendcount[netnode]--;
//
// check for out of order / duplicated packet
//
if (realend == nettics[netnode])
continue;
if (realend < nettics[netnode])
{
if (debugfile)
fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
continue;
}
//
// check for a missed packet
//
if (realstart > nettics[netnode])
{
// stop processing until the other system resends the missed tics
if (debugfile)
fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
remoteresend[netnode] = true;
continue;
}
//
// update command store from the packet
//
{
int start;
remoteresend[netnode] = false;
start = nettics[netnode] - realstart;
src = &netbuffer->cmds[start];
while (nettics[netnode] < realend)
{
dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
nettics[netnode]++;
*dest = *src;
src++;
}
}
}
}
/*
=============
=
= NetUpdate
=
= Builds ticcmds for console player
= sends out a packet
=============
*/
int gametime;
void NetUpdate (void)
{
int nowtime;
int newtics;
int i,j;
int realstart;
int gameticdiv;
//
// check time
//
nowtime = I_GetTime ()/ticdup;
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
goto listen;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
netbuffer->player = consoleplayer;
//
// build new ticcmds for console player
//
gameticdiv = gametic/ticdup;
for (i=0 ; i<newtics ; i++)
{
I_StartTic ();
D_ProcessEvents ();
if (maketic - gameticdiv >= BACKUPTICS/2-1)
break; // can't hold any more
//printf ("mk:%i ",maketic);
G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
maketic++;
}
if (singletics)
return; // singletic update is syncronous
//
// send the packet to the other nodes
//
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
netbuffer->starttic = realstart = resendto[i];
netbuffer->numtics = maketic - realstart;
if (netbuffer->numtics > BACKUPTICS)
I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
resendto[i] = maketic - doomcom->extratics;
for (j=0 ; j< netbuffer->numtics ; j++)
netbuffer->cmds[j] =
localcmds[(realstart+j)%BACKUPTICS];
if (remoteresend[i])
{
netbuffer->retransmitfrom = nettics[i];
HSendPacket (i, NCMD_RETRANSMIT);
}
else
{
netbuffer->retransmitfrom = 0;
HSendPacket (i, 0);
}
}
//
// listen for other packets
//
listen:
GetPackets ();
}
/*
=====================
=
= CheckAbort
=
=====================
*/
void CheckAbort (void)
{
event_t *ev;
int stoptic;
stoptic = I_GetTime () + 2;
while (I_GetTime() < stoptic)
I_StartTic ();
I_StartTic ();
for ( ; eventtail != eventhead
; eventtail = (++eventtail)&(MAXEVENTS-1) )
{
ev = &events[eventtail];
if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
I_Error ("Network game synchronization aborted.");
}
}
/*
=====================
=
= D_ArbitrateNetStart
=
=====================
*/
void D_ArbitrateNetStart (void)
{
int i;
boolean gotinfo[MAXNETNODES];
autostart = true;
memset (gotinfo,0,sizeof(gotinfo));
if (doomcom->consoleplayer)
{ // listen for setup info from key player
// mprintf ("listening for network start info...\n");
while (1)
{
CheckAbort ();
if (!HGetPacket ())
continue;
if (netbuffer->checksum & NCMD_SETUP)
{
if (netbuffer->player != VERSION)
I_Error ("Different DOOM versions cannot play a net game!");
startskill = netbuffer->retransmitfrom & 15;
deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
//startmap = netbuffer->starttic & 0x3f;
//startepisode = netbuffer->starttic >> 6;
startmap = netbuffer->starttic&15;
startepisode = netbuffer->starttic>>4;
return;
}
}
}
else
{ // key player, send the setup info
// mprintf ("sending network start info...\n");
do
{
CheckAbort ();
for (i=0 ; i<doomcom->numnodes ; i++)
{
netbuffer->retransmitfrom = startskill;
if (deathmatch)
netbuffer->retransmitfrom |= (deathmatch<<6);
if (nomonsters)
netbuffer->retransmitfrom |= 0x20;
if (respawnparm)
netbuffer->retransmitfrom |= 0x10;
//netbuffer->starttic = startepisode * 64 + startmap;
netbuffer->starttic = (startepisode<<4)+startmap;
netbuffer->player = VERSION;
netbuffer->numtics = 0;
HSendPacket (i, NCMD_SETUP);
}
#if 1
for(i = 10 ; i && HGetPacket(); --i)
{
if((netbuffer->player&0x7f) < MAXNETNODES)
gotinfo[netbuffer->player&0x7f] = true;
}
#else
while (HGetPacket ())
{
gotinfo[netbuffer->player&0x7f] = true;
}
#endif
for (i=1 ; i<doomcom->numnodes ; i++)
if (!gotinfo[i])
break;
} while (i < doomcom->numnodes);
}
}
/*
===================
=
= D_CheckNetGame
=
= Works out player numbers among the net participants
===================
*/
extern int viewangleoffset;
void D_CheckNetGame (void)
{
int i;
for (i=0 ; i<MAXNETNODES ; i++)
{
nodeingame[i] = false;
nettics[i] = 0;
remoteresend[i] = false; // set when local needs tics
resendto[i] = 0; // which tic to start sending
}
// I_InitNetwork sets doomcom and netgame
I_InitNetwork ();
if (doomcom->id != DOOMCOM_ID)
I_Error ("Doomcom buffer invalid!");
netbuffer = &doomcom->data;
consoleplayer = displayplayer = doomcom->consoleplayer;
if (netgame)
D_ArbitrateNetStart ();
//printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
// read values out of doomcom
ticdup = doomcom->ticdup;
maxsend = BACKUPTICS/(2*ticdup)-1;
if (maxsend<1)
maxsend = 1;
for (i=0 ; i<doomcom->numplayers ; i++)
playeringame[i] = true;
for (i=0 ; i<doomcom->numnodes ; i++)
nodeingame[i] = true;
//printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
}
/*
==================
=
= D_QuitNetGame
=
= Called before quitting to leave a net game without hanging the
= other players
=
==================
*/
void D_QuitNetGame (void)
{
int i, j;
if (debugfile)
fclose (debugfile);
if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
return;
// send a bunch of packets for security
netbuffer->player = consoleplayer;
netbuffer->numtics = 0;
for (i=0 ; i<4 ; i++)
{
for (j=1 ; j<doomcom->numnodes ; j++)
if (nodeingame[j])
HSendPacket (j, NCMD_EXIT);
I_WaitVBL (1);
}
}
/*
===============
=
= TryRunTics
=
===============
*/
int frametics[4], frameon;
int frameskip[4];
int oldnettics;
extern boolean advancedemo;
void TryRunTics (void)
{
int i;
int lowtic;
int entertic;
static int oldentertics;
int realtics, availabletics;
int counts;
int numplaying;
//
// get real tics
//
entertic = I_GetTime ()/ticdup;
realtics = entertic - oldentertics;
oldentertics = entertic;
//
// get available tics
//
NetUpdate ();
lowtic = MAXINT;
numplaying = 0;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
numplaying++;
if (nettics[i] < lowtic)
lowtic = nettics[i];
}
availabletics = lowtic - gametic/ticdup;
//
// decide how many tics to run
//
if (realtics < availabletics-1)
counts = realtics+1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
frameon++;
if (debugfile)
fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
if (!demoplayback)
{
//=============================================================================
//
// ideally nettics[0] should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
//
for (i=0 ; i<MAXPLAYERS ; i++)
if (playeringame[i])
break;
if (consoleplayer == i)
{ // the key player does not adapt
}
else
{
if (nettics[0] <= nettics[nodeforplayer[i]])
{
gametime--;
// printf ("-");
}
frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
oldnettics = nettics[0];
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
// printf ("+");
}
}
//=============================================================================
} // demoplayback
//
// wait for new tics if needed
//
while (lowtic < gametic/ticdup + counts)
{
NetUpdate ();
lowtic = MAXINT;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i] && nettics[i] < lowtic)
lowtic = nettics[i];
if (lowtic < gametic/ticdup)
I_Error ("TryRunTics: lowtic < gametic");
// don't stay in here forever -- give the menu a chance to work
if (I_GetTime ()/ticdup - entertic >= 20)
{
MN_Ticker ();
return;
}
}
//
// run the count * ticdup dics
//
while (counts--)
{
for (i=0 ; i<ticdup ; i++)
{
if (gametic/ticdup > lowtic)
I_Error ("gametic>lowtic");
if (advancedemo)
D_DoAdvanceDemo ();
MN_Ticker ();
G_Ticker ();
gametic++;
//
// modify command for duplicated tics
//
if (i != ticdup-1)
{
ticcmd_t *cmd;
int buf;
int j;
buf = (gametic/ticdup)%BACKUPTICS;
for (j=0 ; j<MAXPLAYERS ; j++)
{
cmd = &netcmds[j][buf];
cmd->chatchar = 0;
if (cmd->buttons & BT_SPECIAL)
cmd->buttons = 0;
}
}
}
NetUpdate (); // check for new console commands
}
}

797
Heretic Source/D_NETBAK.C Normal file
View File

@ -0,0 +1,797 @@
// I_pcnet.m
//
// Modified 12-21-94 by Chris Rhinehart for use with multiple ticdups
// actually, it wasn't modified, but rather we are currently using this
// older version of D_NET.C, since the new one doesn't seem to work with
// ticdup set to greater than one.
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000
#define NCMD_SETUP 0x20000000
#define NCMD_CHECKSUM 0x0fffffff
/*
if more space needs to be crunched out of the protocol...
1 drone
2 player
8 tic
5 numtics
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000 // a retransmit will have 0 tics
#define NCMD_DRONE 0x20000000
#define NCMD_PLAYER 0x18000000
#define NCMD_PLAYERSHIFT 27
#define NCMD_TIC 0x00ff0000
#define NCMD_TICSHIFT 16
#define NCMD_NUMTICS 0x0000ff00
#define NCMD_NUMTICSSHIFT 8
#define NCMD_CHECKSUM 0x000000ff
*/
doomcom_t *doomcom;
doomdata_t *netbuffer; // points inside doomcom
/*
==============================================================================
NETWORKING
gametic is the tic about to (or currently being) run
maketic is the tick that hasn't had control made for it yet
nettics[] has the maketics for all players
a gametic cannot be run until nettics[] > gametic for all players
==============================================================================
*/
#define RESENDCOUNT 10
#define PL_DRONE 0x80 // bit flag in doomdata->player
ticcmd_t localcmds[BACKUPTICS];
ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
int nettics[MAXNETNODES];
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
boolean remoteresend[MAXNETNODES]; // set when local needs tics
int resendto[MAXNETNODES]; // set when remote needs tics
int resendcount[MAXNETNODES];
int nodeforplayer[MAXPLAYERS];
int gametime;
int maketic;
int lastnettic, skiptics;
int ticdup;
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t *cmd);
void D_DoAdvanceDemo (void);
boolean reboundpacket;
doomdata_t reboundstore;
int NetbufferSize (void)
{
return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
}
unsigned NetbufferChecksum (void)
{
unsigned c;
int i,l;
c = 0x1234567;
l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
for (i=0 ; i<l ; i++)
c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
return c & NCMD_CHECKSUM;
}
int ExpandTics (int low)
{
int delta;
delta = low - (maketic&0xff);
if (delta >= -64 && delta <= 64)
return (maketic&~0xff) + low;
if (delta > 64)
return (maketic&~0xff) - 256 + low;
if (delta < -64)
return (maketic&~0xff) + 256 + low;
I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
return 0;
}
//============================================================================
/*
==============
=
= HSendPacket
=
==============
*/
void HSendPacket (int node, int flags)
{
netbuffer->checksum = NetbufferChecksum () | flags;
if (!node)
{
reboundstore = *netbuffer;
reboundpacket = true;
return;
}
if (!netgame)
I_Error ("Tried to transmit to another node");
doomcom->command = CMD_SEND;
doomcom->remotenode = node;
doomcom->datalength = NetbufferSize ();
if (debugfile)
{
int i;
int realretrans;
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"send (%i + %i, R %i) [%i] "
,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
I_NetCmd ();
}
/*
==============
=
= HGetPacket
=
= Returns false if no packet is waiting
=
==============
*/
boolean HGetPacket (void)
{
if (reboundpacket)
{
*netbuffer = reboundstore;
doomcom->remotenode = 0;
reboundpacket = false;
return true;
}
if (!netgame)
return false;
doomcom->command = CMD_GET;
I_NetCmd ();
if (doomcom->remotenode == -1)
return false;
if (doomcom->datalength != NetbufferSize ())
{
if (debugfile)
fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
return false;
}
if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
{
if (debugfile)
fprintf (debugfile,"bad packet checksum\n");
return false;
}
if (debugfile)
{
int realretrans;
int i;
if (netbuffer->checksum & NCMD_SETUP)
fprintf (debugfile,"setup packet\n");
else
{
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
}
return true;
}
/*
===================
=
= GetPackets
=
===================
*/
char exitmsg[80];
void GetPackets (void)
{
int netconsole;
int netnode;
int netdrone;
int j;
ticcmd_t *src, *dest;
int dupedstart, dupedend;
int skiptics;
int realstart;
while (HGetPacket ())
{
if (netbuffer->checksum & NCMD_SETUP)
continue; // extra setup packet
netdrone = netbuffer->player & PL_DRONE;
netconsole = netbuffer->player & ~PL_DRONE;
netnode = doomcom->remotenode;
//
// to save bytes, only the low byte of tic numbers are sent
// Figure out what the rest of the bytes are
//
realstart = ExpandTics (netbuffer->starttic);
dupedstart = realstart*doomcom->ticdup;
dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
//
// check for exiting the game
//
if (netbuffer->checksum & NCMD_EXIT)
{
if (!nodeingame[netnode])
continue;
nodeingame[netnode] = false;
if (!netdrone)
{
playeringame[netconsole] = false;
strcpy (exitmsg, "PLAYER 1 HAS LEFT THE GAME");
exitmsg[7] += netconsole;
P_SetMessage(&players[consoleplayer], exitmsg, true);
UpdateState |= I_MESSAGES;
S_StartSound(NULL, sfx_chat);
}
continue;
}
//
// drone packets are just notifications
//
if (netdrone)
{
nettics[netnode] = dupedend;
continue;
}
nodeforplayer[netconsole] = netnode;
//
// check for retransmit request
//
if ( resendcount[netnode] <= 0
&& (netbuffer->checksum & NCMD_RETRANSMIT) )
{
resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
if (debugfile)
fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
resendcount[netnode] = RESENDCOUNT;
}
else
resendcount[netnode]--;
//
// check for out of order / duplicated packet
//
if (dupedend == nettics[netnode])
continue;
if (dupedend < nettics[netnode])
{
if (debugfile)
fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
continue;
}
//
// check for a missed packet
//
if (dupedstart > nettics[netnode])
{
// stop processing until the other system resends the missed tics
if (debugfile)
fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
remoteresend[netnode] = true;
continue;
}
//
// update command store from the packet
//
remoteresend[netnode] = false;
skiptics = nettics[netnode]/doomcom->ticdup - realstart;
src = &netbuffer->cmds[skiptics];
while (nettics[netnode] < dupedend)
{
for (j=0 ; j<doomcom->ticdup ; j++)
{
dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
nettics[netnode]++;
*dest = *src;
src->chatchar = 0;
if (src->buttons & BT_SPECIAL)
src->buttons = 0;
}
src++;
}
}
}
/*
=============
=
= NetUpdate
=
= Builds ticcmds for console player
= sends out a packet
=============
*/
void NetUpdate (void)
{
int nowtime;
int newtics;
int i,j;
int gameticdiv;
int realstart;
if (singletics)
return; // singletic update is syncronous
//
// check time
//
nowtime = I_GetTime ()/doomcom->ticdup;
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
goto listen;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
netbuffer->player = consoleplayer;
if (doomcom->drone)
netbuffer->player |= PL_DRONE;
//
// drone packets
//
if (doomcom->drone)
{
I_StartTic ();
D_ProcessEvents ();
goto sendit;
}
//
// build new ticcmds for console player
//
gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
for (i=0 ; i<newtics ; i++)
{
I_StartTic ();
D_ProcessEvents ();
if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
{
newtics = i;
break; // can't hold any more
}
//printf ("mk:%i ",maketic);
G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
maketic++;
}
//
// send the packet to the other nodes
//
sendit:
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
if (doomcom->drone)
{
netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
netbuffer->numtics = 0;
}
else
{
netbuffer->starttic = realstart = resendto[i];
netbuffer->numtics = maketic - realstart;
resendto[i] = maketic - doomcom->extratics;
}
if (netbuffer->numtics > BACKUPTICS)
I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
for (j=0 ; j< netbuffer->numtics ; j++)
netbuffer->cmds[j] =
localcmds[(realstart+j)%BACKUPTICS];
if (remoteresend[i])
{
netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
HSendPacket (i, NCMD_RETRANSMIT);
}
else
{
netbuffer->retransmitfrom = 0;
HSendPacket (i, 0);
}
}
//
// listen for other packets
//
listen:
GetPackets ();
}
/*
=====================
=
= CheckAbort
=
=====================
*/
void CheckAbort (void)
{
event_t *ev;
I_WaitVBL(2);
I_StartTic ();
for ( ; eventtail != eventhead
; eventtail = (++eventtail)&(MAXEVENTS-1) )
{
ev = &events[eventtail];
if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
I_Error ("Network game synchronization aborted.");
}
}
/*
=====================
=
= D_ArbitrateNetStart
=
=====================
*/
void D_ArbitrateNetStart (void)
{
int i;
boolean gotinfo[MAXNETNODES];
autostart = true;
memset (gotinfo,0,sizeof(gotinfo));
if (doomcom->consoleplayer)
{ // listen for setup info from key player
//printf ("listening for network start info...\n");
while (1)
{
CheckAbort ();
if (!HGetPacket ())
continue;
if (netbuffer->checksum & NCMD_SETUP)
{
if (netbuffer->player != VERSION)
I_Error ("Different HERETIC versions cannot play a net game!");
startskill = netbuffer->retransmitfrom & 15;
deathmatch = (netbuffer->retransmitfrom & 0x80) > 0;
startmap = netbuffer->starttic & 15;
startepisode = netbuffer->starttic >> 4;
return;
}
}
}
else
{ // key player, send the setup info
// printf ("sending network start info...\n");
do
{
CheckAbort ();
for (i=0 ; i<doomcom->numnodes ; i++)
{
netbuffer->retransmitfrom = startskill;
if (deathmatch)
netbuffer->retransmitfrom |= 0x80;
netbuffer->starttic = startepisode * 16 + startmap;
netbuffer->player = VERSION;
netbuffer->numtics = 0;
HSendPacket (i, NCMD_SETUP);
}
while (HGetPacket ())
{
//printf ("got packet\n");
gotinfo[netbuffer->player&0x7f] = true;
}
for (i=1 ; i<doomcom->numnodes ; i++)
if (!gotinfo[i])
break;
} while (i < doomcom->numnodes);
}
}
/*
===================
=
= D_CheckNetGame
=
= Works out player numbers among the net participants
===================
*/
extern int viewangleoffset;
void D_CheckNetGame (void)
{
int i;
for (i=0 ; i<MAXNETNODES ; i++)
{
nodeingame[i] = false;
nettics[i] = 0;
remoteresend[i] = false; // set when local needs tics
resendto[i] = 0; // which tic to start sending
}
// I_InitNetwork sets doomcom and netgame
I_InitNetwork ();
if (doomcom->id != DOOMCOM_ID)
I_Error ("Doomcom buffer invalid!");
netbuffer = &doomcom->data;
consoleplayer = displayplayer = doomcom->consoleplayer;
if (netgame)
D_ArbitrateNetStart ();
//printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
// read values out of doomcom
ticdup = doomcom->ticdup;
for (i=0 ; i<doomcom->numplayers ; i++)
playeringame[i] = true;
for (i=0 ; i<doomcom->numnodes ; i++)
nodeingame[i] = true;
//printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
}
/*
==================
=
= D_QuitNetGame
=
= Called before quitting to leave a net game without hanging the
= other players
=
==================
*/
void D_QuitNetGame (void)
{
int i, j;
if (debugfile)
fclose (debugfile);
if (!netgame || !usergame || consoleplayer == -1)
return;
// send a bunch of packets for security
netbuffer->player = consoleplayer;
if (doomcom->drone)
netbuffer->player |= PL_DRONE;
netbuffer->numtics = 0;
for (i=0 ; i<4 ; i++)
{
for (j=1 ; j<doomcom->numnodes ; j++)
if (nodeingame[j])
HSendPacket (j, NCMD_EXIT);
I_WaitVBL (1);
}
}
/*
===============
=
= TryRunTics
=
===============
*/
int frametics[4], frameon;
int frameskip[4];
int oldnettics;
extern boolean advancedemo;
void TryRunTics (void)
{
int i;
int lowtic, nextlowest;
int entertic;
int static oldentertics;
int realtics, availabletics;
int counts;
int numplaying;
//
// get real tics
//
entertic = I_GetTime ();
realtics = entertic - oldentertics;
oldentertics = entertic;
//
// get available tics
//
NetUpdate ();
lowtic = nextlowest = MAXINT;
numplaying = 0;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
numplaying++;
if (nettics[i] < lowtic)
{
nextlowest = lowtic;
lowtic = nettics[i];
}
else if (nettics[i] < nextlowest)
nextlowest = nettics[i];
}
availabletics = lowtic - gametic;
//
// decide how many tics to run
//
if (realtics < availabletics-1)
counts = realtics+1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
frameon++;
if (debugfile)
fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
//=============================================================================
//
// ideally nettics[0] should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
// drones should never hold up the other players
//
for (i=0 ; i<MAXPLAYERS ; i++)
if (playeringame[i])
break;
if (consoleplayer == i)
{ // the key player does not adapt
}
else
{
if (nettics[0] <= nettics[nodeforplayer[i]])
{
gametime--;
// printf ("-");
}
frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
oldnettics = nettics[0];
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
// printf ("+");
}
}
//=============================================================================
//
// wait for new tics if needed
//
while (lowtic < gametic + counts)
{
NetUpdate ();
lowtic = MAXINT;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i] && nettics[i] < lowtic)
lowtic = nettics[i];
if (lowtic < gametic)
I_Error ("TryRunTics: lowtic < gametic");
// don't stay in here forever -- give the menu a chance to work
if (I_GetTime () - entertic >= 20)
{
MN_Ticker ();
return;
}
}
//
// run the tics
//
while (counts--)
{
if (advancedemo)
D_DoAdvanceDemo ();
MN_Ticker ();
G_Ticker ();
NetUpdate (); // check for new console commands
gametic++;
}
}

452
Heretic Source/F_FINALE.C Normal file
View File

@ -0,0 +1,452 @@
// F_finale.c
#include "DoomDef.h"
#include "soundst.h"
#include <ctype.h>
int finalestage; // 0 = text, 1 = art screen
int finalecount;
#define TEXTSPEED 3
#define TEXTWAIT 250
char *e1text = E1TEXT;
char *e2text = E2TEXT;
char *e3text = E3TEXT;
char *e4text = E4TEXT;
char *e5text = E5TEXT;
char *finaletext;
char *finaleflat;
int FontABaseLump;
extern boolean automapactive;
extern boolean viewactive;
extern void D_StartTitle(void);
/*
=======================
=
= F_StartFinale
=
=======================
*/
void F_StartFinale (void)
{
gameaction = ga_nothing;
gamestate = GS_FINALE;
viewactive = false;
automapactive = false;
players[consoleplayer].messageTics = 1;
players[consoleplayer].message = NULL;
switch(gameepisode)
{
case 1:
finaleflat = "FLOOR25";
finaletext = e1text;
break;
case 2:
finaleflat = "FLATHUH1";
finaletext = e2text;
break;
case 3:
finaleflat = "FLTWAWA2";
finaletext = e3text;
break;
case 4:
finaleflat = "FLOOR28";
finaletext = e4text;
break;
case 5:
finaleflat = "FLOOR08";
finaletext = e5text;
break;
}
finalestage = 0;
finalecount = 0;
FontABaseLump = W_GetNumForName("FONTA_S")+1;
// S_ChangeMusic(mus_victor, true);
S_StartSong(mus_cptd, true);
}
boolean F_Responder (event_t *event)
{
if(event->type != ev_keydown)
{
return false;
}
if(finalestage == 1 && gameepisode == 2)
{ // we're showing the water pic, make any key kick to demo mode
finalestage++;
memset((byte *)0xa0000, 0, SCREENWIDTH*SCREENHEIGHT);
memset(screen, 0, SCREENWIDTH*SCREENHEIGHT);
I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
return true;
}
return false;
}
/*
=======================
=
= F_Ticker
=
=======================
*/
void F_Ticker (void)
{
finalecount++;
if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
{
finalecount = 0;
if(!finalestage)
{
finalestage = 1;
}
// wipegamestate = -1; // force a wipe
/*
if (gameepisode == 3)
S_StartMusic (mus_bunny);
*/
}
}
/*
=======================
=
= F_TextWrite
=
=======================
*/
//#include "HU_stuff.h"
//extern patch_t *hu_font[HU_FONTSIZE];
void F_TextWrite (void)
{
byte *src, *dest;
int x,y;
int count;
char *ch;
int c;
int cx, cy;
patch_t *w;
//
// erase the entire screen to a tiled background
//
src = W_CacheLumpName(finaleflat, PU_CACHE);
dest = screen;
for (y=0 ; y<SCREENHEIGHT ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
// V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
//
// draw some of the text onto the screen
//
cx = 20;
cy = 5;
ch = finaletext;
count = (finalecount - 10)/TEXTSPEED;
if (count < 0)
count = 0;
for ( ; count ; count-- )
{
c = *ch++;
if (!c)
break;
if (c == '\n')
{
cx = 20;
cy += 9;
continue;
}
c = toupper(c);
if (c < 33)
{
cx += 5;
continue;
}
w = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
if (cx+w->width > SCREENWIDTH)
break;
V_DrawPatch(cx, cy, w);
cx += w->width;
}
}
#if 0
/*
=======================
=
= F_Cast
=
=======================
*/
void F_Cast (void)
{
byte *src, *dest;
int x,y,w;
int count;
char *ch;
int c;
int cx, cy;
//
// erase the entire screen to a tiled background
//
src = W_CacheLumpName ( "FWATER1" , PU_CACHE);
dest = screen;
for (y=0 ; y<SCREENHEIGHT ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
V_DrawPatch (105,21,0, W_CacheLumpName ( "
}
#endif
void F_DrawPatchCol (int x, patch_t *patch, int col)
{
column_t *column;
byte *source, *dest, *desttop;
int count;
column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
desttop = screen+x;
// step through the posts in a column
while (column->topdelta != 0xff )
{
source = (byte *)column + 3;
dest = desttop + column->topdelta*SCREENWIDTH;
count = column->length;
while (count--)
{
*dest = *source++;
dest += SCREENWIDTH;
}
column = (column_t *)( (byte *)column + column->length+ 4 );
}
}
/*
==================
=
= F_DemonScroll
=
==================
*/
void F_DemonScroll(void)
{
byte *p1, *p2;
static int yval = 0;
static int nextscroll = 0;
if(finalecount < nextscroll)
{
return;
}
p1 = W_CacheLumpName("FINAL1", PU_LEVEL);
p2 = W_CacheLumpName("FINAL2", PU_LEVEL);
if(finalecount < 70)
{
memcpy(screen, p1, SCREENHEIGHT*SCREENWIDTH);
nextscroll = finalecount;
return;
}
if(yval < 64000)
{
memcpy(screen, p2+SCREENHEIGHT*SCREENWIDTH-yval, yval);
memcpy(screen+yval, p1, SCREENHEIGHT*SCREENWIDTH-yval);
yval += SCREENWIDTH;
nextscroll = finalecount+3;
}
else
{ //else, we'll just sit here and wait, for now
memcpy(screen, p2, SCREENWIDTH*SCREENHEIGHT);
}
}
/*
==================
=
= F_DrawUnderwater
=
==================
*/
void F_DrawUnderwater(void)
{
static boolean underwawa;
extern boolean MenuActive;
extern boolean askforquit;
switch(finalestage)
{
case 1:
if(!underwawa)
{
underwawa = true;
memset((byte *)0xa0000, 0, SCREENWIDTH*SCREENHEIGHT);
I_SetPalette(W_CacheLumpName("E2PAL", PU_CACHE));
memcpy(screen, W_CacheLumpName("E2END", PU_CACHE),
SCREENWIDTH*SCREENHEIGHT);
}
paused = false;
MenuActive = false;
askforquit = false;
break;
case 2:
memcpy(screen, W_CacheLumpName("TITLE", PU_CACHE),
SCREENWIDTH*SCREENHEIGHT);
//D_StartTitle(); // go to intro/demo mode.
}
}
#if 0
/*
==================
=
= F_BunnyScroll
=
==================
*/
void F_BunnyScroll (void)
{
int scrolled, x;
patch_t *p1, *p2;
char name[10];
int stage;
static int laststage;
p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
scrolled = 320 - (finalecount-230)/2;
if (scrolled > 320)
scrolled = 320;
if (scrolled < 0)
scrolled = 0;
for ( x=0 ; x<SCREENWIDTH ; x++)
{
if (x+scrolled < 320)
F_DrawPatchCol (x, p1, x+scrolled);
else
F_DrawPatchCol (x, p2, x+scrolled - 320);
}
if (finalecount < 1130)
return;
if (finalecount < 1180)
{
V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName ("END0",PU_CACHE));
laststage = 0;
return;
}
stage = (finalecount-1180) / 5;
if (stage > 6)
stage = 6;
if (stage > laststage)
{
S_StartSound (NULL, sfx_pistol);
laststage = stage;
}
sprintf (name,"END%i",stage);
V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2, W_CacheLumpName (name,PU_CACHE));
}
#endif
/*
=======================
=
= F_Drawer
=
=======================
*/
void F_Drawer(void)
{
UpdateState |= I_FULLSCRN;
if (!finalestage)
F_TextWrite ();
else
{
switch (gameepisode)
{
case 1:
if(shareware)
{
V_DrawRawScreen(W_CacheLumpName("ORDER", PU_CACHE));
}
else
{
V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
}
break;
case 2:
F_DrawUnderwater();
break;
case 3:
F_DemonScroll();
break;
case 4: // Just show credits screen for extended episodes
case 5:
V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
break;
}
}
}

1952
Heretic Source/G_GAME.C Normal file

File diff suppressed because it is too large Load Diff

1819
Heretic Source/G_OLD.C Normal file

File diff suppressed because it is too large Load Diff

124
Heretic Source/H.BAT Normal file
View File

@ -0,0 +1,124 @@
@echo off
if "%1x"=="x" goto badargs
if "%2x"=="x" goto badargs
set hticargs=-noartiskip -warp %1 %2
set hticwads=-file
set hticnplay=
:parseloop
if "%3x"=="x" goto doneparse
if "%3"=="m" goto nomonsters
if "%3"=="M" goto nomonsters
if "%3"=="s1" goto skill1
if "%3"=="S1" goto skill1
if "%3"=="s2" goto skill2
if "%3"=="S2" goto skill2
if "%3"=="s3" goto skill3
if "%3"=="S3" goto skill3
if "%3"=="s4" goto skill4
if "%3"=="S4" goto skill4
if "%3"=="s5" goto skill5
if "%3"=="S5" goto skill5
if "%3"=="n1" goto nplay1
if "%3"=="N1" goto nplay1
if "%3"=="n2" goto nplay2
if "%3"=="N2" goto nplay2
if "%3"=="n3" goto nplay3
if "%3"=="N3" goto nplay3
if "%3"=="n4" goto nplay4
if "%3"=="N4" goto nplay4
if "%3"=="p" goto altport
if "%3"=="P" goto altport
goto addwad
:nomonsters
set hticargs=%hticargs% -nomonsters
shift
goto parseloop
:skill1
set hticargs=%hticargs% -skill 1
shift
goto parseloop
:skill2
set hticargs=%hticargs% -skill 2
shift
goto parseloop
:skill3
set hticargs=%hticargs% -skill 3
shift
goto parseloop
:skill4
set hticargs=%hticargs% -skill 4
shift
goto parseloop
:skill5
set hticargs=%hticargs% -skill 5
shift
goto parseloop
:nplay1
set hticnplay=1
shift
goto parseloop
:nplay2
set hticnplay=2
shift
goto parseloop
:nplay3
set hticnplay=3
shift
goto parseloop
:nplay4
set hticnplay=4
shift
goto parseloop
:altport
set hticargs=%hticargs% -port 3
shift
goto parseloop
:addwad
set hticwads=%hticwads% %3.wad
shift
goto parseloop
:badargs
echo Usage: H episode map [s?] [m] [n?] [p] [wadfile [wadfile ...] ]
echo.
echo [s?] = skill (1-5)
echo [m] = no monsters
echo [n?] = net play (1-4)
echo [p] = use alternate port setting
echo [wadfile] = add external wadfile (.WAD is implicit)
echo.
goto end
:doneparse
if"%hticwads%"=="-file" goto startgame
set hticargs=%hticargs% %hticwads%
:startgame
if"%hticnplay%x"=="x" goto normalplay
echo -nodes %hticnplay% -deathmatch %hticargs%
ipxsetup -nodes %hticnplay% -deathmatch %hticargs%
goto end
:normalplay
echo %hticargs%
heretic %hticargs%
goto end
:end
set hticargs=
set hticwads=
set hticnplay=

BIN
Heretic Source/HDEMO1.LMP Normal file

Binary file not shown.

BIN
Heretic Source/HDEMO2.LMP Normal file

Binary file not shown.

BIN
Heretic Source/HDEMO3.LMP Normal file

Binary file not shown.

View File

@ -0,0 +1,93 @@
/* Lint file for Heretic project */
//--------------------------------------------------------------------------
//
// OPTIONS
//
//--------------------------------------------------------------------------
// Use integer model for enumerations
//
+fie
// Allow ignoring return values
//
-e534
// Allow repeated include files
//
-e537
// Allow shifting signed quantities
//
-e701
-e702
// Allow more than 127 enumeration constants (ANSI limit)
//
-"esym(793,enumeration constants)"
// Don't complain about global macros that are not referenced
//
-e755
// Don't complain about global enumeration constants that are not
// referenced
//
-e769
// Don't complain about external symbols that could be made static
//
-e765
//--------------------------------------------------------------------------
//
// FILES
//
//--------------------------------------------------------------------------
i_ibm.c
i_cyber.c
i_sound.c
am_map.c
ct_chat.c
d_main.c
d_net.c
g_game.c
f_finale.c
info.c
in_lude.c
mn_menu.c
m_misc.c
p_ceilng.c
p_doors.c
p_enemy.c
p_floor.c
p_inter.c
p_lights.c
p_map.c
p_maputl.c
p_mobj.c
p_plats.c
p_pspr.c
p_setup.c
p_sight.c
p_spec.c
p_switch.c
p_telept.c
p_tick.c
p_user.c
r_bsp.c
r_data.c
r_draw.c
r_main.c
r_plane.c
r_segs.c
r_things.c
sb_bar.c
sounds.c
tables.c
v_video.c
w_wad.c
z_zone.c

5677
Heretic Source/INFO.C Normal file

File diff suppressed because it is too large Load Diff

1550
Heretic Source/INFO.H Normal file

File diff suppressed because it is too large Load Diff

1007
Heretic Source/IN_LUDE.C Normal file

File diff suppressed because it is too large Load Diff

997
Heretic Source/IN_LUDE.OLD Normal file
View File

@ -0,0 +1,997 @@
/*
========================
=
= IN_lude.c
=
========================
*/
#include "DoomDef.h"
#include "soundst.h"
typedef enum
{
SINGLE,
COOPERATIVE,
DEATHMATCH
} gametype_t;
// Public functions
void IN_Start(void);
void IN_Ticker(void);
void IN_Drawer(void);
boolean intermission;
// Private functions
void IN_WaitStop(void);
void IN_Stop(void);
void IN_LoadPics(void);
void IN_UnloadPics(void);
void IN_CheckForSkip(void);
void IN_InitStats(void);
void IN_InitDeathmatchStats(void);
void IN_InitNetgameStats(void);
void IN_DrawOldLevel(void);
void IN_DrawYAH(void);
void IN_DrawStatBack(void);
void IN_DrawSingleStats(void);
void IN_DrawCoopStats(void);
void IN_DrawDMStats(void);
void IN_DrawNumber(int val, int x, int y, int digits);
void IN_DrawTime(int x, int y, int h, int m, int s);
void IN_DrTextB(char *text, int x, int y);
static boolean skipintermission;
static int interstate = 0;
static int intertime = -1;
static int oldintertime = 0;
static gametype_t gametype;
static int cnt;
static int time;
static int hours;
static int minutes;
static int seconds;
static int slaughterboy; // in DM, the player with the most kills
static int killPercent[MAXPLAYERS];
static int bonusPercent[MAXPLAYERS];
static int secretPercent[MAXPLAYERS];
static patch_t *patchINTERPIC;
static patch_t *patchBEENTHERE;
static patch_t *patchGOINGTHERE;
static patch_t *FontBNumbers[10];
static patch_t *FontBNegative;
static patch_t *FontBSlash;
static patch_t *FontBPercent;
static int FontBLump;
static int FontBLumpBase;
static int patchFaceOkayBase;
static int patchFaceDeadBase;
static signed int totalFrags[MAXPLAYERS];
static fixed_t dSlideX[MAXPLAYERS];
static fixed_t dSlideY[MAXPLAYERS];
static char *KillersText[] = { "K", "I", "L", "L", "E", "R", "S" };
extern char *LevelNames[];
typedef struct
{
int x;
int y;
} yahpt_t;
static yahpt_t YAHspot[3][9] =
{
{
{ 172, 78 },
{ 86, 90 },
{ 73, 66 },
{ 159, 95 },
{ 148, 126 },
{ 132, 54 },
{ 131, 74 },
{ 208, 138 },
{ 52, 101 }
},
{
{ 218, 57 },
{ 137, 81 },
{ 155, 124 },
{ 171, 68 },
{ 250, 86 },
{ 136, 98 },
{ 203, 90 },
{ 220, 140 },
{ 279, 106 }
},
{
{ 86, 99 },
{ 124, 103 },
{ 154, 79 },
{ 202, 83 },
{ 178, 59 },
{ 142, 58 },
{ 219, 66 },
{ 247, 57 },
{ 107, 80 }
}
};
//========================================================================
//
// IN_Start
//
//========================================================================
extern void AM_Stop (void);
void IN_Start(void)
{
I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
IN_LoadPics();
IN_InitStats();
intermission = true;
interstate = -1;
skipintermission = false;
intertime = 0;
oldintertime = 0;
AM_Stop();
S_StartSong(mus_intr, true);
}
//========================================================================
//
// IN_WaitStop
//
//========================================================================
void IN_WaitStop(void)
{
if(!--cnt)
{
IN_Stop();
G_WorldDone();
}
}
//========================================================================
//
// IN_Stop
//
//========================================================================
void IN_Stop(void)
{
intermission = false;
IN_UnloadPics();
SB_state = -1;
BorderNeedRefresh = true;
}
//========================================================================
//
// IN_InitStats
//
// Initializes the stats for single player mode
//========================================================================
void IN_InitStats(void)
{
int i;
int j;
signed int slaughterfrags;
int posnum;
int slaughtercount;
int playercount;
if(!netgame)
{
gametype = SINGLE;
time = leveltime/35;
hours = time/3600;
time -= hours*3600;
minutes = time/60;
time -= minutes*60;
seconds = time;
}
else if(netgame && !deathmatch)
{
gametype = COOPERATIVE;
memset(killPercent, 0, MAXPLAYERS*sizeof(int));
memset(bonusPercent, 0, MAXPLAYERS*sizeof(int));
memset(secretPercent, 0, MAXPLAYERS*sizeof(int));
for(i=0; i<MAXPLAYERS; i++)
{
if(playeringame[i])
{
if(totalkills)
{
killPercent[i] = players[i].killcount*100/totalkills;
}
if(totalitems)
{
bonusPercent[i] = players[i].itemcount*100/totalitems;
}
if(totalsecret)
{
secretPercent[i] = players[i].secretcount*100/totalsecret;
}
}
}
}
else
{
gametype = DEATHMATCH;
slaughterboy = 0;
slaughterfrags = -9999;
posnum = 0;
playercount = 0;
slaughtercount = 0;
for(i=0; i<MAXPLAYERS; i++)
{
totalFrags[i] = 0;
if(playeringame[i])
{
playercount++;
for(j=0; j<MAXPLAYERS; j++)
{
if(playeringame[j])
{
totalFrags[i] += players[i].frags[j];
}
}
dSlideX[i] = (43*posnum*FRACUNIT)/20;
dSlideY[i] = (36*posnum*FRACUNIT)/20;
posnum++;
}
if(totalFrags[i] > slaughterfrags)
{
slaughterboy = 1<<i;
slaughterfrags = totalFrags[i];
slaughtercount = 1;
}
else if(totalFrags[i] == slaughterfrags)
{
slaughterboy |= 1<<i;
slaughtercount++;
}
}
if(playercount == slaughtercount)
{ // don't do the slaughter stuff if everyone is equal
slaughterboy = 0;
}
}
}
//========================================================================
//
// IN_LoadPics
//
//========================================================================
void IN_LoadPics(void)
{
int i;
switch(gameepisode)
{
case 1:
patchINTERPIC = W_CacheLumpName("MAPE1", PU_STATIC);
break;
case 2:
patchINTERPIC = W_CacheLumpName("MAPE2", PU_STATIC);
break;
case 3:
patchINTERPIC = W_CacheLumpName("MAPE3", PU_STATIC);
break;
default:
break;
}
patchBEENTHERE = W_CacheLumpName("IN_X", PU_STATIC);
patchGOINGTHERE = W_CacheLumpName("IN_YAH", PU_STATIC);
FontBLumpBase = W_GetNumForName("FONTB16");
for(i=0; i<10; i++)
{
FontBNumbers[i] = W_CacheLumpNum(FontBLumpBase+i, PU_STATIC);
}
FontBLump = W_GetNumForName("FONTB_S")+1;
FontBNegative = W_CacheLumpName("FONTB13", PU_STATIC);
FontBSlash = W_CacheLumpName("FONTB15", PU_STATIC);
FontBPercent = W_CacheLumpName("FONTB05", PU_STATIC);
patchFaceOkayBase = W_GetNumForName("FACEA0");
patchFaceDeadBase = W_GetNumForName("FACEB0");
}
//========================================================================
//
// IN_UnloadPics
//
//========================================================================
void IN_UnloadPics(void)
{
int i;
if(patchINTERPIC)
{
Z_ChangeTag(patchINTERPIC, PU_CACHE);
}
Z_ChangeTag(patchBEENTHERE, PU_CACHE);
Z_ChangeTag(patchGOINGTHERE, PU_CACHE);
for(i=0; i<10; i++)
{
Z_ChangeTag(FontBNumbers[i], PU_CACHE);
}
Z_ChangeTag(FontBNegative, PU_CACHE);
Z_ChangeTag(FontBSlash, PU_CACHE);
Z_ChangeTag(FontBPercent, PU_CACHE);
}
//========================================================================
//
// IN_Ticker
//
//========================================================================
void IN_Ticker(void)
{
if(!intermission)
{
return;
}
if(interstate == 3)
{
IN_WaitStop();
return;
}
IN_CheckForSkip();
intertime++;
if(oldintertime < intertime)
{
interstate++;
switch(interstate)
{
case 0:
oldintertime = intertime+300;
break;
case 1:
oldintertime = intertime+200;
break;
case 2:
oldintertime = MAXINT;
break;
case 3:
cnt = 10;
break;
default:
break;
}
}
if(skipintermission)
{
if(interstate == 0 && intertime < 150)
{
intertime = 150;
skipintermission = false;
return;
}
else if(interstate < 2 && gameepisode < 4)
{
interstate = 2;
skipintermission = false;
return;
}
interstate = 3;
cnt = 10;
skipintermission = false;
S_StartSound(NULL, sfx_dorcls);
}
}
//========================================================================
//
// IN_CheckForSkip
//
// Check to see if any player hit a key
//========================================================================
void IN_CheckForSkip(void)
{
int i;
player_t *player;
for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
{
if (playeringame[i])
{
if (player->cmd.buttons&BT_ATTACK)
{
if (!player->attackdown)
{
skipintermission = 1;
}
player->attackdown = true;
}
else
{
player->attackdown = false;
}
if (player->cmd.buttons&BT_USE)
{
if (!player->usedown)
{
skipintermission = 1;
}
player->usedown = true;
}
else
{
player->usedown = false;
}
}
}
}
//========================================================================
//
// IN_Drawer
//
//========================================================================
void IN_Drawer(void)
{
static int oldinterstate;
if(!intermission)
{
return;
}
if(interstate == 3)
{
return;
}
UpdateState |= I_FULLSCRN;
if(oldinterstate != 2 && interstate == 2)
{
S_StartSound(NULL, sfx_pstop);
}
oldinterstate = interstate;
switch(interstate)
{
case 0: // draw stats
IN_DrawStatBack();
switch(gametype)
{
case SINGLE:
IN_DrawSingleStats();
break;
case COOPERATIVE:
IN_DrawCoopStats();
break;
case DEATHMATCH:
IN_DrawDMStats();
break;
}
break;
case 1: // leaving old level
if(gameepisode < 4)
{
V_DrawPatch(0, 0, patchINTERPIC);
IN_DrawOldLevel();
}
break;
case 2: // going to the next level
if(gameepisode < 4)
{
V_DrawPatch(0, 0, patchINTERPIC);
IN_DrawYAH();
}
break;
case 3: // waiting before going to the next level
if(gameepisode < 4)
{
V_DrawPatch(0, 0, patchINTERPIC);
}
break;
default:
I_Error("IN_lude: Intermission state out of range.\n");
break;
}
}
//========================================================================
//
// IN_DrawStatBack
//
//========================================================================
void IN_DrawStatBack(void)
{
int x;
int y;
byte *src;
byte *dest;
src = W_CacheLumpName ("FLOOR16", PU_CACHE);
dest = screen;
for (y=0 ; y<SCREENHEIGHT ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
}
//========================================================================
//
// IN_DrawOldLevel
//
//========================================================================
void IN_DrawOldLevel(void)
{
int i;
int x;
x = 160-MN_TextBWidth(LevelNames[(gameepisode-1)*9+prevmap-1]+7)/2;
IN_DrTextB(LevelNames[(gameepisode-1)*9+prevmap-1]+7, x, 3);
x = 160-MN_TextAWidth("FINISHED")/2;
MN_DrTextA("FINISHED", x, 25);
if(prevmap == 9)
{
for(i=0; i<gamemap-1; i++)
{
V_DrawPatch(YAHspot[gameepisode-1][i].x, YAHspot[gameepisode-1][i].y,
patchBEENTHERE);
}
if(!(intertime&16))
{
V_DrawPatch(YAHspot[gameepisode-1][8].x, YAHspot[gameepisode-1][8].y,
patchBEENTHERE);
}
}
else
{
for(i=0; i<prevmap-1; i++)
{
V_DrawPatch(YAHspot[gameepisode-1][i].x, YAHspot[gameepisode-1][i].y,
patchBEENTHERE);
}
if(players[consoleplayer].didsecret)
{
V_DrawPatch(YAHspot[gameepisode-1][8].x, YAHspot[gameepisode-1][8].y,
patchBEENTHERE);
}
if(!(intertime&16))
{
V_DrawPatch(YAHspot[gameepisode-1][prevmap-1].x, YAHspot[gameepisode-1][prevmap-1].y,
patchBEENTHERE);
}
}
}
//========================================================================
//
// IN_DrawYAH
//
//========================================================================
void IN_DrawYAH(void)
{
int i;
int x;
x = 160-MN_TextAWidth("NOW ENTERING:")/2;
MN_DrTextA("NOW ENTERING:", x, 10);
x = 160-MN_TextBWidth(LevelNames[(gameepisode-1)*9+gamemap-1]+7)/2;
IN_DrTextB(LevelNames[(gameepisode-1)*9+gamemap-1]+7, x, 20);
if(prevmap == 9)
{
prevmap = gamemap-1;
}
for(i=0; i<prevmap; i++)
{
V_DrawPatch(YAHspot[gameepisode-1][i].x, YAHspot[gameepisode-1][i].y,
patchBEENTHERE);
}
if(players[consoleplayer].didsecret)
{
V_DrawPatch(YAHspot[gameepisode-1][8].x, YAHspot[gameepisode-1][8].y,
patchBEENTHERE);
}
if(!(intertime&16) || interstate == 3)
{ // draw the destination 'X'
V_DrawPatch(YAHspot[gameepisode-1][gamemap-1].x,
YAHspot[gameepisode-1][gamemap-1].y, patchGOINGTHERE);
}
}
//========================================================================
//
// IN_DrawSingleStats
//
//========================================================================
void IN_DrawSingleStats(void)
{
int x;
static int sounds;
IN_DrTextB("KILLS", 50, 65);
IN_DrTextB("ITEMS", 50, 90);
IN_DrTextB("SECRETS", 50, 115);
x = 160-MN_TextBWidth(LevelNames[(gameepisode-1)*9+prevmap-1]+7)/2;
IN_DrTextB(LevelNames[(gameepisode-1)*9+prevmap-1]+7, x, 3);
x = 160-MN_TextAWidth("FINISHED")/2;
MN_DrTextA("FINISHED", x, 25);
if(intertime < 30)
{
sounds = 0;
return;
}
if(sounds < 1 && intertime >= 30)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
IN_DrawNumber(players[consoleplayer].killcount, 200, 65, 3);
V_DrawShadowedPatch(237, 65, FontBSlash);
IN_DrawNumber(totalkills, 248, 65, 3);
if(intertime < 60)
{
return;
}
if(sounds < 2 && intertime >= 60)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
IN_DrawNumber(players[consoleplayer].itemcount, 200, 90, 3);
V_DrawShadowedPatch(237, 90, FontBSlash);
IN_DrawNumber(totalitems, 248, 90, 3);
if(intertime < 90)
{
return;
}
if(sounds < 3 && intertime >= 90)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
IN_DrawNumber(players[consoleplayer].secretcount, 200, 115, 3);
V_DrawShadowedPatch(237, 115, FontBSlash);
IN_DrawNumber(totalsecret, 248, 115, 3);
if(intertime < 150)
{
return;
}
if(sounds < 4 && intertime >= 150)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
if(!ExtendedWAD || gameepisode < 4)
{
IN_DrTextB("TIME", 85, 160);
IN_DrawTime(155, 160, hours, minutes, seconds);
}
else
{
x = 160-MN_TextAWidth("NOW ENTERING:")/2;
MN_DrTextA("NOW ENTERING:", x, 160);
x = 160-MN_TextBWidth(LevelNames[(gameepisode-1)*9+gamemap-1]+7)/2;
IN_DrTextB(LevelNames[(gameepisode-1)*9+gamemap-1]+7, x, 170);
skipintermission = false;
}
}
//========================================================================
//
// IN_DrawCoopStats
//
//========================================================================
void IN_DrawCoopStats(void)
{
int i;
int x;
int ypos;
static int sounds;
IN_DrTextB("KILLS", 95, 35);
IN_DrTextB("BONUS", 155, 35);
IN_DrTextB("SECRET", 232, 35);
x = 160-MN_TextBWidth(LevelNames[(gameepisode-1)*9+prevmap-1]+7)/2;
IN_DrTextB(LevelNames[(gameepisode-1)*9+prevmap-1]+7, x, 3);
x = 160-MN_TextAWidth("FINISHED")/2;
MN_DrTextA("FINISHED", x, 25);
ypos = 50;
for(i=0; i<MAXPLAYERS; i++)
{
if(playeringame[i])
{
V_DrawShadowedPatch(25, ypos, W_CacheLumpNum(patchFaceOkayBase+i, PU_CACHE));
if(intertime < 40)
{
sounds = 0;
ypos += 37;
continue;
}
else if(intertime >= 40 && sounds < 1)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
IN_DrawNumber(killPercent[i], 85, ypos+10, 3);
V_DrawShadowedPatch(121, ypos+10, FontBPercent);
IN_DrawNumber(bonusPercent[i], 160, ypos+10, 3);
V_DrawShadowedPatch(196, ypos+10, FontBPercent);
IN_DrawNumber(secretPercent[i], 237, ypos+10, 3);
V_DrawShadowedPatch(273, ypos+10, FontBPercent);
ypos += 37;
}
}
}
//========================================================================
//
// IN_DrawDMStats
//
//========================================================================
void IN_DrawDMStats(void)
{
int i;
int j;
int ypos;
int xpos;
int kpos;
static int sounds;
xpos = 90;
ypos = 55;
IN_DrTextB("TOTAL", 265, 30);
MN_DrTextA("VICTIMS", 140, 8);
for(i=0; i<7; i++)
{
MN_DrTextA(KillersText[i], 10, 80+9*i);
}
if(intertime < 20)
{
for(i=0; i<MAXPLAYERS; i++)
{
if(playeringame[i])
{
V_DrawShadowedPatch(40, ((ypos<<FRACBITS)+dSlideY[i]*intertime)
>>FRACBITS, W_CacheLumpNum(patchFaceOkayBase+i, PU_CACHE));
V_DrawShadowedPatch(((xpos<<FRACBITS)+dSlideX[i]*intertime)
>>FRACBITS, 18, W_CacheLumpNum(patchFaceDeadBase+i, PU_CACHE));
}
}
sounds = 0;
return;
}
if(intertime >= 20 && sounds < 1)
{
S_StartSound(NULL, sfx_dorcls);
sounds++;
}
if(intertime >= 100 && slaughterboy && sounds < 2)
{
S_StartSound(NULL, sfx_wpnup);
sounds++;
}
for(i=0; i<MAXPLAYERS; i++)
{
if(playeringame[i])
{
if(intertime < 100 || i == consoleplayer)
{
V_DrawShadowedPatch(40, ypos, W_CacheLumpNum(patchFaceOkayBase+i, PU_CACHE));
V_DrawShadowedPatch(xpos, 18, W_CacheLumpNum(patchFaceDeadBase+i, PU_CACHE));
}
else
{
V_DrawFuzzPatch(40, ypos, W_CacheLumpNum(patchFaceOkayBase+i, PU_CACHE));
V_DrawFuzzPatch(xpos, 18, W_CacheLumpNum(patchFaceDeadBase+i, PU_CACHE));
}
kpos = 86;
for(j=0; j<MAXPLAYERS; j++)
{
if(playeringame[j])
{
IN_DrawNumber(players[i].frags[j], kpos, ypos+10, 3);
kpos += 43;
}
}
if(slaughterboy&(1<<i))
{
if(!(intertime&16))
{
IN_DrawNumber(totalFrags[i], 263, ypos+10, 3);
}
}
else
{
IN_DrawNumber(totalFrags[i], 263, ypos+10, 3);
}
ypos += 36;
xpos += 43;
}
}
}
//========================================================================
//
// IN_DrawTime
//
//========================================================================
void IN_DrawTime(int x, int y, int h, int m, int s)
{
if(h)
{
IN_DrawNumber(h, x, y, 2);
IN_DrTextB(":", x+26, y);
}
x += 34;
if(m || h)
{
IN_DrawNumber(m, x, y, 2);
}
x += 34;
if(s)
{
IN_DrTextB(":", x-8, y);
IN_DrawNumber(s, x, y, 2);
}
}
//========================================================================
//
// IN_DrawNumber
//
//========================================================================
void IN_DrawNumber(int val, int x, int y, int digits)
{
patch_t *patch;
int xpos;
int oldval;
int realdigits;
boolean neg;
oldval = val;
xpos = x;
neg = false;
realdigits = 1;
if(val < 0)
{ //...this should reflect negative frags
val = -val;
neg = true;
if(val > 99)
{
val = 99;
}
}
if(val > 9)
{
realdigits++;
if(digits < realdigits)
{
realdigits = digits;
val = 9;
}
}
if(val > 99)
{
realdigits++;
if(digits < realdigits)
{
realdigits = digits;
val = 99;
}
}
if(val > 999)
{
realdigits++;
if(digits < realdigits)
{
realdigits = digits;
val = 999;
}
}
if(digits == 4)
{
patch = FontBNumbers[val/1000];
V_DrawShadowedPatch(xpos+6-patch->width/2-12, y, patch);
}
if(digits > 2)
{
if(realdigits > 2)
{
patch = FontBNumbers[val/100];
V_DrawShadowedPatch(xpos+6-patch->width/2, y, patch);
}
xpos += 12;
}
val = val%100;
if(digits > 1)
{
if(val > 9)
{
patch = FontBNumbers[val/10];
V_DrawShadowedPatch(xpos+6-patch->width/2, y, patch);
}
else if(digits == 2 || oldval > 99)
{
V_DrawShadowedPatch(xpos, y, FontBNumbers[0]);
}
xpos += 12;
}
val = val%10;
patch = FontBNumbers[val];
V_DrawShadowedPatch(xpos+6-patch->width/2, y, patch);
if(neg)
{
patch = FontBNegative;
V_DrawShadowedPatch(xpos+6-patch->width/2-12*(realdigits), y, patch);
}
}
//========================================================================
//
// IN_DrTextB
//
//========================================================================
void IN_DrTextB(char *text, int x, int y)
{
char c;
patch_t *p;
while((c = *text++) != 0)
{
if(c < 33)
{
x += 8;
}
else
{
p = W_CacheLumpNum(FontBLump+c-33, PU_CACHE);
V_DrawShadowedPatch(x, y, p);
x += p->width-1;
}
}
}

259
Heretic Source/I_CYBER.C Normal file
View File

@ -0,0 +1,259 @@
// I_cyber.c
#include <dos.h>
#include <stdlib.h>
/*
====================================================
Doom control structure
The keybaord and joystick will add to the values set by the cyberman,
to a maximum of 0x19000 for forwardmove and sidemove. Angleturn is
not bounded at all.
parm normal fast
----- ------ ----
forwardmove 0xc800 0x19000
sidemove 0xc000 0x14000
angleturn 0x2800000 0x5000000
The keyboard and joystick have a 1/3 second slow turn of 0x1400000 under
normal speed to help aiming.
====================================================
*/
typedef struct
{
char forwardmove; // *2048 for move
char sidemove; // *2048 for move
short angleturn; // <<16 for angle delta
short consistancy; // checks for net game
unsigned char chatchar;
unsigned char buttons;
} ticcmd_t;
#define BT_ATTACK 1
#define BT_USE 2
#define BT_CHANGE 4 // if true, the next 3 bits hold weapon num
#define BT_WEAPONMASK (8+16+32)
#define BT_WEAPONSHIFT 3
//==================================================
//
// CyberMan detection and usage info
//
//==================================================
#define DPMI_INT 0x31
#define MOUSE_INT 0x33
#define DOSMEMSIZE 64 // enough for any SWIFT structure
typedef struct {
short x;
short y;
short z;
short pitch;
short roll;
short yaw;
short buttons;
} SWIFT_3DStatus;
// DPMI real mode interrupt structure
static struct rminfo {
long EDI;
long ESI;
long EBP;
long reserved_by_system;
long EBX;
long EDX;
long ECX;
long EAX;
short flags;
short ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;
typedef struct {
unsigned char deviceType;
unsigned char majorVersion;
unsigned char minorVersion;
unsigned char absRelFlags;
unsigned char centeringFlags;
unsigned char reserved[5];
} StaticDeviceData;
// values for deviceType:
#define DEVTYPE_CYBERMAN 1
short selector;
unsigned short segment; // segment of DOS memory block
SWIFT_3DStatus *cyberstat;
int isCyberPresent; // is CyberMan present?
static union REGS regs;
static struct SREGS sregs;
extern int mousepresent;
//===========================================================
//
// I_StartupCyberMan
//
// If a cyberman is present, init it and set isCyberPresent to 1
//===========================================================
void I_StartupCyberMan(void)
{
StaticDeviceData *pbuf;
int success = 0;
isCyberPresent = 0;
cyberstat = (SWIFT_3DStatus *)I_AllocLow (DOSMEMSIZE);
segment = (int)cyberstat>>4;
pbuf = (StaticDeviceData *)cyberstat;
memset(pbuf, 0, sizeof (StaticDeviceData));
// Use DPMI call 300h to issue mouse interrupt
memset(&RMI, 0, sizeof(RMI));
RMI.EAX = 0x53C1; // SWIFT: Get Static Device Data
RMI.ES = segment;
RMI.EDX = 0;
memset(&sregs, 0, sizeof (sregs));
regs.w.ax = 0x0300; // DPMI: simulate interrupt
regs.w.bx = MOUSE_INT;
regs.w.cx = 0;
regs.x.edi = FP_OFF(&RMI);
sregs.es = FP_SEG(&RMI);
int386x( DPMI_INT, &regs, &regs, &sregs );
if ((short)RMI.EAX != 1)
{
// SWIFT functions not present
tprintf("CyberMan: Wrong mouse driver - no SWIFT support (AX=%04x).\n",
(unsigned)(short)RMI.EAX);
}
else
if (pbuf->deviceType != DEVTYPE_CYBERMAN)
{
// no SWIFT device, or not CyberMan
if (pbuf->deviceType == 0)
{
tprintf("CyberMan: no SWIFT device connected.\n");
}
else
{
tprintf("CyberMan: SWIFT device is not a CyberMan! (type=%d)\n",
pbuf->deviceType);
}
}
else
{
tprintf("CyberMan: CyberMan %d.%02d connected.\n",
pbuf->majorVersion, pbuf->minorVersion);
isCyberPresent = 1;
mousepresent = 0;
}
}
/*
===============
=
= I_ReadCyberCmds
=
===============
*/
int oldpos;
void I_ReadCyberCmd (ticcmd_t *cmd)
{
int delta;
// Use DPMI call 300h to issue mouse interrupt
memset(&RMI, 0, sizeof(RMI));
RMI.EAX = 0x5301; // SWIFT: Get Position and Buttons
RMI.ES = segment;
RMI.EDX = 0;
memset(&sregs, 0, sizeof (sregs));
regs.w.ax = 0x0300; // DPMI: simulate interrupt
regs.w.bx = MOUSE_INT;
regs.w.cx = 0;
regs.x.edi = FP_OFF(&RMI);
sregs.es = FP_SEG(&RMI);
int386x( DPMI_INT, &regs, &regs, &sregs );
if (cyberstat->y < -7900)
cmd->forwardmove = 0xc800/2048;
else if (cyberstat->y > 7900)
cmd->forwardmove = -0xc800/2048;
if (cyberstat->buttons & 4)
cmd->buttons |= BT_ATTACK;
if (cyberstat->buttons & 2)
cmd->buttons |= BT_USE;
delta = cyberstat->x - oldpos;
oldpos = cyberstat->x;
if (cyberstat->buttons & 1)
{ // strafe
if (cyberstat->x < -7900)
cmd->sidemove = -0xc800/2048;
else if (cyberstat->x > 7900)
cmd->sidemove = 0xc800/2048;
else
cmd->sidemove = delta*40/2048;
}
else
{
if (cyberstat->x < -7900)
cmd->angleturn = 0x280;
else if (cyberstat->x > 7900)
cmd->angleturn = -0x280;
else
cmd->angleturn = -delta*0xa/16;
}
}
void I_Tactile (int on, int off, int total)
{
if (!isCyberPresent)
return;
on /= 5;
off /= 5;
total /= 40;
if (on > 255)
on = 255;
if (off > 255)
off = 255;
if (total > 255)
total = 255;
memset(&RMI, 0, sizeof(RMI));
RMI.EAX = 0x5330; // SWIFT: Get Position and Buttons
RMI.EBX = on*256+off;
RMI.ECX = total;
memset(&sregs, 0, sizeof (sregs));
regs.w.ax = 0x0300; // DPMI: simulate interrupt
regs.w.bx = MOUSE_INT;
regs.w.cx = 0;
regs.x.edi = FP_OFF(&RMI);
sregs.es = FP_SEG(&RMI);
int386x( DPMI_INT, &regs, &regs, &sregs );
}

77
Heretic Source/I_HEADER.H Normal file
View File

@ -0,0 +1,77 @@
#ifndef __I_HEADER_H__
#define __I_HEADER_H__
#include "DoomDef.h"
//--------
//SOUND IO
//--------
#define FREQ_LOW 0x40
#define FREQ_NORM 0x80
#define FREQ_HIGH 0xff
void I_SetMasterVolume(int volume);
void I_TurnOffSfx(void);
void I_TurnOnSfx(void);
void I_TurnOffMusic(void);
void I_TurnOnMusic(void);
// MUSIC I/O
//
int I_RegisterSong(void *songdata);
// called by anything that wants to register a song lump with the sound lib
// calls Paul's function of the similar name to register music only.
// note that the song data is the same for any sound card and is paul's
// MUS format. Returns a handle which will be passed to all other music
// functions.
void I_UnregisterSong(int handle);
// called by anything which is finished with a song and no longer needs
// the sound library to be aware of it. All songs should be stopped
// before calling this, but it will double check and stop it if necessary.
void I_LoopSong(int handle);
// called by anything that wishes to start music.
// plays a song, and when the song is done, starts playing it again in
// an endless loop. the start is faded in over three seconds.
void I_FadeOutSong(int handle, int fotime);
// called by anything that wishes to stop music.
// fades out the song over <fotime> milliseconds.
void I_StopSong(int handle);
// called by anything that wishes to stop music.
// stops a song abruptly.
// SFX I/O
//
void *I_GetSoundEffect (char *soundname);
// called by routines which wish to play a sound effect at some later
// time. Pass it the lump name of a sound effect WITHOUT the sfx
// prefix. This means the maximum name length is 7 letters/digits.
// The prefixes for different sound cards are 'S','M','A', and 'P'.
// They refer to the card type. The routine will cache in the
// appropriate sound effect when it is played.
void I_UngetSoundEffect (void *soundset);
// called by routines which wish to no longer use the sounds at all
// frees up the associated structure. It stops any currently playing
// sound effects.
void I_StartSound (channel_t *c, int vol, int sep, int pitch, int priority);
// Starts a sound in a particular sound channel
void I_UpdateSoundParams(channel_t *c, int vol, int sep, int pitch);
// Updates the volume, separation, and pitch of a sound channel
void I_StopSound(channel_t *c);
// Stops a sound channel
int I_SoundIsPlaying(channel_t *c);
// called by S_*()'s to see if a channel is still playing. Returns 0
// if no longer playing, 1 if playing.
#endif

2204
Heretic Source/I_IBM.C Normal file

File diff suppressed because it is too large Load Diff

135
Heretic Source/I_IBM_A.ASM Normal file
View File

@ -0,0 +1,135 @@
.386
.MODEL small
.DATA
.CODE
IF 0
#define PEL_WRITE_ADR 0x3c8
#define PEL_READ_ADR 0x3c7
#define PEL_DATA 0x3c9
ENDIF
;================
;
; I_DivException
;
;================
PROC I_DivException_
PUBLIC I_DivException_
mov edx,03c9h
mov al,63
out dx,al
mov ebx,0ffffffh
mov eax,[ebx]
retf
ENDP
;================
;
; I_SetDivException
;
;================
PROC I_SetDivException_
PUBLIC I_SetDivException_
pusha
mov eax,0212h
mov ebx,0
mov ecx,cs
mov edx,OFFSET I_DivException_
int 31h
jnc good
popa
mov eax,0
ret
good:
popa
mov eax,1
ret
ENDP
;================
;
; I_ReadJoystick
;
; Read the absolute joystick values
; returns false if not connected
;================
.data
_joystickx dd 0
_joysticky dd 0
PUBLIC _joystickx, _joysticky
.code
PROC I_ReadJoystick_
PUBLIC I_ReadJoystick_
pusha
pushf ; state of interrupt flag
cli
mov dx,0201h
in al,dx
out dx,al ; Clear the resistors
mov ah,1 ; Get masks into registers
mov ch,2
xor esi,esi ; Clear count registers
xor edi,edi
xor ebx,ebx ; Clear high byte of bx for later
mov ebp,10000 ; joystick is disconnected if value is this big
jloop:
in al,dx ; Get bits indicating whether all are finished
dec ebp ; Check bounding register
jz bad ; We have a silly value - abort
mov bl,al ; Duplicate the bits
and bl,ah ; Mask off useless bits (in [xb])
add esi,ebx ; Possibly increment count register
mov cl,bl ; Save for testing later
mov bl,al
and bl,ch ; [yb]
add edi,ebx
add cl,bl
jnz jloop ; If both bits were 0, drop out
done:
mov [_joystickx],esi
shr edi,1 ; because 2s were added
mov [_joysticky],edi
popf ; restore interrupt flag
popa
mov eax,1 ; read was ok
ret
bad:
popf ; restore interrupt flag
popa
xor eax, eax ; read was bad
ret
ENDP
END

391
Heretic Source/I_SOUND.C Normal file
View File

@ -0,0 +1,391 @@
// I_SOUND.C
#include <stdio.h>
#include "doomdef.h"
#include "dmx.h"
#include "sounds.h"
#include "i_sound.h"
/*
===============
=
= I_StartupTimer
=
===============
*/
int tsm_ID = -1;
void I_StartupTimer (void)
{
#ifndef NOTIMER
extern int I_TimerISR(void);
tprintf("I_StartupTimer()\n",0);
// installs master timer. Must be done before StartupTimer()!
TSM_Install(SND_TICRATE);
tsm_ID = TSM_NewService (I_TimerISR, 35, 255, 0); // max priority
if (tsm_ID == -1)
{
I_Error("Can't register 35 Hz timer w/ DMX library");
}
#endif
}
void I_ShutdownTimer (void)
{
TSM_DelService(tsm_ID);
TSM_Remove();
}
/*
*
* SOUND HEADER & DATA
*
*
*/
// sound information
#if 0
const char *dnames[] = {"None",
"PC_Speaker",
"Adlib",
"Sound_Blaster",
"ProAudio_Spectrum16",
"Gravis_Ultrasound",
"MPU",
"AWE32"
};
#endif
const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
'M', 'M', 'S' };
int snd_Channels;
int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
int snd_MusicDevice, // current music card # (index to dmxCodes)
snd_SfxDevice, // current sfx card # (index to dmxCodes)
snd_MaxVolume, // maximum volume for sound
snd_MusicVolume; // maximum volume for music
int dmxCodes[NUM_SCARDS]; // the dmx code for a given card
int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
int snd_Mport; // midi variables
extern boolean snd_MusicAvail, // whether music is available
snd_SfxAvail; // whether sfx are available
void I_PauseSong(int handle)
{
MUS_PauseSong(handle);
}
void I_ResumeSong(int handle)
{
MUS_ResumeSong(handle);
}
void I_SetMusicVolume(int volume)
{
MUS_SetMasterVolume(volume*8);
// snd_MusicVolume = volume;
}
void I_SetSfxVolume(int volume)
{
snd_MaxVolume = volume; // THROW AWAY?
}
/*
*
* SONG API
*
*/
int I_RegisterSong(void *data)
{
int rc = MUS_RegisterSong(data);
#ifdef SNDDEBUG
if (rc<0) printf("MUS_Reg() returned %d\n", rc);
#endif
return rc;
}
void I_UnRegisterSong(int handle)
{
int rc = MUS_UnregisterSong(handle);
#ifdef SNDDEBUG
if (rc < 0) printf("MUS_Unreg() returned %d\n", rc);
#endif
}
int I_QrySongPlaying(int handle)
{
int rc = MUS_QrySongPlaying(handle);
#ifdef SNDDEBUG
if (rc < 0) printf("MUS_QrySP() returned %d\n", rc);
#endif
return rc;
}
// Stops a song. MUST be called before I_UnregisterSong().
void I_StopSong(int handle)
{
int rc;
rc = MUS_StopSong(handle);
#ifdef SNDDEBUG
if (rc < 0) printf("MUS_StopSong() returned %d\n", rc);
#endif
// Fucking kluge pause
{
int s;
extern volatile int ticcount;
for (s=ticcount ; ticcount - s < 10 ; );
}
}
void I_PlaySong(int handle, boolean looping)
{
int rc;
rc = MUS_ChainSong(handle, looping ? handle : -1);
#ifdef SNDDEBUG
if (rc < 0) printf("MUS_ChainSong() returned %d\n", rc);
#endif
rc = MUS_PlaySong(handle, snd_MusicVolume);
#ifdef SNDDEBUG
if (rc < 0) printf("MUS_PlaySong() returned %d\n", rc);
#endif
}
/*
*
* SOUND FX API
*
*/
// Gets lump nums of the named sound. Returns pointer which will be
// passed to I_StartSound() when you want to start an SFX. Must be
// sure to pass this to UngetSoundEffect() so that they can be
// freed!
int I_GetSfxLumpNum(sfxinfo_t *sound)
{
char namebuf[9];
if(sound->name == 0)
return 0;
if (sound->link) sound = sound->link;
// sprintf(namebuf, "d%c%s", snd_prefixen[snd_SfxDevice], sound->name);
return W_GetNumForName(sound->name);
}
int I_StartSound (int id, void *data, int vol, int sep, int pitch, int priority)
{
/*
// hacks out certain PC sounds
if (snd_SfxDevice == PC
&& (data == S_sfx[sfx_posact].data
|| data == S_sfx[sfx_bgact].data
|| data == S_sfx[sfx_dmact].data
|| data == S_sfx[sfx_dmpain].data
|| data == S_sfx[sfx_popain].data
|| data == S_sfx[sfx_sawidl].data)) return -1;
else
*/
return SFX_PlayPatch(data, pitch, sep, vol, 0, 0);
}
void I_StopSound(int handle)
{
// extern volatile long gDmaCount;
// long waittocount;
SFX_StopPatch(handle);
// waittocount = gDmaCount + 2;
// while (gDmaCount < waittocount) ;
}
int I_SoundIsPlaying(int handle)
{
return SFX_Playing(handle);
}
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
{
SFX_SetOrigin(handle, pitch, sep, vol);
}
/*
*
* SOUND STARTUP STUFF
*
*
*/
//
// Why PC's Suck, Reason #8712
//
void I_sndArbitrateCards(void)
{
char tmp[160];
boolean gus, adlib, pc, sb, midi;
int i, rc, mputype, p, opltype, wait, dmxlump;
// snd_MaxVolume = 127;
//Damn you, Dave Taylor!
snd_MusicDevice = snd_DesiredMusicDevice;
snd_SfxDevice = snd_DesiredSfxDevice;
// check command-line parameters- overrides config file
//
if (M_CheckParm("-nosound")) snd_MusicDevice = snd_SfxDevice = snd_none;
if (M_CheckParm("-nosfx")) snd_SfxDevice = snd_none;
if (M_CheckParm("-nomusic")) snd_MusicDevice = snd_none;
if (snd_MusicDevice > snd_MPU && snd_MusicDevice <= snd_MPU3)
snd_MusicDevice = snd_MPU;
if (snd_MusicDevice == snd_SB)
snd_MusicDevice = snd_Adlib;
if (snd_MusicDevice == snd_PAS)
snd_MusicDevice = snd_Adlib;
// figure out what i've got to initialize
//
gus = snd_MusicDevice == snd_GUS || snd_SfxDevice == snd_GUS;
sb = snd_SfxDevice == snd_SB || snd_MusicDevice == snd_SB;
adlib = snd_MusicDevice == snd_Adlib ;
pc = snd_SfxDevice == snd_PC;
midi = snd_MusicDevice == snd_MPU;
// initialize whatever i've got
//
if (gus)
{
if (GF1_Detect()) tprintf("Dude. The GUS ain't responding.\n",1);
else
{
dmxlump = W_GetNumForName("dmxgus");
GF1_SetMap(W_CacheLumpNum(dmxlump, PU_CACHE), lumpinfo[dmxlump].size);
}
}
if (sb)
{
if(debugmode)
{
sprintf(tmp,"cfg p=0x%x, i=%d, d=%d\n",
snd_SBport, snd_SBirq, snd_SBdma);
tprintf(tmp,0);
}
if (SB_Detect(&snd_SBport, &snd_SBirq, &snd_SBdma, 0))
{
sprintf(tmp,"SB isn't responding at p=0x%x, i=%d, d=%d\n",
snd_SBport, snd_SBirq, snd_SBdma);
tprintf(tmp,0);
}
else SB_SetCard(snd_SBport, snd_SBirq, snd_SBdma);
if(debugmode)
{
sprintf(tmp,"SB_Detect returned p=0x%x,i=%d,d=%d\n",
snd_SBport, snd_SBirq, snd_SBdma);
tprintf(tmp,0);
}
}
if (adlib)
{
if (AL_Detect(&wait,0))
tprintf("Dude. The Adlib isn't responding.\n",1);
else
AL_SetCard(wait, W_CacheLumpName("genmidi", PU_STATIC));
}
if (midi)
{
if (debugmode)
{
sprintf(tmp,"cfg p=0x%x\n", snd_Mport);
tprintf(tmp,0);
}
if (MPU_Detect(&snd_Mport, &i))
{
sprintf(tmp,"The MPU-401 isn't reponding @ p=0x%x.\n", snd_Mport);
tprintf(tmp,0);
}
else MPU_SetCard(snd_Mport);
}
}
// inits all sound stuff
void I_StartupSound (void)
{
char tmp[80];
int rc, i;
if (debugmode)
tprintf("I_StartupSound: Hope you hear a pop.\n",1);
// initialize dmxCodes[]
dmxCodes[0] = 0;
dmxCodes[snd_PC] = AHW_PC_SPEAKER;
dmxCodes[snd_Adlib] = AHW_ADLIB;
dmxCodes[snd_SB] = AHW_SOUND_BLASTER;
dmxCodes[snd_PAS] = AHW_MEDIA_VISION;
dmxCodes[snd_GUS] = AHW_ULTRA_SOUND;
dmxCodes[snd_MPU] = AHW_MPU_401;
dmxCodes[snd_AWE] = AHW_AWE32;
// inits sound library timer stuff
I_StartupTimer();
// pick the sound cards i'm going to use
//
I_sndArbitrateCards();
if (debugmode)
{
sprintf(tmp," Music device #%d & dmxCode=%d", snd_MusicDevice,
dmxCodes[snd_MusicDevice]);
tprintf(tmp,0);
sprintf(tmp," Sfx device #%d & dmxCode=%d\n", snd_SfxDevice,
dmxCodes[snd_SfxDevice]);
tprintf(tmp,0);
}
// inits DMX sound library
tprintf(" calling DMX_Init",0);
rc = DMX_Init(SND_TICRATE, SND_MAXSONGS, dmxCodes[snd_MusicDevice],
dmxCodes[snd_SfxDevice]);
if (debugmode)
{
sprintf(tmp," DMX_Init() returned %d", rc);
tprintf(tmp,0);
}
}
// shuts down all sound stuff
void I_ShutdownSound (void)
{
DMX_DeInit();
I_ShutdownTimer();
}
void I_SetChannels(int channels)
{
WAV_PlayMode(channels, SND_SAMPLERATE);
}

23
Heretic Source/I_SOUND.H Normal file
View File

@ -0,0 +1,23 @@
#ifndef __SOUND__
#define __SOUND__
#define SND_TICRATE 140 // tic rate for updating sound
#define SND_MAXSONGS 40 // max number of songs in game
#define SND_SAMPLERATE 11025 // sample rate of sound effects
typedef enum
{
snd_none,
snd_PC,
snd_Adlib,
snd_SB,
snd_PAS,
snd_GUS,
snd_MPU,
snd_MPU2,
snd_MPU3,
snd_AWE,
NUM_SCARDS
} cardenum_t;
#endif

258
Heretic Source/LINEAR.ASM Normal file
View File

@ -0,0 +1,258 @@
.386
.MODEL small
INCLUDE defs.inc
;============================================================================
;
; unwound vertical scaling code
;
; eax light table pointer, 0 lowbyte overwritten
; ebx all 0, low byte overwritten
; ecx fractional step value
; edx fractional scale value
; esi start of source pixels
; edi bottom pixel in screenbuffer to blit into
;
; ebx should be set to 0 0 0 dh to feed the pipeline
;
; The graphics wrap vertically at 128 pixels
;============================================================================
.DATA
EXTRN _centery:DWORD
SCALEDEFINE MACRO number
dd vscale&number
ENDM
ALIGN 4
scalecalls LABEL
LINE = 0
REPT SCREENHEIGHT+1
SCALEDEFINE %LINE
LINE = LINE+1
ENDM
;=================================
.CODE
;================
;
; R_DrawColumn
;
;================
PROC R_DrawColumn_
PUBLIC R_DrawColumn_
PUSHR
mov ebp,[_dc_yh]
mov ebx,ebp
mov edi,[_ylookup+ebx*4]
mov ebx,[_dc_x]
add edi,[_columnofs + ebx*4]
mov eax,[_dc_yl]
sub ebp,eax ; ebp = pixel count
or ebp,ebp
js done
mov ecx,[_dc_iscale]
sub eax,[_centery]
imul ecx
mov edx,[_dc_texturemid]
add edx,eax
shl edx,9 ; 7 significant bits, 25 frac
shl ecx,9 ; 7 significant bits, 25 frac
mov esi,[_dc_source]
mov eax,[_dc_colormap]
xor ebx,ebx
shld ebx,edx,7 ; get address of first location
call [scalecalls+4+ebp*4]
done:
POPR
ret
;============ HIGH DETAIL ============
SCALELABEL MACRO number
vscale&number:
ENDM
LINE = SCREENHEIGHT
REPT SCREENHEIGHT-1
SCALELABEL %LINE
mov al,[esi+ebx] ; get source pixel
add edx,ecx ; calculate next location
mov al,[eax] ; translate the color
; xor ebx,ebx
; shld ebx,edx,7 ; get address of next location
mov ebx,edx
shr ebx,25
mov [edi-(LINE-1)*SCREENWIDTH],al ; draw a pixel to the buffer
LINE = LINE-1
ENDM
vscale1:
mov al,[esi+ebx]
mov al,[eax]
mov [edi],al
vscale0:
ret
ENDP
;============================================================================
;
; unwound horizontal texture mapping code
;
; eax lighttable
; ebx scratch register
; ecx position 6.10 bits x, 6.10 bits y
; edx step 6.10 bits x, 6.10 bits y
; esi start of block
; edi dest
; ebp fff to mask bx
;
; ebp should by preset from ebx / ecx before calling
;============================================================================
OP_SHLD = 0fh
.DATA
MAPDEFINE MACRO number
dd hmap&number
ENDM
ALIGN 4
mapcalls LABEL
LINE = 0
REPT SCREENWIDTH+1
MAPDEFINE %LINE
LINE = LINE+1
ENDM
callpoint dd 0
returnpoint dd 0
.CODE
;================
;
; R_DrawSpan
;
; Horizontal texture mapping
;
;================
PROC R_DrawSpan_
PUBLIC R_DrawSpan_
PUSHR
IFE SKIPPRIMITIVES
mov eax,[_ds_x1]
mov ebx,[_ds_x2]
mov eax,[mapcalls+eax*4]
mov [callpoint],eax ; spot to jump into unwound
mov eax,[mapcalls+4+ebx*4]
mov [returnpoint],eax ; spot to patch a ret at
mov BYTE PTR [eax], OP_RET
;
; build composite position
;
mov ecx,[_ds_xfrac]
shl ecx,10
and ecx,0ffff0000h
mov eax,[_ds_yfrac]
shr eax,6
and eax,0ffffh
or ecx,eax
;
; build composite step
;
mov edx,[_ds_xstep]
shl edx,10
and edx,0ffff0000h
mov eax,[_ds_ystep]
shr eax,6
and eax,0ffffh
or edx,eax
mov esi,[_ds_source]
mov edi,[_ds_y]
mov edi,[_ylookup+edi*4]
add edi,[_columnofs]
mov eax,[_ds_colormap]
;
; feed the pipeline and jump in
;
mov ebp,0fffh ; used to mask off slop high bits from position
shld ebx,ecx,22 ; shift y units in
shld ebx,ecx,6 ; shift x units in
and ebx,ebp ; mask off slop bits
call [callpoint]
mov ebx,[returnpoint]
mov BYTE PTR [ebx],OP_MOVAL ; remove the ret patched in
ENDIF
POPR
ret
;============= HIGH DETAIL ============
.CODE
MAPLABEL MACRO number
hmap&number:
ENDM
LINE = 0
PCOL = 0
REPT SCREENWIDTH/4
PLANE = 0
REPT 4
MAPLABEL %LINE
LINE = LINE + 1
mov al,[esi+ebx] ; get source pixel
shld ebx,ecx,22 ; shift y units in
shld ebx,ecx,6 ; shift x units in
mov al,[eax] ; translate color
and ebx,ebp ; mask off slop bits
add ecx,edx ; position += step
mov [edi+PLANE+PCOL*4],al ; write pixel
PLANE = PLANE + 1
ENDM
PCOL = PCOL + 1
ENDM
hmap320:
ret
ENDP
END

2
Heretic Source/MAKE.BAT Normal file
View File

@ -0,0 +1,2 @@
@echo off
wmake %1 %2 %3 %4 %5 %6 %7 %8 %9

95
Heretic Source/MAKEFILE Normal file
View File

@ -0,0 +1,95 @@
# TIC.EXE and HERETIC.EXE makefile
# --------------------------------------------------------------------------
#
# 4r use 80486 timings and register argument passing
# c compile only
# d1 include line number debugging information
# d2 include full sybolic debugging information
# ei force enums to be of type int
# j change char default from unsigned to signed
# oa relax aliasing checking
# od do not optimize
# oe[=#] expand functions inline, # = quads (default 20)
# oi use the inline library functions
# om generate inline 80x87 code for math functions
# ot optimize for time
# ox maximum optimization
# s remove stack overflow checks
# zp1 align structures on bytes
# zq use quiet mode
# /i=dir add include directories
#
# --------------------------------------------------------------------------
CCOPTS = /d2 /omaxet /zp1 /4r /ei /j /zq /i=dmx
LOCOBJS = &
i_cyber.obj &
i_ibm_a.obj &
i_sound.obj &
linear.obj
GLOBOBJS = &
am_map.obj &
ct_chat.obj &
d_main.obj &
d_net.obj &
g_game.obj &
f_finale.obj &
info.obj &
in_lude.obj &
mn_menu.obj &
m_misc.obj &
p_ceilng.obj &
p_doors.obj &
p_enemy.obj &
p_floor.obj &
p_inter.obj &
p_lights.obj &
p_map.obj &
p_maputl.obj &
p_mobj.obj &
p_plats.obj &
p_pspr.obj &
p_setup.obj &
p_sight.obj &
p_spec.obj &
p_switch.obj &
p_telept.obj &
p_tick.obj &
p_user.obj &
r_bsp.obj &
r_data.obj &
r_draw.obj &
r_main.obj &
r_plane.obj &
r_segs.obj &
r_things.obj &
sb_bar.obj &
sounds.obj &
tables.obj &
v_video.obj &
w_wad.obj &
z_zone.obj
tic.exe : $(LOCOBJS) $(GLOBOBJS) i_ibm.obj
wlink @tic.lnk
copy tic.exe striptic.exe
wstrip striptic.exe
4gwbind 4gwpro.exe striptic.exe heretic.exe -V
prsucc
i_ibm.obj:
wcc386 /zp1 /4r /zq /ei /j i_ibm.c
.c.obj :
wcc386 $(CCOPTS) $[*
.asm.obj :
tasm /mx $[*
clean : .SYMBOLIC
del *.obj
del tic.exe

1588
Heretic Source/MN_MENU.C Normal file

File diff suppressed because it is too large Load Diff

798
Heretic Source/M_MISC.C Normal file
View File

@ -0,0 +1,798 @@
// M_misc.c
#ifdef __NeXT__
#include <libc.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <direct.h>
#include <fcntl.h>
#include <stdlib.h>
#endif
#include <ctype.h>
#include "DoomDef.h"
#include "soundst.h"
int myargc;
char **myargv;
//---------------------------------------------------------------------------
//
// FUNC M_ValidEpisodeMap
//
//---------------------------------------------------------------------------
boolean M_ValidEpisodeMap(int episode, int map)
{
if(episode < 1 || map < 1 || map > 9)
{
return false;
}
if(shareware)
{ // Shareware version checks
if(episode != 1)
{
return false;
}
}
else if(ExtendedWAD)
{ // Extended version checks
if(episode == 6)
{
if(map > 3)
{
return false;
}
}
else if(episode > 5)
{
return false;
}
}
else
{ // Registered version checks
if(episode == 4)
{
if(map != 1)
{
return false;
}
}
else if(episode > 3)
{
return false;
}
}
return true;
}
/*
=================
=
= M_CheckParm
=
= Checks for the given parameter in the program's command line arguments
=
= Returns the argument number (1 to argc-1) or 0 if not present
=
=================
*/
int M_CheckParm (char *check)
{
int i;
for (i = 1;i<myargc;i++)
{
if ( !strcasecmp(check, myargv[i]) )
return i;
}
return 0;
}
/*
===============
=
= M_Random
=
= Returns a 0-255 number
=
===============
*/
unsigned char rndtable[256] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66,
74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36,
95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188,
52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224,
149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242,
145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0,
175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235,
25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113,
94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75,
136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196,
135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113,
80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241,
24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224,
145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95,
28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226,
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36,
17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106,
197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136,
120, 163, 236, 249
};
int rndindex = 0;
int prndindex = 0;
int P_Random (void)
{
prndindex = (prndindex+1)&0xff;
return rndtable[prndindex];
}
int M_Random (void)
{
rndindex = (rndindex+1)&0xff;
return rndtable[rndindex];
}
void M_ClearRandom (void)
{
rndindex = prndindex = 0;
}
void M_ClearBox (fixed_t *box)
{
box[BOXTOP] = box[BOXRIGHT] = MININT;
box[BOXBOTTOM] = box[BOXLEFT] = MAXINT;
}
void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y)
{
if (x<box[BOXLEFT])
box[BOXLEFT] = x;
else if (x>box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y<box[BOXBOTTOM])
box[BOXBOTTOM] = y;
else if (y>box[BOXTOP])
box[BOXTOP] = y;
}
/*
==================
=
= M_WriteFile
=
==================
*/
#ifndef O_BINARY
#define O_BINARY 0
#endif
boolean M_WriteFile (char const *name, void *source, int length)
{
int handle, count;
handle = open (name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (handle == -1)
return false;
count = write (handle, source, length);
close (handle);
if (count < length)
return false;
return true;
}
/*
==================
=
= M_ReadFile
=
==================
*/
int M_ReadFile (char const *name, byte **buffer)
{
int handle, count, length;
struct stat fileinfo;
byte *buf;
handle = open (name, O_RDONLY | O_BINARY, 0666);
if (handle == -1)
I_Error ("Couldn't read file %s", name);
if (fstat (handle,&fileinfo) == -1)
I_Error ("Couldn't read file %s", name);
length = fileinfo.st_size;
buf = Z_Malloc (length, PU_STATIC, NULL);
count = read (handle, buf, length);
close (handle);
if (count < length)
I_Error ("Couldn't read file %s", name);
*buffer = buf;
return length;
}
//---------------------------------------------------------------------------
//
// PROC M_FindResponseFile
//
//---------------------------------------------------------------------------
#define MAXARGVS 100
void M_FindResponseFile(void)
{
int i;
for(i = 1; i < myargc; i++)
{
if(myargv[i][0] == '@')
{
FILE *handle;
int size;
int k;
int index;
int indexinfile;
char *infile;
char *file;
char *moreargs[20];
char *firstargv;
// READ THE RESPONSE FILE INTO MEMORY
handle = fopen(&myargv[i][1], "rb");
if(!handle)
{
printf("\nNo such response file!");
exit(1);
}
printf("Found response file %s!\n",&myargv[i][1]);
fseek (handle,0,SEEK_END);
size = ftell(handle);
fseek (handle,0,SEEK_SET);
file = malloc (size);
fread (file,size,1,handle);
fclose (handle);
// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
for (index = 0,k = i+1; k < myargc; k++)
moreargs[index++] = myargv[k];
firstargv = myargv[0];
myargv = malloc(sizeof(char *)*MAXARGVS);
memset(myargv,0,sizeof(char *)*MAXARGVS);
myargv[0] = firstargv;
infile = file;
indexinfile = k = 0;
indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
do
{
myargv[indexinfile++] = infile+k;
while(k < size &&
((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
k++;
*(infile+k) = 0;
while(k < size &&
((*(infile+k)<= ' ') || (*(infile+k)>'z')))
k++;
} while(k < size);
for (k = 0;k < index;k++)
myargv[indexinfile++] = moreargs[k];
myargc = indexinfile;
// DISPLAY ARGS
if(M_CheckParm("-debug"))
{
printf("%d command-line args:\n", myargc);
for(k = 1; k < myargc; k++)
{
printf("%s\n", myargv[k]);
}
}
break;
}
}
}
//---------------------------------------------------------------------------
//
// PROC M_ForceUppercase
//
// Change string to uppercase.
//
//---------------------------------------------------------------------------
void M_ForceUppercase(char *text)
{
char c;
while((c = *text) != 0)
{
if(c >= 'a' && c <= 'z')
{
*text++ = c-('a'-'A');
}
else
{
text++;
}
}
}
/*
==============================================================================
DEFAULTS
==============================================================================
*/
int usemouse;
int usejoystick;
extern int key_right, key_left, key_up, key_down;
extern int key_strafeleft, key_straferight;
extern int key_fire, key_use, key_strafe, key_speed;
extern int key_flyup, key_flydown, key_flycenter;
extern int key_lookup, key_lookdown, key_lookcenter;
extern int key_invleft, key_invright, key_useartifact;
extern int mousebfire;
extern int mousebstrafe;
extern int mousebforward;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
extern int viewwidth, viewheight;
int mouseSensitivity;
extern int screenblocks;
extern char *chat_macros[10];
typedef struct
{
char *name;
int *location;
int defaultvalue;
int scantranslate; // PC scan code hack
int untranslated; // lousy hack
} default_t;
#ifndef __NeXT__
extern int snd_Channels;
extern int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
extern int snd_MusicDevice, // current music card # (index to dmxCodes)
snd_SfxDevice; // current sfx card # (index to dmxCodes)
extern int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
extern int snd_Mport; // midi variables
#endif
default_t defaults[] =
{
{ "mouse_sensitivity", &mouseSensitivity, 5 },
#ifndef __NeXT__
{ "sfx_volume", &snd_MaxVolume, 10},
{ "music_volume", &snd_MusicVolume, 10},
#endif
#ifdef __WATCOMC__
#define SC_UPARROW 0x48
#define SC_DOWNARROW 0x50
#define SC_LEFTARROW 0x4b
#define SC_RIGHTARROW 0x4d
#define SC_RCTRL 0x1d
#define SC_RALT 0x38
#define SC_RSHIFT 0x36
#define SC_SPACE 0x39
#define SC_COMMA 0x33
#define SC_PERIOD 0x34
#define SC_PAGEUP 0x49
#define SC_INSERT 0x52
#define SC_HOME 0x47
#define SC_PAGEDOWN 0x51
#define SC_DELETE 0x53
#define SC_END 0x4f
#define SC_ENTER 0x1c
{ "key_right", &key_right, SC_RIGHTARROW, 1 },
{ "key_left", &key_left, SC_LEFTARROW, 1 },
{ "key_up", &key_up, SC_UPARROW, 1 },
{ "key_down", &key_down, SC_DOWNARROW, 1 },
{ "key_strafeleft", &key_strafeleft, SC_COMMA, 1 },
{ "key_straferight", &key_straferight, SC_PERIOD, 1 },
{ "key_flyup", &key_flyup, SC_PAGEUP, 1 },
{ "key_flydown", &key_flydown, SC_INSERT, 1 },
{ "key_flycenter", &key_flycenter, SC_HOME, 1 },
{ "key_lookup", &key_lookup, SC_PAGEDOWN, 1 },
{ "key_lookdown", &key_lookdown, SC_DELETE, 1 },
{ "key_lookcenter", &key_lookcenter, SC_END, 1 },
{ "key_invleft", &key_invleft, 0x1a, 1 },
{ "key_invright", &key_invright, 0x1b, 1 },
{ "key_useartifact", &key_useartifact, SC_ENTER, 1 },
{ "key_fire", &key_fire, SC_RCTRL, 1 },
{ "key_use", &key_use, SC_SPACE, 1 },
{ "key_strafe", &key_strafe, SC_RALT, 1 },
{ "key_speed", &key_speed, SC_RSHIFT, 1 },
#endif
#ifdef __NeXT__
{ "key_right", &key_right, KEY_RIGHTARROW },
{ "key_left", &key_left, KEY_LEFTARROW },
{ "key_up", &key_up, KEY_UPARROW },
{ "key_down", &key_down, KEY_DOWNARROW },
{ "key_strafeleft", &key_strafeleft, ',' },
{ "key_straferight", &key_straferight, '.' },
{ "key_flyup", &key_flyup, 'u' },
{ "key_flydown", &key_flydown, 'j' },
{ "key_flycenter", &key_flycenter, 'k' },
{ "key_lookup", &key_lookup, 'm' },
{ "key_lookdown", &key_lookdown, 'b' },
{ "key_lookcenter", &key_lookcenter, 'n' },
{ "key_invleft", &key_invleft, '[' },
{ "key_invright", &key_invright, ']' },
{ "key_useartifact", &key_useartifact, 13 },
{ "key_fire", &key_fire, ' ', 1 },
{ "key_use", &key_use, 'x', 1 },
{ "key_strafe", &key_strafe, 'c', 1 },
{ "key_speed", &key_speed, 'z', 1 },
#endif
{ "use_mouse", &usemouse, 1 },
{ "mouseb_fire", &mousebfire, 0 },
{ "mouseb_strafe", &mousebstrafe, 1 },
{ "mouseb_forward", &mousebforward, 2 },
{ "use_joystick", &usejoystick, 0 },
{ "joyb_fire", &joybfire, 0 },
{ "joyb_strafe", &joybstrafe, 1 },
{ "joyb_use", &joybuse, 3 },
{ "joyb_speed", &joybspeed, 2 },
{ "screenblocks", &screenblocks, 10 },
#ifndef __NeXT__
{ "snd_channels", &snd_Channels, 3 },
{ "snd_musicdevice", &snd_DesiredMusicDevice, 0 },
{ "snd_sfxdevice", &snd_DesiredSfxDevice, 0 },
{ "snd_sbport", &snd_SBport, 544 },
{ "snd_sbirq", &snd_SBirq, -1 },
{ "snd_sbdma", &snd_SBdma, -1 },
{ "snd_mport", &snd_Mport, -1 },
#endif
{ "usegamma", &usegamma, 0 },
{ "chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0 },
{ "chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1 },
{ "chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2 },
{ "chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3 },
{ "chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4 },
{ "chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5 },
{ "chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6 },
{ "chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7 },
{ "chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8 },
{ "chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9 }
};
int numdefaults;
char *defaultfile;
/*
==============
=
= M_SaveDefaults
=
==============
*/
void M_SaveDefaults (void)
{
int i,v;
FILE *f;
f = fopen (defaultfile, "w");
if (!f)
return; // can't write the file, but don't complain
for (i=0 ; i<numdefaults ; i++)
{
#ifdef __WATCOMC__
if (defaults[i].scantranslate)
defaults[i].location = &defaults[i].untranslated;
#endif
if (defaults[i].defaultvalue > -0xfff
&& defaults[i].defaultvalue < 0xfff)
{
v = *defaults[i].location;
fprintf (f,"%s\t\t%i\n",defaults[i].name,v);
} else {
fprintf (f,"%s\t\t\"%s\"\n",defaults[i].name,
* (char **) (defaults[i].location));
}
}
fclose (f);
}
/*
==============
=
= M_LoadDefaults
=
==============
*/
extern byte scantokey[128];
extern char *basedefault;
void M_LoadDefaults (void)
{
int i, len;
FILE *f;
char def[80];
char strparm[100];
char *newstring;
int parm;
boolean isstring;
//
// set everything to base values
//
numdefaults = sizeof(defaults)/sizeof(defaults[0]);
for (i=0 ; i<numdefaults ; i++)
*defaults[i].location = defaults[i].defaultvalue;
//
// check for a custom default file
//
i = M_CheckParm("-config");
if(i && i<myargc-1)
{
defaultfile = myargv[i+1];
printf("default file: %s\n", defaultfile);
}
else if(cdrom)
{
defaultfile = "c:\\heretic.cd\\heretic.cfg";
}
else
{
defaultfile = basedefault;
}
//
// read the file in, overriding any set defaults
//
f = fopen (defaultfile, "r");
if (f)
{
while (!feof(f))
{
isstring = false;
if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2)
{
if (strparm[0] == '"')
{
// get a string default
isstring = true;
len = strlen(strparm);
newstring = (char *) malloc(len);
strparm[len-1] = 0;
strcpy(newstring, strparm+1);
}
else if (strparm[0] == '0' && strparm[1] == 'x')
sscanf(strparm+2, "%x", &parm);
else
sscanf(strparm, "%i", &parm);
for (i=0 ; i<numdefaults ; i++)
if (!strcmp(def, defaults[i].name))
{
if (!isstring)
*defaults[i].location = parm;
else
*defaults[i].location =
(int) newstring;
break;
}
}
}
fclose (f);
}
#ifdef __WATCOMC__
for(i = 0; i < numdefaults; i++)
{
if(defaults[i].scantranslate)
{
parm = *defaults[i].location;
defaults[i].untranslated = parm;
*defaults[i].location = scantokey[parm];
}
}
#endif
}
/*
==============================================================================
SCREEN SHOTS
==============================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
==============
=
= WritePCXfile
=
==============
*/
void WritePCXfile (char *filename, byte *data, int width, int height, byte *palette)
{
int i, length;
pcx_t *pcx;
byte *pack;
pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);
pcx->manufacturer = 0x0a; // PCX id
pcx->version = 5; // 256 color
pcx->encoding = 1; // uncompressed
pcx->bits_per_pixel = 8; // 256 color
pcx->xmin = 0;
pcx->ymin = 0;
pcx->xmax = SHORT(width-1);
pcx->ymax = SHORT(height-1);
pcx->hres = SHORT(width);
pcx->vres = SHORT(height);
memset (pcx->palette,0,sizeof(pcx->palette));
pcx->color_planes = 1; // chunky image
pcx->bytes_per_line = SHORT(width);
pcx->palette_type = SHORT(2); // not a grey scale
memset (pcx->filler,0,sizeof(pcx->filler));
//
// pack the image
//
pack = &pcx->data;
for (i=0 ; i<width*height ; i++)
if ( (*data & 0xc0) != 0xc0)
*pack++ = *data++;
else
{
*pack++ = 0xc1;
*pack++ = *data++;
}
//
// write the palette
//
*pack++ = 0x0c; // palette ID byte
for (i=0 ; i<768 ; i++)
*pack++ = *palette++;
//
// write output file
//
length = pack - (byte *)pcx;
M_WriteFile (filename, pcx, length);
Z_Free (pcx);
}
//==============================================================================
/*
==================
=
= M_ScreenShot
=
==================
*/
void M_ScreenShot (void)
{
int i;
byte *linear;
char lbmname[12];
byte *pal;
#ifdef _WATCOMC_
extern byte *pcscreen;
#endif
//
// munge planar buffer to linear
//
#ifdef _WATCOMC_
linear = pcscreen;
#else
linear = screen;
#endif
//
// find a file name to save it to
//
strcpy(lbmname,"HRTIC00.pcx");
for (i=0 ; i<=99 ; i++)
{
lbmname[5] = i/10 + '0';
lbmname[6] = i%10 + '0';
if (access(lbmname,0) == -1)
break; // file doesn't exist
}
if (i==100)
I_Error ("M_ScreenShot: Couldn't create a PCX");
//
// save the pcx file
//
#ifdef __WATCOMC__
pal = (byte *)Z_Malloc(768, PU_STATIC, NULL);
outp(0x3c7, 0);
for(i = 0; i < 768; i++)
{
*(pal+i) = inp(0x3c9)<<2;
}
#else
pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
#endif
WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT
, pal);
players[consoleplayer].message = "SCREEN SHOT";
#ifdef __WATCOMC__
Z_Free(pal);
#endif
}

783
Heretic Source/NETOLD.C Normal file
View File

@ -0,0 +1,783 @@
// I_pcnet.m
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000
#define NCMD_SETUP 0x20000000
#define NCMD_KILL 0x10000000 // kill game
#define NCMD_CHECKSUM 0x0fffffff
doomcom_t *doomcom;
doomdata_t *netbuffer; // points inside doomcom
/*
==============================================================================
NETWORKING
gametic is the tic about to (or currently being) run
maketic is the tick that hasn't had control made for it yet
nettics[] has the maketics for all players
a gametic cannot be run until nettics[] > gametic for all players
==============================================================================
*/
#define RESENDCOUNT 10
#define PL_DRONE 0x80 // bit flag in doomdata->player
ticcmd_t localcmds[BACKUPTICS];
ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
int nettics[MAXNETNODES];
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
boolean remoteresend[MAXNETNODES]; // set when local needs tics
int resendto[MAXNETNODES]; // set when remote needs tics
int resendcount[MAXNETNODES];
int nodeforplayer[MAXPLAYERS];
int maketic;
int lastnettic, skiptics;
int ticdup;
int maxsend; // BACKUPTICS/(2*ticdup)-1
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t *cmd);
void D_DoAdvanceDemo (void);
boolean reboundpacket;
doomdata_t reboundstore;
int NetbufferSize (void)
{
return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
}
unsigned NetbufferChecksum (void)
{
unsigned c;
int i,l;
c = 0x1234567;
#ifdef NeXT
return 0; // byte order problems
#endif
l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
for (i=0 ; i<l ; i++)
c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
return c & NCMD_CHECKSUM;
}
int ExpandTics (int low)
{
int delta;
delta = low - (maketic&0xff);
if (delta >= -64 && delta <= 64)
return (maketic&~0xff) + low;
if (delta > 64)
return (maketic&~0xff) - 256 + low;
if (delta < -64)
return (maketic&~0xff) + 256 + low;
I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
return 0;
}
//============================================================================
/*
==============
=
= HSendPacket
=
==============
*/
void HSendPacket (int node, int flags)
{
netbuffer->checksum = NetbufferChecksum () | flags;
if (!node)
{
reboundstore = *netbuffer;
reboundpacket = true;
return;
}
if (demoplayback)
return;
if (!netgame)
I_Error ("Tried to transmit to another node");
doomcom->command = CMD_SEND;
doomcom->remotenode = node;
doomcom->datalength = NetbufferSize ();
if (debugfile)
{
int i;
int realretrans;
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"send (%i + %i, R %i) [%i] "
,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
I_NetCmd ();
}
/*
==============
=
= HGetPacket
=
= Returns false if no packet is waiting
=
==============
*/
boolean HGetPacket (void)
{
if (reboundpacket)
{
*netbuffer = reboundstore;
doomcom->remotenode = 0;
reboundpacket = false;
return true;
}
if (!netgame)
return false;
if (demoplayback)
return false;
doomcom->command = CMD_GET;
I_NetCmd ();
if (doomcom->remotenode == -1)
return false;
if (doomcom->datalength != NetbufferSize ())
{
if (debugfile)
fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
return false;
}
if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
{
if (debugfile)
fprintf (debugfile,"bad packet checksum\n");
return false;
}
if (debugfile)
{
int realretrans;
int i;
if (netbuffer->checksum & NCMD_SETUP)
fprintf (debugfile,"setup packet\n");
else
{
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
}
return true;
}
/*
===================
=
= GetPackets
=
===================
*/
char exitmsg[80];
void GetPackets (void)
{
int netconsole;
int netnode;
ticcmd_t *src, *dest;
int realend;
int realstart;
while (HGetPacket ())
{
if (netbuffer->checksum & NCMD_SETUP)
continue; // extra setup packet
netconsole = netbuffer->player & ~PL_DRONE;
netnode = doomcom->remotenode;
//
// to save bytes, only the low byte of tic numbers are sent
// Figure out what the rest of the bytes are
//
realstart = ExpandTics (netbuffer->starttic);
realend = (realstart+netbuffer->numtics);
//
// check for exiting the game
//
if (netbuffer->checksum & NCMD_EXIT)
{
if (!nodeingame[netnode])
continue;
nodeingame[netnode] = false;
playeringame[netconsole] = false;
strcpy(exitmsg, "PLAYER 1 LEFT THE GAME");
S_StartSound(NULL, sfx_chat);
exitmsg[7] += netconsole;
//players[consoleplayer].message = exitmsg;
P_SetMessage(&players[consoleplayer], exitmsg, true);
/* if (demorecording)
G_CheckDemoStatus ();
*/ // DEBUG
continue;
}
//
// check for a remote game kill
//
if (netbuffer->checksum & NCMD_KILL)
I_Error ("Killed by network driver");
nodeforplayer[netconsole] = netnode;
//
// check for retransmit request
//
if ( resendcount[netnode] <= 0
&& (netbuffer->checksum & NCMD_RETRANSMIT) )
{
resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
if (debugfile)
fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
resendcount[netnode] = RESENDCOUNT;
}
else
resendcount[netnode]--;
//
// check for out of order / duplicated packet
//
if (realend == nettics[netnode])
continue;
if (realend < nettics[netnode])
{
if (debugfile)
fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
continue;
}
//
// check for a missed packet
//
if (realstart > nettics[netnode])
{
// stop processing until the other system resends the missed tics
if (debugfile)
fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
remoteresend[netnode] = true;
continue;
}
//
// update command store from the packet
//
{
int start;
remoteresend[netnode] = false;
start = nettics[netnode] - realstart;
src = &netbuffer->cmds[start];
while (nettics[netnode] < realend)
{
dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
nettics[netnode]++;
*dest = *src;
src++;
}
}
}
}
/*
=============
=
= NetUpdate
=
= Builds ticcmds for console player
= sends out a packet
=============
*/
int gametime;
void NetUpdate (void)
{
int nowtime;
int newtics;
int i,j;
int realstart;
int gameticdiv;
//
// check time
//
nowtime = I_GetTime ()/ticdup;
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
goto listen;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
netbuffer->player = consoleplayer;
//
// build new ticcmds for console player
//
gameticdiv = gametic/ticdup;
for (i=0 ; i<newtics ; i++)
{
I_StartTic ();
D_ProcessEvents ();
if (maketic - gameticdiv >= BACKUPTICS/2-1)
break; // can't hold any more
//printf ("mk:%i ",maketic);
G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
maketic++;
}
if (singletics)
return; // singletic update is syncronous
//
// send the packet to the other nodes
//
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
netbuffer->starttic = realstart = resendto[i];
netbuffer->numtics = maketic - realstart;
if (netbuffer->numtics > BACKUPTICS)
I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
resendto[i] = maketic - doomcom->extratics;
for (j=0 ; j< netbuffer->numtics ; j++)
netbuffer->cmds[j] =
localcmds[(realstart+j)%BACKUPTICS];
if (remoteresend[i])
{
netbuffer->retransmitfrom = nettics[i];
HSendPacket (i, NCMD_RETRANSMIT);
}
else
{
netbuffer->retransmitfrom = 0;
HSendPacket (i, 0);
}
}
//
// listen for other packets
//
listen:
GetPackets ();
}
/*
=====================
=
= CheckAbort
=
=====================
*/
void CheckAbort (void)
{
event_t *ev;
int stoptic;
stoptic = I_GetTime () + 2;
while (I_GetTime() < stoptic)
I_StartTic ();
I_StartTic ();
for ( ; eventtail != eventhead
; eventtail = (++eventtail)&(MAXEVENTS-1) )
{
ev = &events[eventtail];
if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
I_Error ("Network game synchronization aborted.");
}
}
/*
=====================
=
= D_ArbitrateNetStart
=
=====================
*/
void D_ArbitrateNetStart (void)
{
int i;
boolean gotinfo[MAXNETNODES];
autostart = true;
memset (gotinfo,0,sizeof(gotinfo));
if (doomcom->consoleplayer)
{ // listen for setup info from key player
while (1)
{
CheckAbort ();
if (!HGetPacket ())
continue;
if (netbuffer->checksum & NCMD_SETUP)
{
if (netbuffer->player != VERSION)
I_Error ("Different DOOM versions cannot play a net game!");
startskill = netbuffer->retransmitfrom & 15;
deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
startmap = netbuffer->starttic & 0x3f;
startepisode = netbuffer->starttic >> 6;
return;
}
}
}
else
{ // key player, send the setup info
do
{
CheckAbort ();
for (i=0 ; i<doomcom->numnodes ; i++)
{
netbuffer->retransmitfrom = startskill;
if (deathmatch)
netbuffer->retransmitfrom |= (deathmatch<<6);
if (nomonsters)
netbuffer->retransmitfrom |= 0x20;
if (respawnparm)
netbuffer->retransmitfrom |= 0x10;
netbuffer->starttic = startepisode * 64 + startmap;
netbuffer->player = VERSION;
netbuffer->numtics = 0;
HSendPacket (i, NCMD_SETUP);
}
#if 1
for(i = 10 ; i && HGetPacket(); --i)
{
if((netbuffer->player&0x7f) < MAXNETNODES)
gotinfo[netbuffer->player&0x7f] = true;
}
#else
while (HGetPacket ())
{
gotinfo[netbuffer->player&0x7f] = true;
}
#endif
for (i=1 ; i<doomcom->numnodes ; i++)
if (!gotinfo[i])
break;
} while (i < doomcom->numnodes);
}
}
/*
===================
=
= D_CheckNetGame
=
= Works out player numbers among the net participants
===================
*/
extern int viewangleoffset;
void D_CheckNetGame (void)
{
int i;
for (i=0 ; i<MAXNETNODES ; i++)
{
nodeingame[i] = false;
nettics[i] = 0;
remoteresend[i] = false; // set when local needs tics
resendto[i] = 0; // which tic to start sending
}
// I_InitNetwork sets doomcom and netgame
I_InitNetwork ();
if (doomcom->id != DOOMCOM_ID)
I_Error ("Doomcom buffer invalid!");
netbuffer = &doomcom->data;
consoleplayer = displayplayer = doomcom->consoleplayer;
if (netgame)
D_ArbitrateNetStart ();
//printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
// read values out of doomcom
ticdup = doomcom->ticdup;
maxsend = BACKUPTICS/2-1;
if (maxsend<1)
maxsend = 1;
for (i=0 ; i<doomcom->numplayers ; i++)
playeringame[i] = true;
for (i=0 ; i<doomcom->numnodes ; i++)
nodeingame[i] = true;
//printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
}
/*
==================
=
= D_QuitNetGame
=
= Called before quitting to leave a net game without hanging the
= other players
=
==================
*/
void D_QuitNetGame (void)
{
int i, j;
if (debugfile)
fclose (debugfile);
if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
return;
// send a bunch of packets for security
netbuffer->player = consoleplayer;
netbuffer->numtics = 0;
for (i=0 ; i<4 ; i++)
{
for (j=1 ; j<doomcom->numnodes ; j++)
if (nodeingame[j])
HSendPacket (j, NCMD_EXIT);
I_WaitVBL (1);
}
}
/*
===============
=
= TryRunTics
=
===============
*/
int frametics[4], frameon;
int frameskip[4];
int oldnettics;
extern boolean advancedemo;
void TryRunTics (void)
{
int i;
int lowtic;
int entertic;
static int oldentertics;
int realtics, availabletics;
int counts;
int numplaying;
//
// get real tics
//
entertic = I_GetTime ()/ticdup;
realtics = entertic - oldentertics;
oldentertics = entertic;
//
// get available tics
//
NetUpdate ();
lowtic = MAXINT;
numplaying = 0;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
numplaying++;
if (nettics[i] < lowtic)
lowtic = nettics[i];
}
availabletics = lowtic - gametic/ticdup;
//
// decide how many tics to run
//
if (realtics < availabletics-1)
counts = realtics+1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
frameon++;
if (debugfile)
fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
if (!demoplayback)
{
//=============================================================================
//
// ideally nettics[0] should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
//
for (i=0 ; i<MAXPLAYERS ; i++)
if (playeringame[i])
break;
if (consoleplayer == i)
{ // the key player does not adapt
}
else
{
if (nettics[0] <= nettics[nodeforplayer[i]])
{
gametime--;
// printf ("-");
}
frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
oldnettics = nettics[0];
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
// printf ("+");
}
}
//=============================================================================
} // demoplayback
//
// wait for new tics if needed
//
while (lowtic < gametic/ticdup + counts)
{
NetUpdate ();
lowtic = MAXINT;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i] && nettics[i] < lowtic)
lowtic = nettics[i];
if (lowtic < gametic/ticdup)
I_Error ("TryRunTics: lowtic < gametic");
// don't stay in here forever -- give the menu a chance to work
if (I_GetTime ()/ticdup - entertic >= 20)
{
MN_Ticker ();
return;
}
}
//
// run the count * ticdup dics
//
while (counts--)
{
for (i=0 ; i<ticdup ; i++)
{
if (gametic/ticdup > lowtic)
I_Error ("gametic>lowtic");
if (advancedemo)
D_DoAdvanceDemo ();
MN_Ticker ();
G_Ticker ();
gametic++;
//
// modify command for duplicated tics
//
if (i != ticdup-1)
{
ticcmd_t *cmd;
int buf;
int j;
buf = (gametic/ticdup)%BACKUPTICS;
for (j=0 ; j<MAXPLAYERS ; j++)
{
cmd = &netcmds[j][buf];
cmd->chatchar = 0;
if (cmd->buttons & BT_SPECIAL)
cmd->buttons = 0;
}
}
}
NetUpdate (); // check for new console commands
}
}

790
Heretic Source/OLDD_NET.C Normal file
View File

@ -0,0 +1,790 @@
// I_pcnet.m
#include "DoomDef.h"
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000
#define NCMD_SETUP 0x20000000
#define NCMD_CHECKSUM 0x0fffffff
/*
if more space needs to be crunched out of the protocol...
1 drone
2 player
8 tic
5 numtics
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000 // a retransmit will have 0 tics
#define NCMD_DRONE 0x20000000
#define NCMD_PLAYER 0x18000000
#define NCMD_PLAYERSHIFT 27
#define NCMD_TIC 0x00ff0000
#define NCMD_TICSHIFT 16
#define NCMD_NUMTICS 0x0000ff00
#define NCMD_NUMTICSSHIFT 8
#define NCMD_CHECKSUM 0x000000ff
*/
doomcom_t *doomcom;
doomdata_t *netbuffer; // points inside doomcom
/*
==============================================================================
NETWORKING
gametic is the tic about to (or currently being) run
maketic is the tick that hasn't had control made for it yet
nettics[] has the maketics for all players
a gametic cannot be run until nettics[] > gametic for all players
==============================================================================
*/
#define RESENDCOUNT 10
#define PL_DRONE 0x80 // bit flag in doomdata->player
ticcmd_t localcmds[BACKUPTICS];
ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
int nettics[MAXNETNODES];
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
boolean remoteresend[MAXNETNODES]; // set when local needs tics
int resendto[MAXNETNODES]; // set when remote needs tics
int resendcount[MAXNETNODES];
int nodeforplayer[MAXPLAYERS];
int gametime;
int maketic;
int lastnettic, skiptics;
int ticdup;
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t *cmd);
void D_DoAdvanceDemo (void);
boolean reboundpacket;
doomdata_t reboundstore;
int NetbufferSize (void)
{
return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
}
unsigned NetbufferChecksum (void)
{
unsigned c;
int i,l;
c = 0x1234567;
#ifdef NeXT
return 0; // byte order problems
#endif
l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
for (i=0 ; i<l ; i++)
c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
return c & NCMD_CHECKSUM;
}
int ExpandTics (int low)
{
int delta;
delta = low - (maketic&0xff);
if (delta >= -64 && delta <= 64)
return (maketic&~0xff) + low;
if (delta > 64)
return (maketic&~0xff) - 256 + low;
if (delta < -64)
return (maketic&~0xff) + 256 + low;
I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
return 0;
}
//============================================================================
/*
==============
=
= HSendPacket
=
==============
*/
void HSendPacket (int node, int flags)
{
netbuffer->checksum = NetbufferChecksum () | flags;
if (!node)
{
reboundstore = *netbuffer;
reboundpacket = true;
return;
}
if (!netgame)
I_Error ("Tried to transmit to another node");
doomcom->command = CMD_SEND;
doomcom->remotenode = node;
doomcom->datalength = NetbufferSize ();
if (debugfile)
{
int i;
int realretrans;
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"send (%i + %i, R %i) [%i] "
,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
I_NetCmd ();
}
/*
==============
=
= HGetPacket
=
= Returns false if no packet is waiting
=
==============
*/
boolean HGetPacket (void)
{
if (reboundpacket)
{
*netbuffer = reboundstore;
doomcom->remotenode = 0;
reboundpacket = false;
return true;
}
if (!netgame)
return false;
doomcom->command = CMD_GET;
I_NetCmd ();
if (doomcom->remotenode == -1)
return false;
if (doomcom->datalength != NetbufferSize ())
{
if (debugfile)
fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
return false;
}
if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
{
if (debugfile)
fprintf (debugfile,"bad packet checksum\n");
return false;
}
if (debugfile)
{
int realretrans;
int i;
if (netbuffer->checksum & NCMD_SETUP)
fprintf (debugfile,"setup packet\n");
else
{
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics (netbuffer->retransmitfrom);
else
realretrans = -1;
fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
for (i=0 ; i<doomcom->datalength ; i++)
fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
fprintf (debugfile,"\n");
}
}
return true;
}
/*
===================
=
= GetPackets
=
===================
*/
char exitmsg[80];
void GetPackets (void)
{
int netconsole;
int netnode;
int netdrone;
int j;
ticcmd_t *src, *dest;
int dupedstart, dupedend;
int skiptics;
int realstart;
while (HGetPacket ())
{
if (netbuffer->checksum & NCMD_SETUP)
continue; // extra setup packet
netdrone = netbuffer->player & PL_DRONE;
netconsole = netbuffer->player & ~PL_DRONE;
netnode = doomcom->remotenode;
//
// to save bytes, only the low byte of tic numbers are sent
// Figure out what the rest of the bytes are
//
realstart = ExpandTics (netbuffer->starttic);
dupedstart = realstart*doomcom->ticdup;
dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
//
// check for exiting the game
//
if (netbuffer->checksum & NCMD_EXIT)
{
if (!nodeingame[netnode])
continue;
nodeingame[netnode] = false;
if (!netdrone)
{
playeringame[netconsole] = false;
strcpy (exitmsg, "Player 1 left the game");
exitmsg[7] += netconsole;
players[consoleplayer].message = exitmsg;
}
continue;
}
//
// drone packets are just notifications
//
if (netdrone)
{
nettics[netnode] = dupedend;
continue;
}
nodeforplayer[netconsole] = netnode;
//
// check for retransmit request
//
if ( resendcount[netnode] <= 0
&& (netbuffer->checksum & NCMD_RETRANSMIT) )
{
resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
if (debugfile)
fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
resendcount[netnode] = RESENDCOUNT;
}
else
resendcount[netnode]--;
//
// check for out of order / duplicated packet
//
if (dupedend == nettics[netnode])
continue;
if (dupedend < nettics[netnode])
{
if (debugfile)
fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
continue;
}
//
// check for a missed packet
//
if (dupedstart > nettics[netnode])
{
// stop processing until the other system resends the missed tics
if (debugfile)
fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
remoteresend[netnode] = true;
continue;
}
//
// update command store from the packet
//
remoteresend[netnode] = false;
skiptics = nettics[netnode]/doomcom->ticdup - realstart;
src = &netbuffer->cmds[skiptics];
while (nettics[netnode] < dupedend)
{
for (j=0 ; j<doomcom->ticdup ; j++)
{
dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
nettics[netnode]++;
*dest = *src;
src->chatchar = 0;
if (src->buttons & BT_SPECIAL)
src->buttons = 0;
}
src++;
}
}
}
/*
=============
=
= NetUpdate
=
= Builds ticcmds for console player
= sends out a packet
=============
*/
void NetUpdate (void)
{
int nowtime;
int newtics;
int i,j;
int gameticdiv;
int realstart;
if (singletics)
return; // singletic update is syncronous
//
// check time
//
nowtime = I_GetTime ()/doomcom->ticdup;
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
goto listen;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
netbuffer->player = consoleplayer;
if (doomcom->drone)
netbuffer->player |= PL_DRONE;
//
// drone packets
//
if (doomcom->drone)
{
I_StartTic ();
D_ProcessEvents ();
goto sendit;
}
//
// build new ticcmds for console player
//
gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
for (i=0 ; i<newtics ; i++)
{
I_StartTic ();
D_ProcessEvents ();
if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
{
newtics = i;
break; // can't hold any more
}
//printf ("mk:%i ",maketic);
G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
maketic++;
}
//
// send the packet to the other nodes
//
sendit:
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
if (doomcom->drone)
{
netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
netbuffer->numtics = 0;
}
else
{
netbuffer->starttic = realstart = resendto[i];
netbuffer->numtics = maketic - realstart;
resendto[i] = maketic - doomcom->extratics;
}
if (netbuffer->numtics > BACKUPTICS)
I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
for (j=0 ; j< netbuffer->numtics ; j++)
netbuffer->cmds[j] =
localcmds[(realstart+j)%BACKUPTICS];
if (remoteresend[i])
{
netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
HSendPacket (i, NCMD_RETRANSMIT);
}
else
{
netbuffer->retransmitfrom = 0;
HSendPacket (i, 0);
}
}
//
// listen for other packets
//
listen:
GetPackets ();
}
/*
=====================
=
= CheckAbort
=
=====================
*/
void CheckAbort (void)
{
event_t *ev;
I_WaitVBL(2);
I_StartTic ();
for ( ; eventtail != eventhead
; eventtail = (++eventtail)&(MAXEVENTS-1) )
{
ev = &events[eventtail];
if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
I_Error ("Network game synchronization aborted.");
}
}
/*
=====================
=
= D_ArbitrateNetStart
=
=====================
*/
void D_ArbitrateNetStart (void)
{
int i;
boolean gotinfo[MAXNETNODES];
autostart = true;
memset (gotinfo,0,sizeof(gotinfo));
if (doomcom->consoleplayer)
{ // listen for setup info from key player
printf ("listening for network start info...\n");
while (1)
{
CheckAbort ();
if (!HGetPacket ())
continue;
if (netbuffer->checksum & NCMD_SETUP)
{
if (netbuffer->player != VERSION)
I_Error ("Different DOOM versions cannot play a net game!");
startskill = netbuffer->retransmitfrom & 15;
deathmatch = (netbuffer->retransmitfrom & 0x80) > 0;
nomonsters = (netbuffer->retransmitfrom & 0x40) > 0;
respawnparm = (netbuffer->retransmitfrom & 0x20) > 0;
startmap = netbuffer->starttic & 15;
startepisode = netbuffer->starttic >> 4;
return;
}
}
}
else
{ // key player, send the setup info
printf ("sending network start info...\n");
do
{
CheckAbort ();
for (i=0 ; i<doomcom->numnodes ; i++)
{
netbuffer->retransmitfrom = startskill;
if (deathmatch)
netbuffer->retransmitfrom |= 0x80;
if (nomonsters)
netbuffer->retransmitfrom |= 0x40;
if (respawnparm)
netbuffer->retransmitfrom |= 0x20;
netbuffer->starttic = startepisode * 16 + startmap;
netbuffer->player = VERSION;
netbuffer->numtics = 0;
HSendPacket (i, NCMD_SETUP);
}
while (HGetPacket ())
{
gotinfo[netbuffer->player&0x7f] = true;
}
for (i=1 ; i<doomcom->numnodes ; i++)
if (!gotinfo[i])
break;
} while (i < doomcom->numnodes);
}
}
/*
===================
=
= D_CheckNetGame
=
= Works out player numbers among the net participants
===================
*/
extern int viewangleoffset;
void D_CheckNetGame (void)
{
int i;
for (i=0 ; i<MAXNETNODES ; i++)
{
nodeingame[i] = false;
nettics[i] = 0;
remoteresend[i] = false; // set when local needs tics
resendto[i] = 0; // which tic to start sending
}
// I_InitNetwork sets doomcom and netgame
I_InitNetwork ();
if (doomcom->id != DOOMCOM_ID)
I_Error ("Doomcom buffer invalid!");
netbuffer = &doomcom->data;
consoleplayer = displayplayer = doomcom->consoleplayer;
if (netgame)
D_ArbitrateNetStart ();
printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
// read values out of doomcom
ticdup = doomcom->ticdup;
for (i=0 ; i<doomcom->numplayers ; i++)
playeringame[i] = true;
for (i=0 ; i<doomcom->numnodes ; i++)
nodeingame[i] = true;
printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
}
/*
==================
=
= D_QuitNetGame
=
= Called before quitting to leave a net game without hanging the
= other players
=
==================
*/
void D_QuitNetGame (void)
{
int i, j;
if (debugfile)
fclose (debugfile);
if (!netgame || !usergame || consoleplayer == -1)
return;
// send a bunch of packets for security
netbuffer->player = consoleplayer;
if (doomcom->drone)
netbuffer->player |= PL_DRONE;
netbuffer->numtics = 0;
for (i=0 ; i<4 ; i++)
{
for (j=1 ; j<doomcom->numnodes ; j++)
if (nodeingame[j])
HSendPacket (j, NCMD_EXIT);
I_WaitVBL (1);
}
}
/*
===============
=
= TryRunTics
=
===============
*/
int frametics[4], frameon;
int frameskip[4];
int oldnettics;
extern boolean advancedemo;
void TryRunTics (void)
{
int i;
int lowtic, nextlowest;
int entertic;
int static oldentertics;
int realtics, availabletics;
int counts;
int numplaying;
//
// get real tics
//
entertic = I_GetTime ();
realtics = entertic - oldentertics;
oldentertics = entertic;
//
// get available tics
//
NetUpdate ();
lowtic = nextlowest = MAXINT;
numplaying = 0;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i])
{
numplaying++;
if (nettics[i] < lowtic)
{
nextlowest = lowtic;
lowtic = nettics[i];
}
else if (nettics[i] < nextlowest)
nextlowest = nettics[i];
}
availabletics = lowtic - gametic;
//
// decide how many tics to run
//
if (realtics < availabletics-1)
counts = realtics+1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
frameon++;
if (debugfile)
fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
//=============================================================================
//
// ideally nettics[0] should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
// drones should never hold up the other players
//
for (i=0 ; i<MAXPLAYERS ; i++)
if (playeringame[i])
break;
if (consoleplayer == i)
{ // the key player does not adapt
}
else
{
if (nettics[0] <= nettics[nodeforplayer[i]])
{
gametime--;
// printf ("-");
}
frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
oldnettics = nettics[0];
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
// printf ("+");
}
}
//=============================================================================
//
// wait for new tics if needed
//
while (lowtic < gametic + counts)
{
NetUpdate ();
lowtic = MAXINT;
for (i=0 ; i<doomcom->numnodes ; i++)
if (nodeingame[i] && nettics[i] < lowtic)
lowtic = nettics[i];
if (lowtic < gametic)
I_Error ("TryRunTics: lowtic < gametic");
// don't stay in here forever -- give the menu a chance to work
if (I_GetTime () - entertic >= 20)
return;
}
//
// run the tics
//
while (counts--)
{
G_Ticker ();
NetUpdate (); // check for new console commands
gametic++;
}
}

236
Heretic Source/P_CEILNG.C Normal file
View File

@ -0,0 +1,236 @@
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
//==================================================================
//==================================================================
//
// CEILINGS
//
//==================================================================
//==================================================================
ceiling_t *activeceilings[MAXCEILINGS];
//==================================================================
//
// T_MoveCeiling
//
//==================================================================
void T_MoveCeiling (ceiling_t *ceiling)
{
result_e res;
switch(ceiling->direction)
{
case 0: // IN STASIS
break;
case 1: // UP
res = T_MovePlane(ceiling->sector,ceiling->speed,
ceiling->topheight,false,1,ceiling->direction);
if(!(leveltime&7))
S_StartSound((mobj_t *)&ceiling->sector->soundorg, sfx_dormov);
if (res == pastdest)
switch(ceiling->type)
{
case raiseToHighest:
P_RemoveActiveCeiling(ceiling);
break;
case fastCrushAndRaise:
case crushAndRaise:
ceiling->direction = -1;
break;
default:
break;
}
break;
case -1: // DOWN
res = T_MovePlane(ceiling->sector,ceiling->speed,
ceiling->bottomheight,ceiling->crush,1,ceiling->direction);
if (!(leveltime&7))
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_dormov);
if (res == pastdest)
switch(ceiling->type)
{
case crushAndRaise:
ceiling->speed = CEILSPEED;
case fastCrushAndRaise:
ceiling->direction = 1;
break;
case lowerAndCrush:
case lowerToFloor:
P_RemoveActiveCeiling(ceiling);
break;
default:
break;
}
else
if (res == crushed)
switch(ceiling->type)
{
case crushAndRaise:
case lowerAndCrush:
ceiling->speed = CEILSPEED / 8;
break;
default:
break;
}
break;
}
}
//==================================================================
//
// EV_DoCeiling
// Move a ceiling up/down and all around!
//
//==================================================================
int EV_DoCeiling (line_t *line, ceiling_e type)
{
int secnum,rtn;
sector_t *sec;
ceiling_t *ceiling;
secnum = -1;
rtn = 0;
//
// Reactivate in-stasis ceilings...for certain types.
//
switch(type)
{
case fastCrushAndRaise:
case crushAndRaise:
P_ActivateInStasisCeiling(line);
default:
break;
}
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
//
// new door thinker
//
rtn = 1;
ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
P_AddThinker (&ceiling->thinker);
sec->specialdata = ceiling;
ceiling->thinker.function = T_MoveCeiling;
ceiling->sector = sec;
ceiling->crush = false;
switch(type)
{
case fastCrushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
ceiling->direction = -1;
ceiling->speed = CEILSPEED * 2;
break;
case crushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
case lowerAndCrush:
case lowerToFloor:
ceiling->bottomheight = sec->floorheight;
if (type != lowerToFloor)
ceiling->bottomheight += 8*FRACUNIT;
ceiling->direction = -1;
ceiling->speed = CEILSPEED;
break;
case raiseToHighest:
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = CEILSPEED;
break;
}
ceiling->tag = sec->tag;
ceiling->type = type;
P_AddActiveCeiling(ceiling);
}
return rtn;
}
//==================================================================
//
// Add an active ceiling
//
//==================================================================
void P_AddActiveCeiling(ceiling_t *c)
{
int i;
for (i = 0; i < MAXCEILINGS;i++)
if (activeceilings[i] == NULL)
{
activeceilings[i] = c;
return;
}
}
//==================================================================
//
// Remove a ceiling's thinker
//
//==================================================================
void P_RemoveActiveCeiling(ceiling_t *c)
{
int i;
for (i = 0;i < MAXCEILINGS;i++)
if (activeceilings[i] == c)
{
activeceilings[i]->sector->specialdata = NULL;
P_RemoveThinker (&activeceilings[i]->thinker);
activeceilings[i] = NULL;
break;
}
}
//==================================================================
//
// Restart a ceiling that's in-stasis
//
//==================================================================
void P_ActivateInStasisCeiling(line_t *line)
{
int i;
for (i = 0;i < MAXCEILINGS;i++)
if (activeceilings[i] && (activeceilings[i]->tag == line->tag) &&
(activeceilings[i]->direction == 0))
{
activeceilings[i]->direction = activeceilings[i]->olddirection;
activeceilings[i]->thinker.function = T_MoveCeiling;
}
}
//==================================================================
//
// EV_CeilingCrushStop
// Stop a ceiling from crushing!
//
//==================================================================
int EV_CeilingCrushStop(line_t *line)
{
int i;
int rtn;
rtn = 0;
for (i = 0;i < MAXCEILINGS;i++)
if (activeceilings[i] && (activeceilings[i]->tag == line->tag) &&
(activeceilings[i]->direction != 0))
{
activeceilings[i]->olddirection = activeceilings[i]->direction;
activeceilings[i]->thinker.function = NULL;
activeceilings[i]->direction = 0; // in-stasis
rtn = 1;
}
return rtn;
}

368
Heretic Source/P_DOORS.C Normal file
View File

@ -0,0 +1,368 @@
// P_doors.c
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
//==================================================================
//==================================================================
//
// VERTICAL DOORS
//
//==================================================================
//==================================================================
//==================================================================
//
// T_VerticalDoor
//
//==================================================================
void T_VerticalDoor(vldoor_t *door)
{
result_e res;
switch(door->direction)
{
case 0: // WAITING
if(!--door->topcountdown)
switch(door->type)
{
case normal:
door->direction = -1; // time to go back down
S_StartSound((mobj_t *)
&door->sector->soundorg, sfx_doropn);
break;
case close30ThenOpen:
door->direction = 1;
S_StartSound((mobj_t *)
&door->sector->soundorg, sfx_doropn);
break;
default:
break;
}
break;
case 2: // INITIAL WAIT
if(!--door->topcountdown)
{
switch(door->type)
{
case raiseIn5Mins:
door->direction = 1;
door->type = normal;
S_StartSound((mobj_t *)
&door->sector->soundorg, sfx_doropn);
break;
default:
break;
}
}
break;
case -1: // DOWN
res = T_MovePlane(door->sector, door->speed,
door->sector->floorheight, false, 1, door->direction);
if(res == pastdest)
{
switch(door->type)
{
case normal:
case close:
door->sector->specialdata = NULL;
P_RemoveThinker(&door->thinker); // unlink and free
S_StartSound((mobj_t *)
&door->sector->soundorg, sfx_dorcls);
break;
case close30ThenOpen:
door->direction = 0;
door->topcountdown = 35*30;
break;
default:
break;
}
}
else if(res == crushed)
{
switch(door->type)
{
case close: // DON'T GO BACK UP!
break;
default:
door->direction = 1;
S_StartSound((mobj_t *)
&door->sector->soundorg,sfx_doropn);
break;
}
}
break;
case 1: // UP
res = T_MovePlane(door->sector, door->speed,
door->topheight, false, 1, door->direction);
if(res == pastdest)
{
switch(door->type)
{
case normal:
door->direction = 0; // wait at top
door->topcountdown = door->topwait;
break;
case close30ThenOpen:
case open:
door->sector->specialdata = NULL;
P_RemoveThinker (&door->thinker); // unlink and free
S_StopSound((mobj_t *)&door->sector->soundorg);
break;
default:
break;
}
}
break;
}
}
//----------------------------------------------------------------------------
//
// EV_DoDoor
//
// Move a door up/down
//
//----------------------------------------------------------------------------
int EV_DoDoor(line_t *line, vldoor_e type, fixed_t speed)
{
int secnum;
int retcode;
sector_t *sec;
vldoor_t *door;
secnum = -1;
retcode = 0;
while((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
if(sec->specialdata)
{
continue;
}
// Add new door thinker
retcode = 1;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
door->thinker.function = T_VerticalDoor;
door->sector = sec;
switch(type)
{
case close:
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->direction = -1;
S_StartSound((mobj_t *)&door->sector->soundorg, sfx_doropn);
break;
case close30ThenOpen:
door->topheight = sec->ceilingheight;
door->direction = -1;
S_StartSound((mobj_t *)&door->sector->soundorg, sfx_doropn);
break;
case normal:
case open:
door->direction = 1;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
if(door->topheight != sec->ceilingheight)
{
S_StartSound((mobj_t *)&door->sector->soundorg,
sfx_doropn);
}
break;
default:
break;
}
door->type = type;
door->speed = speed;
door->topwait = VDOORWAIT;
}
return(retcode);
}
//==================================================================
//
// EV_VerticalDoor : open a door manually, no tag value
//
//==================================================================
void EV_VerticalDoor(line_t *line, mobj_t *thing)
{
player_t *player;
int secnum;
sector_t *sec;
vldoor_t *door;
int side;
side = 0; // only front sides can be used
//
// Check for locks
//
player = thing->player;
switch(line->special)
{
case 26: // Blue Lock
case 32:
if(!player)
{
return;
}
if(!player->keys[key_blue])
{
P_SetMessage(player, TXT_NEEDBLUEKEY, false);
S_StartSound(NULL, sfx_plroof);
return;
}
break;
case 27: // Yellow Lock
case 34:
if(!player)
{
return;
}
if(!player->keys[key_yellow])
{
P_SetMessage(player, TXT_NEEDYELLOWKEY, false);
S_StartSound(NULL, sfx_plroof);
return;
}
break;
case 28: // Green Lock
case 33:
if(!player)
{
return;
}
if(!player->keys[key_green])
{
P_SetMessage(player, TXT_NEEDGREENKEY, false);
S_StartSound(NULL, sfx_plroof);
return;
}
break;
}
// if the sector has an active thinker, use it
sec = sides[line->sidenum[side^1]].sector;
secnum = sec-sectors;
if(sec->specialdata)
{
door = sec->specialdata;
switch(line->special)
{
case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
case 26:
case 27:
case 28:
if(door->direction == -1)
{
door->direction = 1; // go back up
}
else
{
if(!thing->player)
{ // Monsters don't close doors
return;
}
door->direction = -1; // start going down immediately
}
return;
}
}
// for proper sound
switch(line->special)
{
case 1: // NORMAL DOOR SOUND
case 31:
S_StartSound((mobj_t *)&sec->soundorg, sfx_doropn);
//S_StartSound((mobj_t *)&sec->soundorg, sfx_dormov);
break;
default: // LOCKED DOOR SOUND
S_StartSound((mobj_t *)&sec->soundorg, sfx_doropn);
//S_StartSound((mobj_t *)&sec->soundorg, sfx_dormov);
break;
}
//
// new door thinker
//
door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
door->thinker.function = T_VerticalDoor;
door->sector = sec;
door->direction = 1;
switch(line->special)
{
case 1:
case 26:
case 27:
case 28:
door->type = normal;
break;
case 31:
case 32:
case 33:
case 34:
door->type = open;
line->special = 0;
break;
}
door->speed = VDOORSPEED;
door->topwait = VDOORWAIT;
//
// find the top and bottom of the movement range
//
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
}
//==================================================================
//
// Spawn a door that closes after 30 seconds
//
//==================================================================
void P_SpawnDoorCloseIn30(sector_t *sec)
{
vldoor_t *door;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function = T_VerticalDoor;
door->sector = sec;
door->direction = 0;
door->type = normal;
door->speed = VDOORSPEED;
door->topcountdown = 30*35;
}
//==================================================================
//
// Spawn a door that opens after 5 minutes
//
//==================================================================
void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum)
{
vldoor_t *door;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function = T_VerticalDoor;
door->sector = sec;
door->direction = 2;
door->type = raiseIn5Mins;
door->speed = VDOORSPEED;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->topwait = VDOORWAIT;
door->topcountdown = 5*60*35;
}

2636
Heretic Source/P_ENEMY.C Normal file

File diff suppressed because it is too large Load Diff

445
Heretic Source/P_FLOOR.C Normal file
View File

@ -0,0 +1,445 @@
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
//==================================================================
//==================================================================
//
// FLOORS
//
//==================================================================
//==================================================================
//==================================================================
//
// Move a plane (floor or ceiling) and check for crushing
//
//==================================================================
result_e T_MovePlane(sector_t *sector,fixed_t speed,
fixed_t dest,boolean crush,int floorOrCeiling,int direction)
{
boolean flag;
fixed_t lastpos;
switch(floorOrCeiling)
{
case 0: // FLOOR
switch(direction)
{
case -1: // DOWN
if (sector->floorheight - speed < dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight =lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->floorheight;
sector->floorheight -= speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
case 1: // UP
if (sector->floorheight + speed > dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else // COULD GET CRUSHED
{
lastpos = sector->floorheight;
sector->floorheight += speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
}
break;
case 1: // CEILING
switch(direction)
{
case -1: // DOWN
if (sector->ceilingheight - speed < dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else // COULD GET CRUSHED
{
lastpos = sector->ceilingheight;
sector->ceilingheight -= speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
case 1: // UP
if (sector->ceilingheight + speed > dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->ceilingheight;
sector->ceilingheight += speed;
flag = P_ChangeSector(sector,crush);
#if 0
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
#endif
}
break;
}
break;
}
return ok;
}
//==================================================================
//
// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
//
//==================================================================
void T_MoveFloor(floormove_t *floor)
{
result_e res;
res = T_MovePlane(floor->sector,floor->speed,
floor->floordestheight,floor->crush,0,floor->direction);
if(!(leveltime&7))
{
S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_dormov);
}
if (res == pastdest)
{
floor->sector->specialdata = NULL;
if(floor->type == raiseBuildStep)
{
S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop);
}
if (floor->direction == 1)
switch(floor->type)
{
case donutRaise:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
else if (floor->direction == -1)
switch(floor->type)
{
case lowerAndChange:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
P_RemoveThinker(&floor->thinker);
}
}
//==================================================================
//
// HANDLE FLOOR TYPES
//
//==================================================================
int EV_DoFloor(line_t *line,floor_e floortype)
{
int secnum;
int rtn;
int i;
sector_t *sec;
floormove_t *floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
//
// new floor thinker
//
rtn = 1;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function = T_MoveFloor;
floor->type = floortype;
floor->crush = false;
switch(floortype)
{
case lowerFloor:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindHighestFloorSurrounding(sec);
break;
case lowerFloorToLowest:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
break;
case turboLower:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED * 4;
floor->floordestheight = (8*FRACUNIT) +
P_FindHighestFloorSurrounding(sec);
break;
case raiseFloorCrush:
floor->crush = true;
case raiseFloor:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestCeilingSurrounding(sec);
if (floor->floordestheight > sec->ceilingheight)
floor->floordestheight = sec->ceilingheight;
floor->floordestheight -= (8*FRACUNIT)*
(floortype == raiseFloorCrush);
break;
case raiseFloorToNearest:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindNextHighestFloor(sec,sec->floorheight);
break;
case raiseFloor24:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
break;
case raiseFloor24AndChange:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
sec->floorpic = line->frontsector->floorpic;
sec->special = line->frontsector->special;
break;
case raiseToTexture:
{
int minsize = MAXINT;
side_t *side;
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
for (i = 0; i < sec->linecount; i++)
if (twoSided (secnum, i) )
{
side = getSide(secnum,i,0);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
side = getSide(secnum,i,1);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
}
floor->floordestheight = floor->sector->floorheight +
minsize;
}
break;
case lowerAndChange:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
floor->texture = sec->floorpic;
for (i = 0; i < sec->linecount; i++)
if ( twoSided(secnum, i) )
{
if (getSide(secnum,i,0)->sector-sectors == secnum)
{
sec = getSector(secnum,i,1);
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
else
{
sec = getSector(secnum,i,0);
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
}
default:
break;
}
}
return rtn;
}
//==================================================================
//
// BUILD A STAIRCASE!
//
//==================================================================
int EV_BuildStairs(line_t *line, fixed_t stepDelta)
{
int secnum;
int height;
int i;
int newsecnum;
int texture;
int ok;
int rtn;
sector_t *sec, *tsec;
floormove_t *floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
//
// new floor thinker
//
rtn = 1;
height = sec->floorheight+stepDelta;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function = T_MoveFloor;
floor->type = raiseBuildStep;
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = height;
texture = sec->floorpic;
//
// Find next sector to raise
// 1. Find 2-sided line with same sector side[0]
// 2. Other side is the next sector to raise
//
do
{
ok = 0;
for (i = 0;i < sec->linecount;i++)
{
if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
continue;
tsec = (sec->lines[i])->frontsector;
newsecnum = tsec-sectors;
if (secnum != newsecnum)
continue;
tsec = (sec->lines[i])->backsector;
newsecnum = tsec - sectors;
if (tsec->floorpic != texture)
continue;
height += stepDelta;
if (tsec->specialdata)
continue;
sec = tsec;
secnum = newsecnum;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function = T_MoveFloor;
floor->type = raiseBuildStep;
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = height;
ok = 1;
break;
}
} while(ok);
}
return(rtn);
}

1473
Heretic Source/P_INTER.C Normal file

File diff suppressed because it is too large Load Diff

258
Heretic Source/P_LIGHTS.C Normal file
View File

@ -0,0 +1,258 @@
#include "DoomDef.h"
#include "P_local.h"
//==================================================================
//==================================================================
//
// BROKEN LIGHT FLASHING
//
//==================================================================
//==================================================================
//==================================================================
//
// T_LightFlash
//
// After the map has been loaded, scan each sector for specials
// that spawn thinkers
//
//==================================================================
void T_LightFlash (lightflash_t *flash)
{
if (--flash->count)
return;
if (flash->sector->lightlevel == flash->maxlight)
{
flash-> sector->lightlevel = flash->minlight;
flash->count = (P_Random()&flash->mintime)+1;
}
else
{
flash-> sector->lightlevel = flash->maxlight;
flash->count = (P_Random()&flash->maxtime)+1;
}
}
//==================================================================
//
// P_SpawnLightFlash
//
// After the map has been loaded, scan each sector for specials that spawn thinkers
//
//==================================================================
void P_SpawnLightFlash (sector_t *sector)
{
lightflash_t *flash;
sector->special = 0; // nothing special about it during gameplay
flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
P_AddThinker (&flash->thinker);
flash->thinker.function = T_LightFlash;
flash->sector = sector;
flash->maxlight = sector->lightlevel;
flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
flash->maxtime = 64;
flash->mintime = 7;
flash->count = (P_Random()&flash->maxtime)+1;
}
//==================================================================
//
// STROBE LIGHT FLASHING
//
//==================================================================
//==================================================================
//
// T_StrobeFlash
//
// After the map has been loaded, scan each sector for specials that spawn thinkers
//
//==================================================================
void T_StrobeFlash (strobe_t *flash)
{
if (--flash->count)
return;
if (flash->sector->lightlevel == flash->minlight)
{
flash-> sector->lightlevel = flash->maxlight;
flash->count = flash->brighttime;
}
else
{
flash-> sector->lightlevel = flash->minlight;
flash->count =flash->darktime;
}
}
//==================================================================
//
// P_SpawnLightFlash
//
// After the map has been loaded, scan each sector for specials that spawn thinkers
//
//==================================================================
void P_SpawnStrobeFlash (sector_t *sector,int fastOrSlow, int inSync)
{
strobe_t *flash;
flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
P_AddThinker (&flash->thinker);
flash->sector = sector;
flash->darktime = fastOrSlow;
flash->brighttime = STROBEBRIGHT;
flash->thinker.function = T_StrobeFlash;
flash->maxlight = sector->lightlevel;
flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
if (flash->minlight == flash->maxlight)
flash->minlight = 0;
sector->special = 0; // nothing special about it during gameplay
if (!inSync)
flash->count = (P_Random()&7)+1;
else
flash->count = 1;
}
//==================================================================
//
// Start strobing lights (usually from a trigger)
//
//==================================================================
void EV_StartLightStrobing(line_t *line)
{
int secnum;
sector_t *sec;
secnum = -1;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
P_SpawnStrobeFlash (sec,SLOWDARK, 0);
}
}
//==================================================================
//
// TURN LINE'S TAG LIGHTS OFF
//
//==================================================================
void EV_TurnTagLightsOff(line_t *line)
{
int i;
int j;
int min;
sector_t *sector;
sector_t *tsec;
line_t *templine;
sector = sectors;
for (j = 0;j < numsectors; j++, sector++)
if (sector->tag == line->tag)
{
min = sector->lightlevel;
for (i = 0;i < sector->linecount; i++)
{
templine = sector->lines[i];
tsec = getNextSector(templine,sector);
if (!tsec)
continue;
if (tsec->lightlevel < min)
min = tsec->lightlevel;
}
sector->lightlevel = min;
}
}
//==================================================================
//
// TURN LINE'S TAG LIGHTS ON
//
//==================================================================
void EV_LightTurnOn(line_t *line, int bright)
{
int i;
int j;
sector_t *sector;
sector_t *temp;
line_t *templine;
sector = sectors;
for (i=0;i<numsectors;i++, sector++)
if (sector->tag == line->tag)
{
//
// bright = 0 means to search for highest
// light level surrounding sector
//
if (!bright)
{
for (j = 0;j < sector->linecount; j++)
{
templine = sector->lines[j];
temp = getNextSector(templine,sector);
if (!temp)
continue;
if (temp->lightlevel > bright)
bright = temp->lightlevel;
}
}
sector-> lightlevel = bright;
}
}
//==================================================================
//
// Spawn glowing light
//
//==================================================================
void T_Glow(glow_t *g)
{
switch(g->direction)
{
case -1: // DOWN
g->sector->lightlevel -= GLOWSPEED;
if (g->sector->lightlevel <= g->minlight)
{
g->sector->lightlevel += GLOWSPEED;
g->direction = 1;
}
break;
case 1: // UP
g->sector->lightlevel += GLOWSPEED;
if (g->sector->lightlevel >= g->maxlight)
{
g->sector->lightlevel -= GLOWSPEED;
g->direction = -1;
}
break;
}
}
void P_SpawnGlowingLight(sector_t *sector)
{
glow_t *g;
g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0);
P_AddThinker(&g->thinker);
g->sector = sector;
g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
g->maxlight = sector->lightlevel;
g->thinker.function = T_Glow;
g->direction = -1;
sector->special = 0;
}

262
Heretic Source/P_LOCAL.H Normal file
View File

@ -0,0 +1,262 @@
// P_local.h
#ifndef __P_LOCAL__
#define __P_LOCAL__
#ifndef __R_LOCAL__
#include "R_local.h"
#endif
#define STARTREDPALS 1
#define STARTBONUSPALS 9
#define NUMREDPALS 8
#define NUMBONUSPALS 4
#define FOOTCLIPSIZE 10*FRACUNIT
#define TOCENTER -8
#define FLOATSPEED (FRACUNIT*4)
#define MAXHEALTH 100
#define MAXCHICKENHEALTH 30
#define VIEWHEIGHT (41*FRACUNIT)
// mapblocks are used to check movement against lines and things
#define MAPBLOCKUNITS 128
#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT)
#define MAPBLOCKSHIFT (FRACBITS+7)
#define MAPBMASK (MAPBLOCKSIZE-1)
#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS)
// player radius for movement checking
#define PLAYERRADIUS 16*FRACUNIT
// MAXRADIUS is for precalculated sector block boxes
// the spider demon is larger, but we don't have any moving sectors
// nearby
#define MAXRADIUS 32*FRACUNIT
#define GRAVITY FRACUNIT
#define MAXMOVE (30*FRACUNIT)
#define USERANGE (64*FRACUNIT)
#define MELEERANGE (64*FRACUNIT)
#define MISSILERANGE (32*64*FRACUNIT)
typedef enum
{
DI_EAST,
DI_NORTHEAST,
DI_NORTH,
DI_NORTHWEST,
DI_WEST,
DI_SOUTHWEST,
DI_SOUTH,
DI_SOUTHEAST,
DI_NODIR,
NUMDIRS
} dirtype_t;
#define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds
// ***** P_TICK *****
extern thinker_t thinkercap; // both the head and tail of the thinker list
extern int TimerGame; // tic countdown for deathmatch
void P_InitThinkers(void);
void P_AddThinker(thinker_t *thinker);
void P_RemoveThinker(thinker_t *thinker);
// ***** P_PSPR *****
#define USE_GWND_AMMO_1 1
#define USE_GWND_AMMO_2 1
#define USE_CBOW_AMMO_1 1
#define USE_CBOW_AMMO_2 1
#define USE_BLSR_AMMO_1 1
#define USE_BLSR_AMMO_2 5
#define USE_SKRD_AMMO_1 1
#define USE_SKRD_AMMO_2 5
#define USE_PHRD_AMMO_1 1
#define USE_PHRD_AMMO_2 1
#define USE_MACE_AMMO_1 1
#define USE_MACE_AMMO_2 5
void P_OpenWeapons(void);
void P_CloseWeapons(void);
void P_AddMaceSpot(mapthing_t *mthing);
void P_RepositionMace(mobj_t *mo);
void P_SetPsprite(player_t *player, int position, statenum_t stnum);
void P_SetupPsprites(player_t *curplayer);
void P_MovePsprites(player_t *curplayer);
void P_DropWeapon(player_t *player);
void P_ActivateBeak(player_t *player);
void P_PostChickenWeapon(player_t *player, weapontype_t weapon);
void P_UpdateBeak(player_t *player, pspdef_t *psp);
// ***** P_USER *****
void P_PlayerThink(player_t *player);
void P_Thrust(player_t *player, angle_t angle, fixed_t move);
void P_PlayerRemoveArtifact(player_t *player, int slot);
void P_PlayerUseArtifact(player_t *player, artitype_t arti);
boolean P_UseArtifact(player_t *player, artitype_t arti);
int P_GetPlayerNum(player_t *player);
// ***** P_MOBJ *****
#define FLOOR_SOLID 0
#define FLOOR_WATER 1
#define FLOOR_LAVA 2
#define FLOOR_SLUDGE 3
#define ONFLOORZ MININT
#define ONCEILINGZ MAXINT
#define FLOATRANDZ (MAXINT-1)
extern mobjtype_t PuffType;
extern mobj_t *MissileMobj;
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_RemoveMobj(mobj_t *th);
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state);
void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move);
int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta);
boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax);
void P_MobjThinker(mobj_t *mobj);
void P_BlasterMobjThinker(mobj_t *mobj);
void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z);
void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage);
void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator);
void P_RipperBlood(mobj_t *mo);
int P_GetThingFloorType(mobj_t *thing);
int P_HitFloor(mobj_t *thing);
boolean P_CheckMissileSpawn(mobj_t *missile);
mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type);
mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
angle_t angle, fixed_t momz);
mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type);
mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle);
// ***** P_ENEMY *****
void P_NoiseAlert (mobj_t *target, mobj_t *emmiter);
void P_InitMonsters(void);
void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle);
void P_Massacre(void);
void P_DSparilTeleport(mobj_t *actor);
// ***** P_MAPUTL *****
typedef struct
{
fixed_t x, y, dx, dy;
} divline_t;
typedef struct
{
fixed_t frac; // along trace line
boolean isaline;
union {
mobj_t *thing;
line_t *line;
} d;
} intercept_t;
#define MAXINTERCEPTS 128
extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
typedef boolean (*traverser_t) (intercept_t *in);
fixed_t P_AproxDistance (fixed_t dx, fixed_t dy);
int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line);
int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line);
void P_MakeDivline (line_t *li, divline_t *dl);
fixed_t P_InterceptVector (divline_t *v2, divline_t *v1);
int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld);
extern fixed_t opentop, openbottom, openrange;
extern fixed_t lowfloor;
void P_LineOpening (line_t *linedef);
boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) );
boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) );
#define PT_ADDLINES 1
#define PT_ADDTHINGS 2
#define PT_EARLYOUT 4
extern divline_t trace;
boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
int flags, boolean (*trav) (intercept_t *));
void P_UnsetThingPosition (mobj_t *thing);
void P_SetThingPosition (mobj_t *thing);
// ***** P_MAP *****
extern boolean floatok; // if true, move would be ok if
extern fixed_t tmfloorz, tmceilingz; // within tmfloorz - tmceilingz
extern line_t *ceilingline;
boolean P_TestMobjLocation(mobj_t *mobj);
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
mobj_t *P_CheckOnmobj(mobj_t *thing);
void P_FakeZMovement(mobj_t *mo);
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y);
boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y);
void P_SlideMove(mobj_t *mo);
boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
void P_UseLines(player_t *player);
boolean P_ChangeSector (sector_t *sector, boolean crunch);
extern mobj_t *linetarget; // who got hit (or NULL)
fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance);
void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage);
void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage);
// ***** P_SETUP *****
extern byte *rejectmatrix; // for fast sight rejection
extern short *blockmaplump; // offsets in blockmap are from here
extern short *blockmap;
extern int bmapwidth, bmapheight; // in mapblocks
extern fixed_t bmaporgx, bmaporgy; // origin of block map
extern mobj_t **blocklinks; // for thing chains
// ***** P_INTER *****
extern int maxammo[NUMAMMO];
extern int clipammo[NUMAMMO];
void P_SetMessage(player_t *player, char *message, boolean ultmsg);
void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher);
void P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source,
int damage);
boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int count);
boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo);
boolean P_GiveBody(player_t *player, int num);
boolean P_GivePower(player_t *player, powertype_t power);
boolean P_ChickenMorphPlayer(player_t *player);
// ***** AM_MAP *****
boolean AM_Responder(event_t *ev);
void AM_Ticker(void);
void AM_Drawer(void);
// ***** SB_BAR *****
extern int SB_state;
extern int ArtifactFlash;
void SB_PaletteFlash(void);
#include "P_spec.h"
#endif // __P_LOCAL__

1638
Heretic Source/P_MAP.C Normal file

File diff suppressed because it is too large Load Diff

760
Heretic Source/P_MAPUTL.C Normal file
View File

@ -0,0 +1,760 @@
// P_maputl.c
#include "DoomDef.h"
#include "P_local.h"
/*
===================
=
= P_AproxDistance
=
= Gives an estimation of distance (not exact)
=
===================
*/
fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
{
dx = abs(dx);
dy = abs(dy);
if (dx < dy)
return dx+dy-(dx>>1);
return dx+dy-(dy>>1);
}
/*
==================
=
= P_PointOnLineSide
=
= Returns 0 or 1
==================
*/
int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
{
fixed_t dx,dy;
fixed_t left, right;
if (!line->dx)
{
if (x <= line->v1->x)
return line->dy > 0;
return line->dy < 0;
}
if (!line->dy)
{
if (y <= line->v1->y)
return line->dx < 0;
return line->dx > 0;
}
dx = (x - line->v1->x);
dy = (y - line->v1->y);
left = FixedMul ( line->dy>>FRACBITS , dx );
right = FixedMul ( dy , line->dx>>FRACBITS );
if (right < left)
return 0; // front side
return 1; // back side
}
/*
=================
=
= P_BoxOnLineSide
=
= Considers the line to be infinite
= Returns side 0 or 1, -1 if box crosses the line
=================
*/
int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
{
int p1, p2;
switch (ld->slopetype)
{
case ST_HORIZONTAL:
p1 = tmbox[BOXTOP] > ld->v1->y;
p2 = tmbox[BOXBOTTOM] > ld->v1->y;
if (ld->dx < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_VERTICAL:
p1 = tmbox[BOXRIGHT] < ld->v1->x;
p2 = tmbox[BOXLEFT] < ld->v1->x;
if (ld->dy < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_POSITIVE:
p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
break;
case ST_NEGATIVE:
p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
break;
}
if (p1 == p2)
return p1;
return -1;
}
/*
==================
=
= P_PointOnDivlineSide
=
= Returns 0 or 1
==================
*/
int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
{
fixed_t dx,dy;
fixed_t left, right;
if (!line->dx)
{
if (x <= line->x)
return line->dy > 0;
return line->dy < 0;
}
if (!line->dy)
{
if (y <= line->y)
return line->dx < 0;
return line->dx > 0;
}
dx = (x - line->x);
dy = (y - line->y);
// try to quickly decide by looking at sign bits
if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
{
if ( (line->dy ^ dx) & 0x80000000 )
return 1; // (left is negative)
return 0;
}
left = FixedMul ( line->dy>>8, dx>>8 );
right = FixedMul ( dy>>8 , line->dx>>8 );
if (right < left)
return 0; // front side
return 1; // back side
}
/*
==============
=
= P_MakeDivline
=
==============
*/
void P_MakeDivline (line_t *li, divline_t *dl)
{
dl->x = li->v1->x;
dl->y = li->v1->y;
dl->dx = li->dx;
dl->dy = li->dy;
}
/*
===============
=
= P_InterceptVector
=
= Returns the fractional intercept point along the first divline
=
= This is only called by the addthings and addlines traversers
===============
*/
fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
{
#if 1
fixed_t frac, num, den;
den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
if (den == 0)
return 0;
// I_Error ("P_InterceptVector: parallel");
num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
frac = FixedDiv (num , den);
return frac;
#else
float frac, num, den, v1x,v1y,v1dx,v1dy,v2x,v2y,v2dx,v2dy;
v1x = (float)v1->x/FRACUNIT;
v1y = (float)v1->y/FRACUNIT;
v1dx = (float)v1->dx/FRACUNIT;
v1dy = (float)v1->dy/FRACUNIT;
v2x = (float)v2->x/FRACUNIT;
v2y = (float)v2->y/FRACUNIT;
v2dx = (float)v2->dx/FRACUNIT;
v2dy = (float)v2->dy/FRACUNIT;
den = v1dy*v2dx - v1dx*v2dy;
if (den == 0)
return 0; // parallel
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
frac = num / den;
return frac*FRACUNIT;
#endif
}
/*
==================
=
= P_LineOpening
=
= Sets opentop and openbottom to the window through a two sided line
= OPTIMIZE: keep this precalculated
==================
*/
fixed_t opentop, openbottom, openrange;
fixed_t lowfloor;
void P_LineOpening (line_t *linedef)
{
sector_t *front, *back;
if (linedef->sidenum[1] == -1)
{ // single sided line
openrange = 0;
return;
}
front = linedef->frontsector;
back = linedef->backsector;
if (front->ceilingheight < back->ceilingheight)
opentop = front->ceilingheight;
else
opentop = back->ceilingheight;
if (front->floorheight > back->floorheight)
{
openbottom = front->floorheight;
lowfloor = back->floorheight;
}
else
{
openbottom = back->floorheight;
lowfloor = front->floorheight;
}
openrange = opentop - openbottom;
}
/*
===============================================================================
THING POSITION SETTING
===============================================================================
*/
/*
===================
=
= P_UnsetThingPosition
=
= Unlinks a thing from block map and sectors
=
===================
*/
void P_UnsetThingPosition (mobj_t *thing)
{
int blockx, blocky;
if ( ! (thing->flags & MF_NOSECTOR) )
{ // inert things don't need to be in blockmap
// unlink from subsector
if (thing->snext)
thing->snext->sprev = thing->sprev;
if (thing->sprev)
thing->sprev->snext = thing->snext;
else
thing->subsector->sector->thinglist = thing->snext;
}
if ( ! (thing->flags & MF_NOBLOCKMAP) )
{ // inert things don't need to be in blockmap
// unlink from block map
if (thing->bnext)
thing->bnext->bprev = thing->bprev;
if (thing->bprev)
thing->bprev->bnext = thing->bnext;
else
{
blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
if (blockx>=0 && blockx < bmapwidth
&& blocky>=0 && blocky <bmapheight)
blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
}
}
}
/*
===================
=
= P_SetThingPosition
=
= Links a thing into both a block and a subsector based on it's x y
= Sets thing->subsector properly
=
===================
*/
void P_SetThingPosition (mobj_t *thing)
{
subsector_t *ss;
sector_t *sec;
int blockx, blocky;
mobj_t **link;
//
// link into subsector
//
ss = R_PointInSubsector (thing->x,thing->y);
thing->subsector = ss;
if ( ! (thing->flags & MF_NOSECTOR) )
{ // invisible things don't go into the sector links
sec = ss->sector;
thing->sprev = NULL;
thing->snext = sec->thinglist;
if (sec->thinglist)
sec->thinglist->sprev = thing;
sec->thinglist = thing;
}
//
// link into blockmap
//
if ( ! (thing->flags & MF_NOBLOCKMAP) )
{ // inert things don't need to be in blockmap
blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky <bmapheight)
{
link = &blocklinks[blocky*bmapwidth+blockx];
thing->bprev = NULL;
thing->bnext = *link;
if (*link)
(*link)->bprev = thing;
*link = thing;
}
else
{ // thing is off the map
thing->bnext = thing->bprev = NULL;
}
}
}
/*
===============================================================================
BLOCK MAP ITERATORS
For each line/thing in the given mapblock, call the passed function.
If the function returns false, exit with false without checking anything else.
===============================================================================
*/
/*
==================
=
= P_BlockLinesIterator
=
= The validcount flags are used to avoid checking lines
= that are marked in multiple mapblocks, so increment validcount before
= the first call to P_BlockLinesIterator, then make one or more calls to it
===================
*/
boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
{
int offset;
short *list;
line_t *ld;
if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
return true;
offset = y*bmapwidth+x;
offset = *(blockmap+offset);
for ( list = blockmaplump+offset ; *list != -1 ; list++)
{
ld = &lines[*list];
if (ld->validcount == validcount)
continue; // line has already been checked
ld->validcount = validcount;
if ( !func(ld) )
return false;
}
return true; // everything was checked
}
/*
==================
=
= P_BlockThingsIterator
=
==================
*/
boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
{
mobj_t *mobj;
if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
return true;
for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext)
if (!func( mobj ) )
return false;
return true;
}
/*
===============================================================================
INTERCEPT ROUTINES
===============================================================================
*/
intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
divline_t trace;
boolean earlyout;
int ptflags;
/*
==================
=
= PIT_AddLineIntercepts
=
= Looks for lines in the given block that intercept the given trace
= to add to the intercepts list
= A line is crossed if its endpoints are on opposite sides of the trace
= Returns true if earlyout and a solid line hit
==================
*/
boolean PIT_AddLineIntercepts (line_t *ld)
{
int s1, s2;
fixed_t frac;
divline_t dl;
// avoid precision problems with two routines
if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16
|| trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
{
s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
}
else
{
s1 = P_PointOnLineSide (trace.x, trace.y, ld);
s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
}
if (s1 == s2)
return true; // line isn't crossed
//
// hit the line
//
P_MakeDivline (ld, &dl);
frac = P_InterceptVector (&trace, &dl);
if (frac < 0)
return true; // behind source
// try to early out the check
if (earlyout && frac < FRACUNIT && !ld->backsector)
return false; // stop checking
intercept_p->frac = frac;
intercept_p->isaline = true;
intercept_p->d.line = ld;
intercept_p++;
return true; // continue
}
/*
==================
=
= PIT_AddThingIntercepts
=
==================
*/
boolean PIT_AddThingIntercepts (mobj_t *thing)
{
fixed_t x1,y1, x2,y2;
int s1, s2;
boolean tracepositive;
divline_t dl;
fixed_t frac;
tracepositive = (trace.dx ^ trace.dy)>0;
// check a corner to corner crossection for hit
if (tracepositive)
{
x1 = thing->x - thing->radius;
y1 = thing->y + thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y - thing->radius;
}
else
{
x1 = thing->x - thing->radius;
y1 = thing->y - thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y + thing->radius;
}
s1 = P_PointOnDivlineSide (x1, y1, &trace);
s2 = P_PointOnDivlineSide (x2, y2, &trace);
if (s1 == s2)
return true; // line isn't crossed
dl.x = x1;
dl.y = y1;
dl.dx = x2-x1;
dl.dy = y2-y1;
frac = P_InterceptVector (&trace, &dl);
if (frac < 0)
return true; // behind source
intercept_p->frac = frac;
intercept_p->isaline = false;
intercept_p->d.thing = thing;
intercept_p++;
return true; // keep going
}
/*
====================
=
= P_TraverseIntercepts
=
= Returns true if the traverser function returns true for all lines
====================
*/
boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac )
{
int count;
fixed_t dist;
intercept_t *scan, *in;
count = intercept_p - intercepts;
in = 0; // shut up compiler warning
while (count--)
{
dist = MAXINT;
for (scan = intercepts ; scan<intercept_p ; scan++)
if (scan->frac < dist)
{
dist = scan->frac;
in = scan;
}
if (dist > maxfrac)
return true; // checked everything in range
#if 0
{ // don't check these yet, ther may be others inserted
in = scan = intercepts;
for ( scan = intercepts ; scan<intercept_p ; scan++)
if (scan->frac > maxfrac)
*in++ = *scan;
intercept_p = in;
return false;
}
#endif
if ( !func (in) )
return false; // don't bother going farther
in->frac = MAXINT;
}
return true; // everything was traversed
}
/*
==================
=
= P_PathTraverse
=
= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
= Returns true if the traverser function returns true for all lines
==================
*/
boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
int flags, boolean (*trav) (intercept_t *))
{
fixed_t xt1,yt1,xt2,yt2;
fixed_t xstep,ystep;
fixed_t partial;
fixed_t xintercept, yintercept;
int mapx, mapy, mapxstep, mapystep;
int count;
earlyout = flags & PT_EARLYOUT;
validcount++;
intercept_p = intercepts;
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
y1 += FRACUNIT; // don't side exactly on a line
trace.x = x1;
trace.y = y1;
trace.dx = x2 - x1;
trace.dy = y2 - y1;
x1 -= bmaporgx;
y1 -= bmaporgy;
xt1 = x1>>MAPBLOCKSHIFT;
yt1 = y1>>MAPBLOCKSHIFT;
x2 -= bmaporgx;
y2 -= bmaporgy;
xt2 = x2>>MAPBLOCKSHIFT;
yt2 = y2>>MAPBLOCKSHIFT;
if (xt2 > xt1)
{
mapxstep = 1;
partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
ystep = FixedDiv (y2-y1,abs(x2-x1));
}
else if (xt2 < xt1)
{
mapxstep = -1;
partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
ystep = FixedDiv (y2-y1,abs(x2-x1));
}
else
{
mapxstep = 0;
partial = FRACUNIT;
ystep = 256*FRACUNIT;
}
yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
if (yt2 > yt1)
{
mapystep = 1;
partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
xstep = FixedDiv (x2-x1,abs(y2-y1));
}
else if (yt2 < yt1)
{
mapystep = -1;
partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
xstep = FixedDiv (x2-x1,abs(y2-y1));
}
else
{
mapystep = 0;
partial = FRACUNIT;
xstep = 256*FRACUNIT;
}
xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
//
// step through map blocks
// Count is present to prevent a round off error from skipping the break
mapx = xt1;
mapy = yt1;
for (count = 0 ; count < 64 ; count++)
{
if (flags & PT_ADDLINES)
{
if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
return false; // early out
}
if (flags & PT_ADDTHINGS)
{
if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
return false; // early out
}
if (mapx == xt2 && mapy == yt2)
break;
if ( (yintercept >> FRACBITS) == mapy)
{
yintercept += ystep;
mapx += mapxstep;
}
else if ( (xintercept >> FRACBITS) == mapx)
{
xintercept += xstep;
mapy += mapystep;
}
}
//
// go through the sorted list
//
return P_TraverseIntercepts ( trav, FRACUNIT );
}

1599
Heretic Source/P_MOBJ.C Normal file

File diff suppressed because it is too large Load Diff

240
Heretic Source/P_PLATS.C Normal file
View File

@ -0,0 +1,240 @@
// P_plats.c
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
plat_t *activeplats[MAXPLATS];
//==================================================================
//
// Move a plat up and down
//
//==================================================================
void T_PlatRaise(plat_t *plat)
{
result_e res;
switch(plat->status)
{
case up:
res = T_MovePlane(plat->sector,plat->speed,
plat->high,plat->crush,0,1);
if(!(leveltime&31))
{
S_StartSound((mobj_t *)&plat->sector->soundorg,
sfx_stnmov);
}
if(plat->type == raiseAndChange
|| plat->type == raiseToNearestAndChange)
{
if(!(leveltime&7))
{
S_StartSound((mobj_t *)&plat->sector->soundorg,
sfx_stnmov);
}
}
if (res == crushed && (!plat->crush))
{
plat->count = plat->wait;
plat->status = down;
S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart);
}
else
if (res == pastdest)
{
plat->count = plat->wait;
plat->status = waiting;
S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop);
switch(plat->type)
{
case downWaitUpStay:
P_RemoveActivePlat(plat);
break;
case raiseAndChange:
P_RemoveActivePlat(plat);
break;
default:
break;
}
}
break;
case down:
res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1);
if (res == pastdest)
{
plat->count = plat->wait;
plat->status = waiting;
S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop);
}
else
{
if(!(leveltime&31))
{
S_StartSound((mobj_t *)&plat->sector->soundorg,
sfx_stnmov);
}
}
break;
case waiting:
if (!--plat->count)
{
if (plat->sector->floorheight == plat->low)
plat->status = up;
else
plat->status = down;
S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart);
}
case in_stasis:
break;
}
}
//==================================================================
//
// Do Platforms
// "amount" is only used for SOME platforms.
//
//==================================================================
int EV_DoPlat(line_t *line,plattype_e type,int amount)
{
plat_t *plat;
int secnum;
int rtn;
sector_t *sec;
secnum = -1;
rtn = 0;
//
// Activate all <type> plats that are in_stasis
//
switch(type)
{
case perpetualRaise:
P_ActivateInStasis(line->tag);
break;
default:
break;
}
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
//
// Find lowest & highest floors around sector
//
rtn = 1;
plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
P_AddThinker(&plat->thinker);
plat->type = type;
plat->sector = sec;
plat->sector->specialdata = plat;
plat->thinker.function = T_PlatRaise;
plat->crush = false;
plat->tag = line->tag;
switch(type)
{
case raiseToNearestAndChange:
plat->speed = PLATSPEED/2;
sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
plat->high = P_FindNextHighestFloor(sec,sec->floorheight);
plat->wait = 0;
plat->status = up;
sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE
S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov);
break;
case raiseAndChange:
plat->speed = PLATSPEED/2;
sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
plat->high = sec->floorheight + amount*FRACUNIT;
plat->wait = 0;
plat->status = up;
S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov);
break;
case downWaitUpStay:
plat->speed = PLATSPEED * 4;
plat->low = P_FindLowestFloorSurrounding(sec);
if (plat->low > sec->floorheight)
plat->low = sec->floorheight;
plat->high = sec->floorheight;
plat->wait = 35*PLATWAIT;
plat->status = down;
S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart);
break;
case perpetualRaise:
plat->speed = PLATSPEED;
plat->low = P_FindLowestFloorSurrounding(sec);
if (plat->low > sec->floorheight)
plat->low = sec->floorheight;
plat->high = P_FindHighestFloorSurrounding(sec);
if (plat->high < sec->floorheight)
plat->high = sec->floorheight;
plat->wait = 35*PLATWAIT;
plat->status = P_Random()&1;
S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart);
break;
}
P_AddActivePlat(plat);
}
return rtn;
}
void P_ActivateInStasis(int tag)
{
int i;
for (i = 0;i < MAXPLATS;i++)
if (activeplats[i] &&
(activeplats[i])->tag == tag &&
(activeplats[i])->status == in_stasis)
{
(activeplats[i])->status = (activeplats[i])->oldstatus;
(activeplats[i])->thinker.function = T_PlatRaise;
}
}
void EV_StopPlat(line_t *line)
{
int j;
for (j = 0;j < MAXPLATS;j++)
if (activeplats[j] && ((activeplats[j])->status != in_stasis) &&
((activeplats[j])->tag == line->tag))
{
(activeplats[j])->oldstatus = (activeplats[j])->status;
(activeplats[j])->status = in_stasis;
(activeplats[j])->thinker.function = NULL;
}
}
void P_AddActivePlat(plat_t *plat)
{
int i;
for (i = 0;i < MAXPLATS;i++)
if (activeplats[i] == NULL)
{
activeplats[i] = plat;
return;
}
I_Error ("P_AddActivePlat: no more plats!");
}
void P_RemoveActivePlat(plat_t *plat)
{
int i;
for (i = 0;i < MAXPLATS;i++)
if (plat == activeplats[i])
{
(activeplats[i])->sector->specialdata = NULL;
P_RemoveThinker(&(activeplats[i])->thinker);
activeplats[i] = NULL;
return;
}
I_Error ("P_RemoveActivePlat: can't find plat!");
}

1869
Heretic Source/P_PSPR.C Normal file

File diff suppressed because it is too large Load Diff

624
Heretic Source/P_SETUP.C Normal file
View File

@ -0,0 +1,624 @@
// P_main.c
#include <math.h>
#include <stdlib.h>
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
void P_SpawnMapThing (mapthing_t *mthing);
int numvertexes;
vertex_t *vertexes;
int numsegs;
seg_t *segs;
int numsectors;
sector_t *sectors;
int numsubsectors;
subsector_t *subsectors;
int numnodes;
node_t *nodes;
int numlines;
line_t *lines;
int numsides;
side_t *sides;
short *blockmaplump; // offsets in blockmap are from here
short *blockmap;
int bmapwidth, bmapheight; // in mapblocks
fixed_t bmaporgx, bmaporgy; // origin of block map
mobj_t **blocklinks; // for thing chains
byte *rejectmatrix; // for fast sight rejection
mapthing_t deathmatchstarts[10], *deathmatch_p;
mapthing_t playerstarts[MAXPLAYERS];
/*
=================
=
= P_LoadVertexes
=
=================
*/
void P_LoadVertexes (int lump)
{
byte *data;
int i;
mapvertex_t *ml;
vertex_t *li;
numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
data = W_CacheLumpNum (lump,PU_STATIC);
ml = (mapvertex_t *)data;
li = vertexes;
for (i=0 ; i<numvertexes ; i++, li++, ml++)
{
li->x = SHORT(ml->x)<<FRACBITS;
li->y = SHORT(ml->y)<<FRACBITS;
}
Z_Free (data);
}
/*
=================
=
= P_LoadSegs
=
=================
*/
void P_LoadSegs (int lump)
{
byte *data;
int i;
mapseg_t *ml;
seg_t *li;
line_t *ldef;
int linedef, side;
numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
memset (segs, 0, numsegs*sizeof(seg_t));
data = W_CacheLumpNum (lump,PU_STATIC);
ml = (mapseg_t *)data;
li = segs;
for (i=0 ; i<numsegs ; i++, li++, ml++)
{
li->v1 = &vertexes[SHORT(ml->v1)];
li->v2 = &vertexes[SHORT(ml->v2)];
li->angle = (SHORT(ml->angle))<<16;
li->offset = (SHORT(ml->offset))<<16;
linedef = SHORT(ml->linedef);
ldef = &lines[linedef];
li->linedef = ldef;
side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
if (ldef-> flags & ML_TWOSIDED)
li->backsector = sides[ldef->sidenum[side^1]].sector;
else
li->backsector = 0;
}
Z_Free (data);
}
/*
=================
=
= P_LoadSubsectors
=
=================
*/
void P_LoadSubsectors (int lump)
{
byte *data;
int i;
mapsubsector_t *ms;
subsector_t *ss;
numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
data = W_CacheLumpNum (lump,PU_STATIC);
ms = (mapsubsector_t *)data;
memset (subsectors,0, numsubsectors*sizeof(subsector_t));
ss = subsectors;
for (i=0 ; i<numsubsectors ; i++, ss++, ms++)
{
ss->numlines = SHORT(ms->numsegs);
ss->firstline = SHORT(ms->firstseg);
}
Z_Free (data);
}
/*
=================
=
= P_LoadSectors
=
=================
*/
void P_LoadSectors (int lump)
{
byte *data;
int i;
mapsector_t *ms;
sector_t *ss;
numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0);
memset (sectors, 0, numsectors*sizeof(sector_t));
data = W_CacheLumpNum (lump,PU_STATIC);
ms = (mapsector_t *)data;
ss = sectors;
for (i=0 ; i<numsectors ; i++, ss++, ms++)
{
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
ss->floorpic = R_FlatNumForName(ms->floorpic);
ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
ss->lightlevel = SHORT(ms->lightlevel);
ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag);
ss->thinglist = NULL;
}
Z_Free (data);
}
/*
=================
=
= P_LoadNodes
=
=================
*/
void P_LoadNodes (int lump)
{
byte *data;
int i,j,k;
mapnode_t *mn;
node_t *no;
numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
data = W_CacheLumpNum (lump,PU_STATIC);
mn = (mapnode_t *)data;
no = nodes;
for (i=0 ; i<numnodes ; i++, no++, mn++)
{
no->x = SHORT(mn->x)<<FRACBITS;
no->y = SHORT(mn->y)<<FRACBITS;
no->dx = SHORT(mn->dx)<<FRACBITS;
no->dy = SHORT(mn->dy)<<FRACBITS;
for (j=0 ; j<2 ; j++)
{
no->children[j] = SHORT(mn->children[j]);
for (k=0 ; k<4 ; k++)
no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
}
}
Z_Free (data);
}
/*
=================
=
= P_LoadThings
=
=================
*/
void P_LoadThings (int lump)
{
byte *data;
int i;
mapthing_t *mt;
int numthings;
data = W_CacheLumpNum (lump,PU_STATIC);
numthings = W_LumpLength (lump) / sizeof(mapthing_t);
mt = (mapthing_t *)data;
for (i=0 ; i<numthings ; i++, mt++)
{
mt->x = SHORT(mt->x);
mt->y = SHORT(mt->y);
mt->angle = SHORT(mt->angle);
mt->type = SHORT(mt->type);
mt->options = SHORT(mt->options);
P_SpawnMapThing (mt);
}
Z_Free (data);
}
/*
=================
=
= P_LoadLineDefs
=
= Also counts secret lines for intermissions
=================
*/
void P_LoadLineDefs (int lump)
{
byte *data;
int i;
maplinedef_t *mld;
line_t *ld;
vertex_t *v1, *v2;
numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0);
memset (lines, 0, numlines*sizeof(line_t));
data = W_CacheLumpNum (lump,PU_STATIC);
mld = (maplinedef_t *)data;
ld = lines;
for (i=0 ; i<numlines ; i++, mld++, ld++)
{
ld->flags = SHORT(mld->flags);
ld->special = SHORT(mld->special);
ld->tag = SHORT(mld->tag);
v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y;
if (!ld->dx)
ld->slopetype = ST_VERTICAL;
else if (!ld->dy)
ld->slopetype = ST_HORIZONTAL;
else
{
if (FixedDiv (ld->dy , ld->dx) > 0)
ld->slopetype = ST_POSITIVE;
else
ld->slopetype = ST_NEGATIVE;
}
if (v1->x < v2->x)
{
ld->bbox[BOXLEFT] = v1->x;
ld->bbox[BOXRIGHT] = v2->x;
}
else
{
ld->bbox[BOXLEFT] = v2->x;
ld->bbox[BOXRIGHT] = v1->x;
}
if (v1->y < v2->y)
{
ld->bbox[BOXBOTTOM] = v1->y;
ld->bbox[BOXTOP] = v2->y;
}
else
{
ld->bbox[BOXBOTTOM] = v2->y;
ld->bbox[BOXTOP] = v1->y;
}
ld->sidenum[0] = SHORT(mld->sidenum[0]);
ld->sidenum[1] = SHORT(mld->sidenum[1]);
if (ld->sidenum[0] != -1)
ld->frontsector = sides[ld->sidenum[0]].sector;
else
ld->frontsector = 0;
if (ld->sidenum[1] != -1)
ld->backsector = sides[ld->sidenum[1]].sector;
else
ld->backsector = 0;
}
Z_Free (data);
}
/*
=================
=
= P_LoadSideDefs
=
=================
*/
void P_LoadSideDefs (int lump)
{
byte *data;
int i;
mapsidedef_t *msd;
side_t *sd;
numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0);
memset (sides, 0, numsides*sizeof(side_t));
data = W_CacheLumpNum (lump,PU_STATIC);
msd = (mapsidedef_t *)data;
sd = sides;
for (i=0 ; i<numsides ; i++, msd++, sd++)
{
sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
sd->toptexture = R_TextureNumForName(msd->toptexture);
sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
sd->midtexture = R_TextureNumForName(msd->midtexture);
sd->sector = &sectors[SHORT(msd->sector)];
}
Z_Free (data);
}
/*
=================
=
= P_LoadBlockMap
=
=================
*/
void P_LoadBlockMap (int lump)
{
int i, count;
blockmaplump = W_CacheLumpNum (lump,PU_LEVEL);
blockmap = blockmaplump+4;
count = W_LumpLength (lump)/2;
for (i=0 ; i<count ; i++)
blockmaplump[i] = SHORT(blockmaplump[i]);
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
// clear out mobj chains
count = sizeof(*blocklinks)* bmapwidth*bmapheight;
blocklinks = Z_Malloc (count,PU_LEVEL, 0);
memset (blocklinks, 0, count);
}
/*
=================
=
= P_GroupLines
=
= Builds sector line lists and subsector sector numbers
= Finds block bounding boxes for sectors
=================
*/
void P_GroupLines (void)
{
line_t **linebuffer;
int i, j, total;
line_t *li;
sector_t *sector;
subsector_t *ss;
seg_t *seg;
fixed_t bbox[4];
int block;
// look up sector number for each subsector
ss = subsectors;
for (i=0 ; i<numsubsectors ; i++, ss++)
{
seg = &segs[ss->firstline];
ss->sector = seg->sidedef->sector;
}
// count number of lines in each sector
li = lines;
total = 0;
for (i=0 ; i<numlines ; i++, li++)
{
total++;
li->frontsector->linecount++;
if (li->backsector && li->backsector != li->frontsector)
{
li->backsector->linecount++;
total++;
}
}
// build line tables for each sector
linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
sector = sectors;
for (i=0 ; i<numsectors ; i++, sector++)
{
M_ClearBox (bbox);
sector->lines = linebuffer;
li = lines;
for (j=0 ; j<numlines ; j++, li++)
{
if (li->frontsector == sector || li->backsector == sector)
{
*linebuffer++ = li;
M_AddToBox (bbox, li->v1->x, li->v1->y);
M_AddToBox (bbox, li->v2->x, li->v2->y);
}
}
if (linebuffer - sector->lines != sector->linecount)
I_Error ("P_GroupLines: miscounted");
// set the degenmobj_t to the middle of the bounding box
sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
// adjust bounding box to map blocks
block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
block = block >= bmapheight ? bmapheight-1 : block;
sector->blockbox[BOXTOP]=block;
block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
sector->blockbox[BOXBOTTOM]=block;
block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
block = block >= bmapwidth ? bmapwidth-1 : block;
sector->blockbox[BOXRIGHT]=block;
block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
sector->blockbox[BOXLEFT]=block;
}
}
//=============================================================================
/*
=================
=
= P_SetupLevel
=
=================
*/
void P_SetupLevel (int episode, int map, int playermask, skill_t skill)
{
int i;
int parm;
char lumpname[9];
int lumpnum;
mobj_t *mobj;
totalkills = totalitems = totalsecret = 0;
for (i=0 ; i<MAXPLAYERS ; i++)
{
players[i].killcount = players[i].secretcount
= players[i].itemcount = 0;
}
players[consoleplayer].viewz = 1; // will be set by player think
S_Start (); // make sure all sounds are stopped before Z_FreeTags
Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
P_InitThinkers ();
//
// look for a regular (development) map first
//
lumpname[0] = 'E';
lumpname[1] = '0' + episode;
lumpname[2] = 'M';
lumpname[3] = '0' + map;
lumpname[4] = 0;
leveltime = 0;
lumpnum = W_GetNumForName (lumpname);
// note: most of this ordering is important
P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
P_LoadVertexes (lumpnum+ML_VERTEXES);
P_LoadSectors (lumpnum+ML_SECTORS);
P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
P_LoadLineDefs (lumpnum+ML_LINEDEFS);
P_LoadSubsectors (lumpnum+ML_SSECTORS);
P_LoadNodes (lumpnum+ML_NODES);
P_LoadSegs (lumpnum+ML_SEGS);
rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
P_GroupLines ();
bodyqueslot = 0;
deathmatch_p = deathmatchstarts;
P_InitAmbientSound();
P_InitMonsters();
P_OpenWeapons();
P_LoadThings(lumpnum+ML_THINGS);
P_CloseWeapons();
//
// if deathmatch, randomly spawn the active players
//
TimerGame = 0;
if(deathmatch)
{
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (playeringame[i])
{ // must give a player spot before deathmatchspawn
mobj = P_SpawnMobj (playerstarts[i].x<<16,
playerstarts[i].y<<16,0, MT_PLAYER);
players[i].mo = mobj;
G_DeathMatchSpawnPlayer (i);
P_RemoveMobj (mobj);
}
}
parm = M_CheckParm("-timer");
if(parm && parm < myargc-1)
{
TimerGame = atoi(myargv[parm+1])*35*60;
}
}
// set up world state
P_SpawnSpecials ();
// build subsector connect matrix
// P_ConnectSubsectors ();
// preload graphics
if (precache)
R_PrecacheLevel ();
//printf ("free memory: 0x%x\n", Z_FreeMemory());
}
/*
=================
=
= P_Init
=
=================
*/
void P_Init (void)
{
P_InitSwitchList();
P_InitPicAnims();
P_InitTerrainTypes();
P_InitLava();
R_InitSprites(sprnames);
}

340
Heretic Source/P_SIGHT.C Normal file
View File

@ -0,0 +1,340 @@
// P_sight.c
#include "DoomDef.h"
#include "P_local.h"
/*
==============================================================================
P_CheckSight
This uses specialized forms of the maputils routines for optimized performance
==============================================================================
*/
fixed_t sightzstart; // eye z of looker
fixed_t topslope, bottomslope; // slopes to top and bottom of target
int sightcounts[3];
/*
==============
=
= PTR_SightTraverse
=
==============
*/
boolean PTR_SightTraverse (intercept_t *in)
{
line_t *li;
fixed_t slope;
li = in->d.line;
//
// crosses a two sided line
//
P_LineOpening (li);
if (openbottom >= opentop) // quick test for totally closed doors
return false; // stop
if (li->frontsector->floorheight != li->backsector->floorheight)
{
slope = FixedDiv (openbottom - sightzstart , in->frac);
if (slope > bottomslope)
bottomslope = slope;
}
if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
{
slope = FixedDiv (opentop - sightzstart , in->frac);
if (slope < topslope)
topslope = slope;
}
if (topslope <= bottomslope)
return false; // stop
return true; // keep going
}
/*
==================
=
= P_SightBlockLinesIterator
=
===================
*/
boolean P_SightBlockLinesIterator (int x, int y )
{
int offset;
short *list;
line_t *ld;
int s1, s2;
divline_t dl;
offset = y*bmapwidth+x;
offset = *(blockmap+offset);
for ( list = blockmaplump+offset ; *list != -1 ; list++)
{
ld = &lines[*list];
if (ld->validcount == validcount)
continue; // line has already been checked
ld->validcount = validcount;
s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
if (s1 == s2)
continue; // line isn't crossed
P_MakeDivline (ld, &dl);
s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
if (s1 == s2)
continue; // line isn't crossed
// try to early out the check
if (!ld->backsector)
return false; // stop checking
// store the line for later intersection testing
intercept_p->d.line = ld;
intercept_p++;
}
return true; // everything was checked
}
/*
====================
=
= P_SightTraverseIntercepts
=
= Returns true if the traverser function returns true for all lines
====================
*/
boolean P_SightTraverseIntercepts ( void )
{
int count;
fixed_t dist;
intercept_t *scan, *in;
divline_t dl;
count = intercept_p - intercepts;
//
// calculate intercept distance
//
for (scan = intercepts ; scan<intercept_p ; scan++)
{
P_MakeDivline (scan->d.line, &dl);
scan->frac = P_InterceptVector (&trace, &dl);
}
//
// go through in order
//
in = 0; // shut up compiler warning
while (count--)
{
dist = MAXINT;
for (scan = intercepts ; scan<intercept_p ; scan++)
if (scan->frac < dist)
{
dist = scan->frac;
in = scan;
}
if ( !PTR_SightTraverse (in) )
return false; // don't bother going farther
in->frac = MAXINT;
}
return true; // everything was traversed
}
/*
==================
=
= P_SightPathTraverse
=
= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
= Returns true if the traverser function returns true for all lines
==================
*/
boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{
fixed_t xt1,yt1,xt2,yt2;
fixed_t xstep,ystep;
fixed_t partial;
fixed_t xintercept, yintercept;
int mapx, mapy, mapxstep, mapystep;
int count;
validcount++;
intercept_p = intercepts;
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
y1 += FRACUNIT; // don't side exactly on a line
trace.x = x1;
trace.y = y1;
trace.dx = x2 - x1;
trace.dy = y2 - y1;
x1 -= bmaporgx;
y1 -= bmaporgy;
xt1 = x1>>MAPBLOCKSHIFT;
yt1 = y1>>MAPBLOCKSHIFT;
x2 -= bmaporgx;
y2 -= bmaporgy;
xt2 = x2>>MAPBLOCKSHIFT;
yt2 = y2>>MAPBLOCKSHIFT;
// points should never be out of bounds, but check once instead of
// each block
if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
|| xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
return false;
if (xt2 > xt1)
{
mapxstep = 1;
partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
ystep = FixedDiv (y2-y1,abs(x2-x1));
}
else if (xt2 < xt1)
{
mapxstep = -1;
partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
ystep = FixedDiv (y2-y1,abs(x2-x1));
}
else
{
mapxstep = 0;
partial = FRACUNIT;
ystep = 256*FRACUNIT;
}
yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
if (yt2 > yt1)
{
mapystep = 1;
partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
xstep = FixedDiv (x2-x1,abs(y2-y1));
}
else if (yt2 < yt1)
{
mapystep = -1;
partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
xstep = FixedDiv (x2-x1,abs(y2-y1));
}
else
{
mapystep = 0;
partial = FRACUNIT;
xstep = 256*FRACUNIT;
}
xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
//
// step through map blocks
// Count is present to prevent a round off error from skipping the break
mapx = xt1;
mapy = yt1;
for (count = 0 ; count < 64 ; count++)
{
if (!P_SightBlockLinesIterator (mapx, mapy))
{
sightcounts[1]++;
return false; // early out
}
if (mapx == xt2 && mapy == yt2)
break;
if ( (yintercept >> FRACBITS) == mapy)
{
yintercept += ystep;
mapx += mapxstep;
}
else if ( (xintercept >> FRACBITS) == mapx)
{
xintercept += xstep;
mapy += mapystep;
}
}
//
// couldn't early out, so go through the sorted list
//
sightcounts[2]++;
return P_SightTraverseIntercepts ( );
}
/*
=====================
=
= P_CheckSight
=
= Returns true if a straight line between t1 and t2 is unobstructed
= look from eyes of t1 to any part of t2
=
=====================
*/
boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
{
int s1, s2;
int pnum, bytenum, bitnum;
//
// check for trivial rejection
//
s1 = (t1->subsector->sector - sectors);
s2 = (t2->subsector->sector - sectors);
pnum = s1*numsectors + s2;
bytenum = pnum>>3;
bitnum = 1 << (pnum&7);
if (rejectmatrix[bytenum]&bitnum)
{
sightcounts[0]++;
return false; // can't possibly be connected
}
//
// check precisely
//
sightzstart = t1->z + t1->height - (t1->height>>2);
topslope = (t2->z+t2->height) - sightzstart;
bottomslope = (t2->z) - sightzstart;
return P_SightPathTraverse ( t1->x, t1->y, t2->x, t2->y );
}

1253
Heretic Source/P_SPEC.C Normal file

File diff suppressed because it is too large Load Diff

374
Heretic Source/P_SPEC.H Normal file
View File

@ -0,0 +1,374 @@
// P_spec.h
/*
===============================================================================
P_SPEC
===============================================================================
*/
//
// Animating textures and planes
//
typedef struct
{
boolean istexture;
int picnum;
int basepic;
int numpics;
int speed;
} anim_t;
//
// source animation definition
//
typedef struct
{
boolean istexture; // if false, it's a flat
char endname[9];
char startname[9];
int speed;
} animdef_t;
#define MAXANIMS 32
extern anim_t anims[MAXANIMS], *lastanim;
extern int *TerrainTypes;
//
// Animating line specials
//
#define MAXLINEANIMS 64
extern short numlinespecials;
extern line_t *linespeciallist[MAXLINEANIMS];
// Define values for map objects
#define MO_TELEPORTMAN 14
// at game start
void P_InitPicAnims(void);
void P_InitTerrainTypes(void);
void P_InitLava(void);
// at map load
void P_SpawnSpecials(void);
void P_InitAmbientSound(void);
void P_AddAmbientSfx(int sequence);
// every tic
void P_UpdateSpecials(void);
void P_AmbientSound(void);
// when needed
boolean P_UseSpecialLine ( mobj_t *thing, line_t *line);
void P_ShootSpecialLine ( mobj_t *thing, line_t *line);
void P_CrossSpecialLine (int linenum, int side, mobj_t *thing);
void P_PlayerInSpecialSector (player_t *player);
int twoSided(int sector,int line);
sector_t *getSector(int currentSector,int line,int side);
side_t *getSide(int currentSector,int line, int side);
fixed_t P_FindLowestFloorSurrounding(sector_t *sec);
fixed_t P_FindHighestFloorSurrounding(sector_t *sec);
fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight);
fixed_t P_FindLowestCeilingSurrounding(sector_t *sec);
fixed_t P_FindHighestCeilingSurrounding(sector_t *sec);
int P_FindSectorFromLineTag(line_t *line,int start);
int P_FindMinSurroundingLight(sector_t *sector,int max);
sector_t *getNextSector(line_t *line,sector_t *sec);
//
// SPECIAL
//
int EV_DoDonut(line_t *line);
/*
===============================================================================
P_LIGHTS
===============================================================================
*/
typedef struct
{
thinker_t thinker;
sector_t *sector;
int count;
int maxlight;
int minlight;
int maxtime;
int mintime;
} lightflash_t;
typedef struct
{
thinker_t thinker;
sector_t *sector;
int count;
int minlight;
int maxlight;
int darktime;
int brighttime;
} strobe_t;
typedef struct
{
thinker_t thinker;
sector_t *sector;
int minlight;
int maxlight;
int direction;
} glow_t;
#define GLOWSPEED 8
#define STROBEBRIGHT 5
#define FASTDARK 15
#define SLOWDARK 35
void T_LightFlash (lightflash_t *flash);
void P_SpawnLightFlash (sector_t *sector);
void T_StrobeFlash (strobe_t *flash);
void P_SpawnStrobeFlash (sector_t *sector, int fastOrSlow, int inSync);
void EV_StartLightStrobing(line_t *line);
void EV_TurnTagLightsOff(line_t *line);
void EV_LightTurnOn(line_t *line, int bright);
void T_Glow(glow_t *g);
void P_SpawnGlowingLight(sector_t *sector);
/*
===============================================================================
P_SWITCH
===============================================================================
*/
typedef struct
{
char name1[9];
char name2[9];
short episode;
} switchlist_t;
typedef enum
{
top,
middle,
bottom
} bwhere_e;
typedef struct
{
line_t *line;
bwhere_e where;
int btexture;
int btimer;
mobj_t *soundorg;
} button_t;
#define MAXSWITCHES 50 // max # of wall switches in a level
#define MAXBUTTONS 16 // 4 players, 4 buttons each at once, max.
#define BUTTONTIME 35 // 1 second
extern button_t buttonlist[MAXBUTTONS];
void P_ChangeSwitchTexture(line_t *line,int useAgain);
void P_InitSwitchList(void);
/*
===============================================================================
P_PLATS
===============================================================================
*/
typedef enum
{
up,
down,
waiting,
in_stasis
} plat_e;
typedef enum
{
perpetualRaise,
downWaitUpStay,
raiseAndChange,
raiseToNearestAndChange
} plattype_e;
typedef struct
{
thinker_t thinker;
sector_t *sector;
fixed_t speed;
fixed_t low;
fixed_t high;
int wait;
int count;
plat_e status;
plat_e oldstatus;
boolean crush;
int tag;
plattype_e type;
} plat_t;
#define PLATWAIT 3
#define PLATSPEED FRACUNIT
#define MAXPLATS 30
extern plat_t *activeplats[MAXPLATS];
void T_PlatRaise(plat_t *plat);
int EV_DoPlat(line_t *line,plattype_e type,int amount);
void P_AddActivePlat(plat_t *plat);
void P_RemoveActivePlat(plat_t *plat);
void EV_StopPlat(line_t *line);
void P_ActivateInStasis(int tag);
/*
===============================================================================
P_DOORS
===============================================================================
*/
typedef enum
{
normal,
close30ThenOpen,
close,
open,
raiseIn5Mins
} vldoor_e;
typedef struct
{
thinker_t thinker;
vldoor_e type;
sector_t *sector;
fixed_t topheight;
fixed_t speed;
int direction; // 1 = up, 0 = waiting at top, -1 = down
int topwait; // tics to wait at the top
// (keep in case a door going down is reset)
int topcountdown; // when it reaches 0, start going down
} vldoor_t;
#define VDOORSPEED FRACUNIT*2
#define VDOORWAIT 150
void EV_VerticalDoor (line_t *line, mobj_t *thing);
int EV_DoDoor (line_t *line, vldoor_e type, fixed_t speed);
void T_VerticalDoor (vldoor_t *door);
void P_SpawnDoorCloseIn30 (sector_t *sec);
void P_SpawnDoorRaiseIn5Mins (sector_t *sec, int secnum);
/*
===============================================================================
P_CEILNG
===============================================================================
*/
typedef enum
{
lowerToFloor,
raiseToHighest,
lowerAndCrush,
crushAndRaise,
fastCrushAndRaise
} ceiling_e;
typedef struct
{
thinker_t thinker;
ceiling_e type;
sector_t *sector;
fixed_t bottomheight, topheight;
fixed_t speed;
boolean crush;
int direction; // 1 = up, 0 = waiting, -1 = down
int tag; // ID
int olddirection;
} ceiling_t;
#define CEILSPEED FRACUNIT
#define CEILWAIT 150
#define MAXCEILINGS 30
extern ceiling_t *activeceilings[MAXCEILINGS];
int EV_DoCeiling (line_t *line, ceiling_e type);
void T_MoveCeiling (ceiling_t *ceiling);
void P_AddActiveCeiling(ceiling_t *c);
void P_RemoveActiveCeiling(ceiling_t *c);
int EV_CeilingCrushStop(line_t *line);
void P_ActivateInStasisCeiling(line_t *line);
/*
===============================================================================
P_FLOOR
===============================================================================
*/
typedef enum
{
lowerFloor, // lower floor to highest surrounding floor
lowerFloorToLowest, // lower floor to lowest surrounding floor
turboLower, // lower floor to highest surrounding floor VERY FAST
raiseFloor, // raise floor to lowest surrounding CEILING
raiseFloorToNearest, // raise floor to next highest surrounding floor
raiseToTexture, // raise floor to shortest height texture around it
lowerAndChange, // lower floor to lowest surrounding floor and change
// floorpic
raiseFloor24,
raiseFloor24AndChange,
raiseFloorCrush,
donutRaise,
raiseBuildStep // One step of a staircase
} floor_e;
typedef struct
{
thinker_t thinker;
floor_e type;
boolean crush;
sector_t *sector;
int direction;
int newspecial;
short texture;
fixed_t floordestheight;
fixed_t speed;
} floormove_t;
#define FLOORSPEED FRACUNIT
typedef enum
{
ok,
crushed,
pastdest
} result_e;
result_e T_MovePlane(sector_t *sector,fixed_t speed,
fixed_t dest,boolean crush,int floorOrCeiling,int direction);
int EV_BuildStairs(line_t *line, fixed_t stepDelta);
int EV_DoFloor(line_t *line,floor_e floortype);
void T_MoveFloor(floormove_t *floor);
/*
===============================================================================
P_TELEPT
===============================================================================
*/
boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle);
boolean EV_Teleport(line_t *line, int side, mobj_t *thing);

390
Heretic Source/P_SWITCH.C Normal file
View File

@ -0,0 +1,390 @@
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
//==================================================================
//
// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
//
//==================================================================
switchlist_t alphSwitchList[] =
{
{"SW1OFF", "SW1ON", 1},
{"SW2OFF", "SW2ON", 1},
/*
{"SW1CTY", "SW2CTY", 1},
{"SW1ORGRY", "SW2ORGRY", 1},
{"SW1GRSTN", "SW2GRSTN", 1},
{"SW1SNDP", "SW2SNDP", 1},
{"SW1SPINE", "SW2SPINE", 1},
{"SW1SQPEB", "SW2SQPEB", 1},
{"SW1TRST1", "SW2TRST1", 1},
{"SW1CSTL", "SW2CSTL", 1},
{"SW1MOSS", "SW2MOSS", 1},
{"SW1SNDSQ", "SW2SNDSQ", 1},
{"SW1RED", "SW2RED", 1},
{"SW1WOOD", "SW2WOOD", 1},
{"SW1BROWN", "SW2BROWN", 1},
{"SW1TRST2", "SW2TRST2", 2},
{"SW1MSC", "SW2MSC", 2},
{"SW1MSC2", "SW2MSC2", 2},
{"SW1GRDMD", "SW2GRDMD", 2},
*/
#if 0
{"SW1BRCOM", "SW2BRCOM", 1},
{"SW1BRN1", "SW2BRN1", 1},
{"SW1BRN2", "SW2BRN2", 1},
{"SW1BRNGN", "SW2BRNGN", 1},
{"SW1BROWN", "SW2BROWN", 1},
{"SW1COMM", "SW2COMM", 1},
{"SW1COMP", "SW2COMP", 1},
{"SW1DIRT", "SW2DIRT", 1},
{"SW1EXIT", "SW2EXIT", 1},
{"SW1GRAY", "SW2GRAY", 1},
{"SW1GRAY1", "SW2GRAY1", 1},
{"SW1METAL", "SW2METAL", 1},
{"SW1PIPE", "SW2PIPE", 1},
{"SW1SLAD", "SW2SLAD", 1},
{"SW1STARG", "SW2STARG", 1},
{"SW1STON1", "SW2STON1", 1},
{"SW1STON2", "SW2STON2", 1},
{"SW1STONE", "SW2STONE", 1},
{"SW1STRTN", "SW2STRTN", 1},
{"SW1BLUE", "SW2BLUE", 2},
{"SW1CMT", "SW2CMT", 2},
{"SW1GARG", "SW2GARG", 2},
{"SW1GSTON", "SW2GSTON", 2},
{"SW1HOT", "SW2HOT", 2},
{"SW1LION", "SW2LION", 2},
{"SW1SATYR", "SW2SATYR", 2},
{"SW1SKIN", "SW2SKIN", 2},
{"SW1VINE", "SW2VINE", 2},
{"SW1WOOD", "SW2WOOD", 2},
#endif
{"\0", "\0", 0}
};
int switchlist[MAXSWITCHES * 2];
int numswitches;
button_t buttonlist[MAXBUTTONS];
/*
===============
=
= P_InitSwitchList
=
= Only called at game initialization
=
===============
*/
void P_InitSwitchList(void)
{
int i;
int index;
int episode;
episode = 1;
if (!shareware)
episode = 2;
for (index = 0,i = 0;i < MAXSWITCHES;i++)
{
if (!alphSwitchList[i].episode)
{
numswitches = index/2;
switchlist[index] = -1;
break;
}
if (alphSwitchList[i].episode <= episode)
{
switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1);
switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2);
}
}
}
//==================================================================
//
// Start a button counting down till it turns off.
//
//==================================================================
void P_StartButton(line_t *line,bwhere_e w,int texture,int time)
{
int i;
for (i = 0;i < MAXBUTTONS;i++)
if (!buttonlist[i].btimer)
{
buttonlist[i].line = line;
buttonlist[i].where = w;
buttonlist[i].btexture = texture;
buttonlist[i].btimer = time;
buttonlist[i].soundorg = (mobj_t *)&line->frontsector->soundorg;
return;
}
I_Error("P_StartButton: no button slots left!");
}
//==================================================================
//
// Function that changes wall texture.
// Tell it if switch is ok to use again (1=yes, it's a button).
//
//==================================================================
void P_ChangeSwitchTexture(line_t *line,int useAgain)
{
int texTop;
int texMid;
int texBot;
int i;
int sound;
if (!useAgain)
line->special = 0;
texTop = sides[line->sidenum[0]].toptexture;
texMid = sides[line->sidenum[0]].midtexture;
texBot = sides[line->sidenum[0]].bottomtexture;
sound = sfx_switch;
//if (line->special == 11) // EXIT SWITCH?
// sound = sfx_swtchx;
for (i = 0;i < numswitches*2;i++)
if (switchlist[i] == texTop)
{
S_StartSound(buttonlist->soundorg,sound);
sides[line->sidenum[0]].toptexture = switchlist[i^1];
if (useAgain)
P_StartButton(line,top,switchlist[i],BUTTONTIME);
return;
}
else
if (switchlist[i] == texMid)
{
S_StartSound(buttonlist->soundorg,sound);
sides[line->sidenum[0]].midtexture = switchlist[i^1];
if (useAgain)
P_StartButton(line, middle,switchlist[i],BUTTONTIME);
return;
}
else
if (switchlist[i] == texBot)
{
S_StartSound(buttonlist->soundorg,sound);
sides[line->sidenum[0]].bottomtexture = switchlist[i^1];
if (useAgain)
P_StartButton(line, bottom,switchlist[i],BUTTONTIME);
return;
}
}
/*
==============================================================================
=
= P_UseSpecialLine
=
= Called when a thing uses a special line
= Only the front sides of lines are usable
===============================================================================
*/
boolean P_UseSpecialLine ( mobj_t *thing, line_t *line)
{
//
// Switches that other things can activate
//
if (!thing->player)
{
if (line->flags & ML_SECRET)
return false; // never open secret doors
switch(line->special)
{
case 1: // MANUAL DOOR RAISE
case 32: // MANUAL BLUE
case 33: // MANUAL RED
case 34: // MANUAL YELLOW
break;
default:
return false;
}
}
//
// do something
//
switch (line->special)
{
//===============================================
// MANUALS
//===============================================
case 1: // Vertical Door
case 26: // Blue Door/Locked
case 27: // Yellow Door /Locked
case 28: // Red Door /Locked
case 31: // Manual door open
case 32: // Blue locked door open
case 33: // Red locked door open
case 34: // Yellow locked door open
EV_VerticalDoor (line, thing);
break;
//===============================================
// SWITCHES
//===============================================
case 7: // Switch_Build_Stairs (8 pixel steps)
if(EV_BuildStairs(line, 8*FRACUNIT))
{
P_ChangeSwitchTexture(line, 0);
}
break;
case 107: // Switch_Build_Stairs_16 (16 pixel steps)
if(EV_BuildStairs(line, 16*FRACUNIT))
{
P_ChangeSwitchTexture(line, 0);
}
break;
case 9: // Change Donut
if (EV_DoDonut(line))
P_ChangeSwitchTexture(line,0);
break;
case 11: // Exit level
G_ExitLevel ();
P_ChangeSwitchTexture(line,0);
break;
case 14: // Raise Floor 32 and change texture
if (EV_DoPlat(line,raiseAndChange,32))
P_ChangeSwitchTexture(line,0);
break;
case 15: // Raise Floor 24 and change texture
if (EV_DoPlat(line,raiseAndChange,24))
P_ChangeSwitchTexture(line,0);
break;
case 18: // Raise Floor to next highest floor
if (EV_DoFloor(line, raiseFloorToNearest))
P_ChangeSwitchTexture(line,0);
break;
case 20: // Raise Plat next highest floor and change texture
if (EV_DoPlat(line,raiseToNearestAndChange,0))
P_ChangeSwitchTexture(line,0);
break;
case 21: // PlatDownWaitUpStay
if (EV_DoPlat(line,downWaitUpStay,0))
P_ChangeSwitchTexture(line,0);
break;
case 23: // Lower Floor to Lowest
if (EV_DoFloor(line,lowerFloorToLowest))
P_ChangeSwitchTexture(line,0);
break;
case 29: // Raise Door
if (EV_DoDoor(line,normal,VDOORSPEED))
P_ChangeSwitchTexture(line,0);
break;
case 41: // Lower Ceiling to Floor
if (EV_DoCeiling(line,lowerToFloor))
P_ChangeSwitchTexture(line,0);
break;
case 71: // Turbo Lower Floor
if (EV_DoFloor(line,turboLower))
P_ChangeSwitchTexture(line,0);
break;
case 49: // Lower Ceiling And Crush
if (EV_DoCeiling(line,lowerAndCrush))
P_ChangeSwitchTexture(line,0);
break;
case 50: // Close Door
if (EV_DoDoor(line,close,VDOORSPEED))
P_ChangeSwitchTexture(line,0);
break;
case 51: // Secret EXIT
G_SecretExitLevel ();
P_ChangeSwitchTexture(line,0);
break;
case 55: // Raise Floor Crush
if (EV_DoFloor(line,raiseFloorCrush))
P_ChangeSwitchTexture(line,0);
break;
case 101: // Raise Floor
if (EV_DoFloor(line,raiseFloor))
P_ChangeSwitchTexture(line,0);
break;
case 102: // Lower Floor to Surrounding floor height
if (EV_DoFloor(line,lowerFloor))
P_ChangeSwitchTexture(line,0);
break;
case 103: // Open Door
if (EV_DoDoor(line,open,VDOORSPEED))
P_ChangeSwitchTexture(line,0);
break;
//===============================================
// BUTTONS
//===============================================
case 42: // Close Door
if (EV_DoDoor(line,close,VDOORSPEED))
P_ChangeSwitchTexture(line,1);
break;
case 43: // Lower Ceiling to Floor
if (EV_DoCeiling(line,lowerToFloor))
P_ChangeSwitchTexture(line,1);
break;
case 45: // Lower Floor to Surrounding floor height
if (EV_DoFloor(line,lowerFloor))
P_ChangeSwitchTexture(line,1);
break;
case 60: // Lower Floor to Lowest
if (EV_DoFloor(line,lowerFloorToLowest))
P_ChangeSwitchTexture(line,1);
break;
case 61: // Open Door
if (EV_DoDoor(line,open,VDOORSPEED))
P_ChangeSwitchTexture(line,1);
break;
case 62: // PlatDownWaitUpStay
if (EV_DoPlat(line,downWaitUpStay,1))
P_ChangeSwitchTexture(line,1);
break;
case 63: // Raise Door
if (EV_DoDoor(line,normal,VDOORSPEED))
P_ChangeSwitchTexture(line,1);
break;
case 64: // Raise Floor to ceiling
if (EV_DoFloor(line,raiseFloor))
P_ChangeSwitchTexture(line,1);
break;
case 66: // Raise Floor 24 and change texture
if (EV_DoPlat(line,raiseAndChange,24))
P_ChangeSwitchTexture(line,1);
break;
case 67: // Raise Floor 32 and change texture
if (EV_DoPlat(line,raiseAndChange,32))
P_ChangeSwitchTexture(line,1);
break;
case 65: // Raise Floor Crush
if (EV_DoFloor(line,raiseFloorCrush))
P_ChangeSwitchTexture(line,1);
break;
case 68: // Raise Plat to next highest floor and change texture
if (EV_DoPlat(line,raiseToNearestAndChange,0))
P_ChangeSwitchTexture(line,1);
break;
case 69: // Raise Floor to next highest floor
if (EV_DoFloor(line, raiseFloorToNearest))
P_ChangeSwitchTexture(line,1);
break;
case 70: // Turbo Lower Floor
if (EV_DoFloor(line,turboLower))
P_ChangeSwitchTexture(line,1);
break;
}
return true;
}

148
Heretic Source/P_TELEPT.C Normal file
View File

@ -0,0 +1,148 @@
// P_telept.c
#include "DoomDef.h"
#include "P_local.h"
#include "soundst.h"
//----------------------------------------------------------------------------
//
// FUNC P_Teleport
//
//----------------------------------------------------------------------------
boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle)
{
fixed_t oldx;
fixed_t oldy;
fixed_t oldz;
fixed_t aboveFloor;
fixed_t fogDelta;
player_t *player;
unsigned an;
mobj_t *fog;
oldx = thing->x;
oldy = thing->y;
oldz = thing->z;
aboveFloor = thing->z-thing->floorz;
if(!P_TeleportMove(thing, x, y))
{
return(false);
}
if(thing->player)
{
player = thing->player;
if(player->powers[pw_flight] && aboveFloor)
{
thing->z = thing->floorz+aboveFloor;
if(thing->z+thing->height > thing->ceilingz)
{
thing->z = thing->ceilingz-thing->height;
}
player->viewz = thing->z+player->viewheight;
}
else
{
thing->z = thing->floorz;
player->viewz = thing->z+player->viewheight;
player->lookdir = 0;
}
}
else if(thing->flags&MF_MISSILE)
{
thing->z = thing->floorz+aboveFloor;
if(thing->z+thing->height > thing->ceilingz)
{
thing->z = thing->ceilingz-thing->height;
}
}
else
{
thing->z = thing->floorz;
}
// Spawn teleport fog at source and destination
fogDelta = thing->flags&MF_MISSILE ? 0 : TELEFOGHEIGHT;
fog = P_SpawnMobj(oldx, oldy, oldz+fogDelta, MT_TFOG);
S_StartSound(fog, sfx_telept);
an = angle>>ANGLETOFINESHIFT;
fog = P_SpawnMobj(x+20*finecosine[an],
y+20*finesine[an], thing->z+fogDelta, MT_TFOG);
S_StartSound(fog, sfx_telept);
if(thing->player && !thing->player->powers[pw_weaponlevel2])
{ // Freeze player for about .5 sec
thing->reactiontime = 18;
}
thing->angle = angle;
if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
{
thing->flags2 |= MF2_FEETARECLIPPED;
}
else if(thing->flags2&MF2_FEETARECLIPPED)
{
thing->flags2 &= ~MF2_FEETARECLIPPED;
}
if(thing->flags&MF_MISSILE)
{
angle >>= ANGLETOFINESHIFT;
thing->momx = FixedMul(thing->info->speed, finecosine[angle]);
thing->momy = FixedMul(thing->info->speed, finesine[angle]);
}
else
{
thing->momx = thing->momy = thing->momz = 0;
}
return(true);
}
//----------------------------------------------------------------------------
//
// FUNC EV_Teleport
//
//----------------------------------------------------------------------------
boolean EV_Teleport(line_t *line, int side, mobj_t *thing)
{
int i;
int tag;
mobj_t *m;
thinker_t *thinker;
sector_t *sector;
if(thing->flags2&MF2_NOTELEPORT)
{
return(false);
}
if(side == 1)
{ // Don't teleport when crossing back side
return(false);
}
tag = line->tag;
for(i = 0; i < numsectors; i++)
{
if(sectors[i].tag == tag)
{
thinker = thinkercap.next;
for(thinker = thinkercap.next; thinker != &thinkercap;
thinker = thinker->next)
{
if(thinker->function != P_MobjThinker)
{ // Not a mobj
continue;
}
m = (mobj_t *)thinker;
if(m->type != MT_TELEPORTMAN )
{ // Not a teleportman
continue;
}
sector = m->subsector->sector;
if(sector-sectors != i)
{ // Wrong sector
continue;
}
return(P_Teleport(thing, m->x, m->y, m->angle));
}
}
}
return(false);
}

643
Heretic Source/P_TICK.C Normal file
View File

@ -0,0 +1,643 @@
// P_tick.c
#include "DoomDef.h"
#include "P_local.h"
int leveltime;
int TimerGame;
/*
====================
=
= P_ArchivePlayers
=
====================
*/
void P_ArchivePlayers(void)
{
int i;
int j;
player_t dest;
for(i = 0; i < MAXPLAYERS; i++)
{
if(!playeringame[i])
{
continue;
}
memcpy(&dest, &players[i], sizeof(player_t));
for(j = 0; j < NUMPSPRITES; j++)
{
if(dest.psprites[j].state)
{
dest.psprites[j].state =
(state_t *)(dest.psprites[j].state-states);
}
}
SV_Write(&dest, sizeof(player_t));
}
}
/*
====================
=
= P_UnArchivePlayers
=
====================
*/
void P_UnArchivePlayers (void)
{
int i,j;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
memcpy (&players[i],save_p, sizeof(player_t));
save_p += sizeof(player_t);
players[i].mo = NULL; // will be set when unarc thinker
players[i].message = NULL;
players[i].attacker = NULL;
for (j=0 ; j<NUMPSPRITES ; j++)
if (players[i]. psprites[j].state)
players[i]. psprites[j].state
= &states[ (int)players[i].psprites[j].state ];
}
}
//=============================================================================
/*
====================
=
= P_ArchiveWorld
=
====================
*/
void P_ArchiveWorld(void)
{
int i, j;
sector_t *sec;
line_t *li;
side_t *si;
// Sectors
for(i = 0, sec = sectors; i < numsectors; i++, sec++)
{
SV_WriteWord(sec->floorheight>>FRACBITS);
SV_WriteWord(sec->ceilingheight>>FRACBITS);
SV_WriteWord(sec->floorpic);
SV_WriteWord(sec->ceilingpic);
SV_WriteWord(sec->lightlevel);
SV_WriteWord(sec->special); // needed?
SV_WriteWord(sec->tag); // needed?
}
// Lines
for(i = 0, li = lines; i < numlines; i++, li++)
{
SV_WriteWord(li->flags);
SV_WriteWord(li->special);
SV_WriteWord(li->tag);
for(j = 0; j < 2; j++)
{
if(li->sidenum[j] == -1)
{
continue;
}
si = &sides[li->sidenum[j]];
SV_WriteWord(si->textureoffset>>FRACBITS);
SV_WriteWord(si->rowoffset>>FRACBITS);
SV_WriteWord(si->toptexture);
SV_WriteWord(si->bottomtexture);
SV_WriteWord(si->midtexture);
}
}
}
/*
====================
=
= P_UnArchiveWorld
=
====================
*/
void P_UnArchiveWorld (void)
{
int i,j;
sector_t *sec;
line_t *li;
side_t *si;
short *get;
get = (short *)save_p;
//
// do sectors
//
for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
{
sec->floorheight = *get++ << FRACBITS;
sec->ceilingheight = *get++ << FRACBITS;
sec->floorpic = *get++;
sec->ceilingpic = *get++;
sec->lightlevel = *get++;
sec->special = *get++; // needed?
sec->tag = *get++; // needed?
sec->specialdata = 0;
sec->soundtarget = 0;
}
//
// do lines
//
for (i=0, li = lines ; i<numlines ; i++,li++)
{
li->flags = *get++;
li->special = *get++;
li->tag = *get++;
for (j=0 ; j<2 ; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
si->textureoffset = *get++ << FRACBITS;
si->rowoffset = *get++ << FRACBITS;
si->toptexture = *get++;
si->bottomtexture = *get++;
si->midtexture = *get++;
}
}
save_p = (byte *)get;
}
//=============================================================================
typedef enum
{
tc_end,
tc_mobj
} thinkerclass_t;
/*
====================
=
= P_ArchiveThinkers
=
====================
*/
void P_ArchiveThinkers(void)
{
thinker_t *th;
mobj_t mobj;
for(th = thinkercap.next; th != &thinkercap; th = th->next)
{
if(th->function == P_MobjThinker)
{
SV_WriteByte(tc_mobj);
memcpy(&mobj, th, sizeof(mobj_t));
mobj.state = (state_t *)(mobj.state-states);
if(mobj.player)
{
mobj.player = (player_t *)((mobj.player-players)+1);
}
SV_Write(&mobj, sizeof(mobj_t));
continue;
}
//I_Error("P_ArchiveThinkers: Unknown thinker function");
}
// Add a terminating marker
SV_WriteByte(tc_end);
}
/*
====================
=
= P_UnArchiveThinkers
=
====================
*/
void P_UnArchiveThinkers (void)
{
byte tclass;
thinker_t *currentthinker, *next;
mobj_t *mobj;
//
// remove all the current thinkers
//
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
next = currentthinker->next;
if (currentthinker->function == P_MobjThinker)
P_RemoveMobj ((mobj_t *)currentthinker);
else
Z_Free (currentthinker);
currentthinker = next;
}
P_InitThinkers ();
// read in saved thinkers
while (1)
{
tclass = *save_p++;
switch (tclass)
{
case tc_end:
return; // end of list
case tc_mobj:
mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
memcpy (mobj, save_p, sizeof(*mobj));
save_p += sizeof(*mobj);
mobj->state = &states[(int)mobj->state];
mobj->target = NULL;
if (mobj->player)
{
mobj->player = &players[(int)mobj->player-1];
mobj->player->mo = mobj;
}
P_SetThingPosition (mobj);
mobj->info = &mobjinfo[mobj->type];
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
mobj->thinker.function = P_MobjThinker;
P_AddThinker (&mobj->thinker);
break;
default:
I_Error ("Unknown tclass %i in savegame",tclass);
}
}
}
//=============================================================================
/*
====================
=
= P_ArchiveSpecials
=
====================
*/
enum
{
tc_ceiling,
tc_door,
tc_floor,
tc_plat,
tc_flash,
tc_strobe,
tc_glow,
tc_endspecials
} specials_e;
void P_ArchiveSpecials(void)
{
/*
T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
T_VerticalDoor, (vldoor_t: sector_t * swizzle),
T_MoveFloor, (floormove_t: sector_t * swizzle),
T_LightFlash, (lightflash_t: sector_t * swizzle),
T_StrobeFlash, (strobe_t: sector_t *),
T_Glow, (glow_t: sector_t *),
T_PlatRaise, (plat_t: sector_t *), - active list
*/
thinker_t *th;
ceiling_t ceiling;
vldoor_t door;
floormove_t floor;
plat_t plat;
lightflash_t flash;
strobe_t strobe;
glow_t glow;
for(th = thinkercap.next; th != &thinkercap; th = th->next)
{
if(th->function == T_MoveCeiling)
{
SV_WriteByte(tc_ceiling);
memcpy(&ceiling, th, sizeof(ceiling_t));
ceiling.sector = (sector_t *)(ceiling.sector-sectors);
SV_Write(&ceiling, sizeof(ceiling_t));
continue;
}
if(th->function == T_VerticalDoor)
{
SV_WriteByte(tc_door);
memcpy(&door, th, sizeof(vldoor_t));
door.sector = (sector_t *)(door.sector-sectors);
SV_Write(&door, sizeof(vldoor_t));
continue;
}
if(th->function == T_MoveFloor)
{
SV_WriteByte(tc_floor);
memcpy(&floor, th, sizeof(floormove_t));
floor.sector = (sector_t *)(floor.sector-sectors);
SV_Write(&floor, sizeof(floormove_t));
continue;
}
if(th->function == T_PlatRaise)
{
SV_WriteByte(tc_plat);
memcpy(&plat, th, sizeof(plat_t));
plat.sector = (sector_t *)(plat.sector-sectors);
SV_Write(&plat, sizeof(plat_t));
continue;
}
if(th->function == T_LightFlash)
{
SV_WriteByte(tc_flash);
memcpy(&flash, th, sizeof(lightflash_t));
flash.sector = (sector_t *)(flash.sector-sectors);
SV_Write(&flash, sizeof(lightflash_t));
continue;
}
if(th->function == T_StrobeFlash)
{
SV_WriteByte(tc_strobe);
memcpy(&strobe, th, sizeof(strobe_t));
strobe.sector = (sector_t *)(strobe.sector-sectors);
SV_Write(&strobe, sizeof(strobe_t));
continue;
}
if(th->function == T_Glow)
{
SV_WriteByte(tc_glow);
memcpy(&glow, th, sizeof(glow_t));
glow.sector = (sector_t *)(glow.sector-sectors);
SV_Write(&glow, sizeof(glow_t));
continue;
}
}
// Add a terminating marker
SV_WriteByte(tc_endspecials);
}
/*
====================
=
= P_UnArchiveSpecials
=
====================
*/
void P_UnArchiveSpecials (void)
{
byte tclass;
ceiling_t *ceiling;
vldoor_t *door;
floormove_t *floor;
plat_t *plat;
lightflash_t *flash;
strobe_t *strobe;
glow_t *glow;
// read in saved thinkers
while (1)
{
tclass = *save_p++;
switch (tclass)
{
case tc_endspecials:
return; // end of list
case tc_ceiling:
ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
memcpy (ceiling, save_p, sizeof(*ceiling));
save_p += sizeof(*ceiling);
ceiling->sector = &sectors[(int)ceiling->sector];
ceiling->sector->specialdata = T_MoveCeiling;
if (ceiling->thinker.function)
ceiling->thinker.function = T_MoveCeiling;
P_AddThinker (&ceiling->thinker);
P_AddActiveCeiling(ceiling);
break;
case tc_door:
door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
memcpy (door, save_p, sizeof(*door));
save_p += sizeof(*door);
door->sector = &sectors[(int)door->sector];
door->sector->specialdata = door;
door->thinker.function = T_VerticalDoor;
P_AddThinker (&door->thinker);
break;
case tc_floor:
floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
memcpy (floor, save_p, sizeof(*floor));
save_p += sizeof(*floor);
floor->sector = &sectors[(int)floor->sector];
floor->sector->specialdata = T_MoveFloor;
floor->thinker.function = T_MoveFloor;
P_AddThinker (&floor->thinker);
break;
case tc_plat:
plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
memcpy (plat, save_p, sizeof(*plat));
save_p += sizeof(*plat);
plat->sector = &sectors[(int)plat->sector];
plat->sector->specialdata = T_PlatRaise;
if (plat->thinker.function)
plat->thinker.function = T_PlatRaise;
P_AddThinker (&plat->thinker);
P_AddActivePlat(plat);
break;
case tc_flash:
flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
memcpy (flash, save_p, sizeof(*flash));
save_p += sizeof(*flash);
flash->sector = &sectors[(int)flash->sector];
flash->thinker.function = T_LightFlash;
P_AddThinker (&flash->thinker);
break;
case tc_strobe:
strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
memcpy (strobe, save_p, sizeof(*strobe));
save_p += sizeof(*strobe);
strobe->sector = &sectors[(int)strobe->sector];
strobe->thinker.function = T_StrobeFlash;
P_AddThinker (&strobe->thinker);
break;
case tc_glow:
glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
memcpy (glow, save_p, sizeof(*glow));
save_p += sizeof(*glow);
glow->sector = &sectors[(int)glow->sector];
glow->thinker.function = T_Glow;
P_AddThinker (&glow->thinker);
break;
default:
I_Error ("P_UnarchiveSpecials:Unknown tclass %i "
"in savegame",tclass);
}
}
}
/*
===============================================================================
THINKERS
All thinkers should be allocated by Z_Malloc so they can be operated on uniformly. The actual
structures will vary in size, but the first element must be thinker_t.
===============================================================================
*/
thinker_t thinkercap; // both the head and tail of the thinker list
/*
===============
=
= P_InitThinkers
=
===============
*/
void P_InitThinkers (void)
{
thinkercap.prev = thinkercap.next = &thinkercap;
}
/*
===============
=
= P_AddThinker
=
= Adds a new thinker at the end of the list
=
===============
*/
void P_AddThinker (thinker_t *thinker)
{
thinkercap.prev->next = thinker;
thinker->next = &thinkercap;
thinker->prev = thinkercap.prev;
thinkercap.prev = thinker;
}
/*
===============
=
= P_RemoveThinker
=
= Deallocation is lazy -- it will not actually be freed until its
= thinking turn comes up
=
===============
*/
void P_RemoveThinker (thinker_t *thinker)
{
thinker->function = (think_t)-1;
}
/*
===============
=
= P_AllocateThinker
=
= Allocates memory and adds a new thinker at the end of the list
=
===============
*/
void P_AllocateThinker (thinker_t *thinker)
{
}
/*
===============
=
= P_RunThinkers
=
===============
*/
void P_RunThinkers (void)
{
thinker_t *currentthinker;
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
if (currentthinker->function == (think_t)-1)
{ // time to remove it
currentthinker->next->prev = currentthinker->prev;
currentthinker->prev->next = currentthinker->next;
Z_Free (currentthinker);
}
else
{
if (currentthinker->function)
currentthinker->function (currentthinker);
}
currentthinker = currentthinker->next;
}
}
//----------------------------------------------------------------------------
//
// PROC P_Ticker
//
//----------------------------------------------------------------------------
void P_Ticker(void)
{
int i;
if(paused)
{
return;
}
for(i = 0; i < MAXPLAYERS; i++)
{
if(playeringame[i])
{
P_PlayerThink(&players[i]);
}
}
if(TimerGame)
{
if(!--TimerGame)
{
G_ExitLevel();
}
}
P_RunThinkers();
P_UpdateSpecials();
P_AmbientSound();
leveltime++;
}

1007
Heretic Source/P_USER.C Normal file

File diff suppressed because it is too large Load Diff

474
Heretic Source/R_BSP.C Normal file
View File

@ -0,0 +1,474 @@
// R_bsp.c
#include "DoomDef.h"
#include "R_local.h"
seg_t *curline;
side_t *sidedef;
line_t *linedef;
sector_t *frontsector, *backsector;
drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
void R_StoreWallRange (int start, int stop);
/*
====================
=
= R_ClearDrawSegs
=
====================
*/
void R_ClearDrawSegs (void)
{
ds_p = drawsegs;
}
//=============================================================================
/*
===============================================================================
=
= ClipWallSegment
=
= Clips the given range of columns and includes it in the new clip list
===============================================================================
*/
typedef struct
{
int first, last;
} cliprange_t;
#define MAXSEGS 32
cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg
void R_ClipSolidWallSegment (int first, int last)
{
cliprange_t *next, *start;
// find the first range that touches the range (adjacent pixels are touching)
start = solidsegs;
while (start->last < first-1)
start++;
if (first < start->first)
{
if (last < start->first-1)
{ // post is entirely visible (above start), so insert a new clippost
R_StoreWallRange (first, last);
next = newend;
newend++;
while (next != start)
{
*next = *(next-1);
next--;
}
next->first = first;
next->last = last;
return;
}
// there is a fragment above *start
R_StoreWallRange (first, start->first - 1);
start->first = first; // adjust the clip size
}
if (last <= start->last)
return; // bottom contained in start
next = start;
while (last >= (next+1)->first-1)
{
// there is a fragment between two posts
R_StoreWallRange (next->last + 1, (next+1)->first - 1);
next++;
if (last <= next->last)
{ // bottom is contained in next
start->last = next->last; // adjust the clip size
goto crunch;
}
}
// there is a fragment after *next
R_StoreWallRange (next->last + 1, last);
start->last = last; // adjust the clip size
// remove start+1 to next from the clip list,
// because start now covers their area
crunch:
if (next == start)
return; // post just extended past the bottom of one post
while (next++ != newend) // remove a post
*++start = *next;
newend = start+1;
}
/*
===============================================================================
=
= R_ClipPassWallSegment
=
= Clips the given range of columns, but does not includes it in the clip list
===============================================================================
*/
void R_ClipPassWallSegment (int first, int last)
{
cliprange_t *start;
// find the first range that touches the range (adjacent pixels are touching)
start = solidsegs;
while (start->last < first-1)
start++;
if (first < start->first)
{
if (last < start->first-1)
{ // post is entirely visible (above start)
R_StoreWallRange (first, last);
return;
}
// there is a fragment above *start
R_StoreWallRange (first, start->first - 1);
}
if (last <= start->last)
return; // bottom contained in start
while (last >= (start+1)->first-1)
{
// there is a fragment between two posts
R_StoreWallRange (start->last + 1, (start+1)->first - 1);
start++;
if (last <= start->last)
return;
}
// there is a fragment after *next
R_StoreWallRange (start->last + 1, last);
}
/*
====================
=
= R_ClearClipSegs
=
====================
*/
void R_ClearClipSegs (void)
{
solidsegs[0].first = -0x7fffffff;
solidsegs[0].last = -1;
solidsegs[1].first = viewwidth;
solidsegs[1].last = 0x7fffffff;
newend = solidsegs+2;
}
//=============================================================================
/*
======================
=
= R_AddLine
=
= Clips the given segment and adds any visible pieces to the line list
=
======================
*/
void R_AddLine (seg_t *line)
{
int x1, x2;
angle_t angle1, angle2, span, tspan;
#ifdef __NeXT__
RD_DrawLineCheck (line);
#endif
curline = line;
// OPTIMIZE: quickly reject orthogonal back sides
angle1 = R_PointToAngle (line->v1->x, line->v1->y);
angle2 = R_PointToAngle (line->v2->x, line->v2->y);
//
// clip to view edges
// OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW)
span = angle1 - angle2;
if (span >= ANG180)
return; // back side
rw_angle1 = angle1; // global angle needed by segcalc
angle1 -= viewangle;
angle2 -= viewangle;
tspan = angle1 + clipangle;
if (tspan > 2*clipangle)
{
tspan -= 2*clipangle;
if (tspan >= span)
return; // totally off the left edge
angle1 = clipangle;
}
tspan = clipangle - angle2;
if (tspan > 2*clipangle)
{
tspan -= 2*clipangle;
if (tspan >= span)
return; // totally off the left edge
angle2 = -clipangle;
}
//
// the seg is in the view range, but not necessarily visible
//
angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
x1 = viewangletox[angle1];
x2 = viewangletox[angle2];
if (x1 == x2)
return; // does not cross a pixel
backsector = line->backsector;
if (!backsector)
goto clipsolid; // single sided line
if (backsector->ceilingheight <= frontsector->floorheight
|| backsector->floorheight >= frontsector->ceilingheight)
goto clipsolid; // closed door
if (backsector->ceilingheight != frontsector->ceilingheight
|| backsector->floorheight != frontsector->floorheight)
goto clippass; // window
// reject empty lines used for triggers and special events
if (backsector->ceilingpic == frontsector->ceilingpic
&& backsector->floorpic == frontsector->floorpic
&& backsector->lightlevel == frontsector->lightlevel
&& curline->sidedef->midtexture == 0)
return;
clippass:
R_ClipPassWallSegment (x1, x2-1);
return;
clipsolid:
R_ClipSolidWallSegment (x1, x2-1);
}
//============================================================================
/*
===============================================================================
=
= R_CheckBBox
=
= Returns true if some part of the bbox might be visible
=
===============================================================================
*/
int checkcoord[12][4] = {
{3,0, 2,1},
{3,0, 2,0},
{3,1, 2,0},
{0},
{2,0, 2,1},
{0,0,0,0},
{3,1, 3,0},
{0},
{2,0, 3,1},
{2,1, 3,1},
{2,1, 3,0} };
boolean R_CheckBBox (fixed_t *bspcoord)
{
int boxx, boxy, boxpos;
fixed_t x1, y1, x2, y2;
angle_t angle1, angle2, span, tspan;
cliprange_t *start;
int sx1, sx2;
#ifdef __NeXT__
RD_DrawBBox (bspcoord);
#endif
// find the corners of the box that define the edges from current viewpoint
if (viewx <= bspcoord[BOXLEFT])
boxx = 0;
else if (viewx < bspcoord[BOXRIGHT])
boxx = 1;
else
boxx = 2;
if (viewy >= bspcoord[BOXTOP])
boxy = 0;
else if (viewy > bspcoord[BOXBOTTOM])
boxy = 1;
else
boxy = 2;
boxpos = (boxy<<2)+boxx;
if (boxpos == 5)
return true;
x1 = bspcoord[checkcoord[boxpos][0]];
y1 = bspcoord[checkcoord[boxpos][1]];
x2 = bspcoord[checkcoord[boxpos][2]];
y2 = bspcoord[checkcoord[boxpos][3]];
#ifdef __NeXT__
// RD_DisplayLine (x1, y1, x2, y2, 0.1);
#endif
//
// check clip list for an open space
//
angle1 = R_PointToAngle (x1, y1) - viewangle;
angle2 = R_PointToAngle (x2, y2) - viewangle;
span = angle1 - angle2;
if (span >= ANG180)
return true; // sitting on a line
tspan = angle1 + clipangle;
if (tspan > 2*clipangle)
{
tspan -= 2*clipangle;
if (tspan >= span)
return false; // totally off the left edge
angle1 = clipangle;
}
tspan = clipangle - angle2;
if (tspan > 2*clipangle)
{
tspan -= 2*clipangle;
if (tspan >= span)
return false; // totally off the left edge
angle2 = -clipangle;
}
// find the first clippost that touches the source post (adjacent pixels are touching)
angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
sx1 = viewangletox[angle1];
sx2 = viewangletox[angle2];
if (sx1 == sx2)
return false; // does not cross a pixel
sx2--;
start = solidsegs;
while (start->last < sx2)
start++;
if (sx1 >= start->first && sx2 <= start->last)
return false; // the clippost contains the new span
return true;
}
/*
================
=
= R_Subsector
=
= Draw one or more segments
================
*/
void R_Subsector (int num)
{
int count;
seg_t *line;
subsector_t *sub;
#ifdef RANGECHECK
if (num>=numsubsectors)
I_Error ("R_Subsector: ss %i with numss = %i",num, numsubsectors);
#endif
sscount++;
sub = &subsectors[num];
frontsector = sub->sector;
count = sub->numlines;
line = &segs[sub->firstline];
if (frontsector->floorheight < viewz)
floorplane = R_FindPlane (frontsector->floorheight,
frontsector->floorpic, frontsector->lightlevel,
frontsector->special);
else
floorplane = NULL;
if (frontsector->ceilingheight > viewz
|| frontsector->ceilingpic == skyflatnum)
ceilingplane = R_FindPlane (frontsector->ceilingheight,
frontsector->ceilingpic, frontsector->lightlevel, 0);
else
ceilingplane = NULL;
R_AddSprites (frontsector);
while (count--)
{
R_AddLine (line);
line++;
}
}
/*
===============================================================================
=
= RenderBSPNode
=
===============================================================================
*/
void R_RenderBSPNode (int bspnum)
{
node_t *bsp;
int side;
if (bspnum & NF_SUBSECTOR)
{
if (bspnum == -1)
R_Subsector (0);
else
R_Subsector (bspnum&(~NF_SUBSECTOR));
return;
}
bsp = &nodes[bspnum];
#ifdef __NeXT__
RD_DrawNodeLine (bsp);
#endif
//
// decide which side the view point is on
//
side = R_PointOnSide (viewx, viewy, bsp);
R_RenderBSPNode (bsp->children[side]); // recursively divide front space
if (R_CheckBBox (bsp->bbox[side^1])) // possibly divide back space
R_RenderBSPNode (bsp->children[side^1]);
}

701
Heretic Source/R_DATA.C Normal file
View File

@ -0,0 +1,701 @@
// R_data.c
#include "DoomDef.h"
#include "R_local.h"
#include "P_local.h"
extern void CheckAbortStartup(void);
typedef struct
{
int originx; // block origin (allways UL), which has allready
int originy; // accounted for the patch's internal origin
int patch;
} texpatch_t;
// a maptexturedef_t describes a rectangular texture, which is composed of one
// or more mappatch_t structures that arrange graphic patches
typedef struct
{
char name[8]; // for switch changing, etc
short width;
short height;
short patchcount;
texpatch_t patches[1]; // [patchcount] drawn back to front
// into the cached texture
} texture_t;
int firstflat, lastflat, numflats;
int firstpatch, lastpatch, numpatches;
int firstspritelump, lastspritelump, numspritelumps;
int numtextures;
texture_t **textures;
int *texturewidthmask;
fixed_t *textureheight; // needed for texture pegging
int *texturecompositesize;
short **texturecolumnlump;
unsigned short **texturecolumnofs;
byte **texturecomposite;
int *flattranslation; // for global animation
int *texturetranslation; // for global animation
fixed_t *spritewidth; // needed for pre rendering
fixed_t *spriteoffset;
fixed_t *spritetopoffset;
lighttable_t *colormaps;
/*
==============================================================================
MAPTEXTURE_T CACHING
when a texture is first needed, it counts the number of composite columns
required in the texture and allocates space for a column directory and any
new columns. The directory will simply point inside other patches if there
is only one patch in a given column, but any columns with multiple patches
will have new column_ts generated.
==============================================================================
*/
/*
===================
=
= R_DrawColumnInCache
=
= Clip and draw a column from a patch into a cached post
=
===================
*/
void R_DrawColumnInCache (column_t *patch, byte *cache, int originy, int cacheheight)
{
int count, position;
byte *source, *dest;
dest = (byte *)cache + 3;
while (patch->topdelta != 0xff)
{
source = (byte *)patch + 3;
count = patch->length;
position = originy + patch->topdelta;
if (position < 0)
{
count += position;
position = 0;
}
if (position + count > cacheheight)
count = cacheheight - position;
if (count > 0)
memcpy (cache + position, source, count);
patch = (column_t *)( (byte *)patch + patch->length + 4);
}
}
/*
===================
=
= R_GenerateComposite
=
===================
*/
void R_GenerateComposite (int texnum)
{
byte *block;
texture_t *texture;
texpatch_t *patch;
patch_t *realpatch;
int x, x1, x2;
int i;
column_t *patchcol;
short *collump;
unsigned short *colofs;
texture = textures[texnum];
block = Z_Malloc (texturecompositesize[texnum], PU_STATIC,
&texturecomposite[texnum]);
collump = texturecolumnlump[texnum];
colofs = texturecolumnofs[texnum];
//
// composite the columns together
//
patch = texture->patches;
for (i=0 , patch = texture->patches; i<texture->patchcount ; i++, patch++)
{
realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
x1 = patch->originx;
x2 = x1 + SHORT(realpatch->width);
if (x1<0)
x = 0;
else
x = x1;
if (x2 > texture->width)
x2 = texture->width;
for ( ; x<x2 ; x++)
{
if (collump[x] >= 0)
continue; // column does not have multiple patches
patchcol = (column_t *)((byte *)realpatch +
LONG(realpatch->columnofs[x-x1]));
R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy,
texture->height);
}
}
// now that the texture has been built, it is purgable
Z_ChangeTag (block, PU_CACHE);
}
/*
===================
=
= R_GenerateLookup
=
===================
*/
void R_GenerateLookup (int texnum)
{
texture_t *texture;
byte *patchcount; // [texture->width]
texpatch_t *patch;
patch_t *realpatch;
int x, x1, x2;
int i;
short *collump;
unsigned short *colofs;
texture = textures[texnum];
texturecomposite[texnum] = 0; // composited not created yet
texturecompositesize[texnum] = 0;
collump = texturecolumnlump[texnum];
colofs = texturecolumnofs[texnum];
//
// count the number of columns that are covered by more than one patch
// fill in the lump / offset, so columns with only a single patch are
// all done
//
patchcount = (byte *)alloca (texture->width);
memset (patchcount, 0, texture->width);
patch = texture->patches;
for (i=0 , patch = texture->patches; i<texture->patchcount ; i++, patch++)
{
realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
x1 = patch->originx;
x2 = x1 + SHORT(realpatch->width);
if (x1 < 0)
x = 0;
else
x = x1;
if (x2 > texture->width)
x2 = texture->width;
for ( ; x<x2 ; x++)
{
patchcount[x]++;
collump[x] = patch->patch;
colofs[x] = LONG(realpatch->columnofs[x-x1])+3;
}
}
for (x=0 ; x<texture->width ; x++)
{
if (!patchcount[x])
{
printf ("R_GenerateLookup: column without a patch (%s)\n", texture->name);
return;
}
// I_Error ("R_GenerateLookup: column without a patch");
if (patchcount[x] > 1)
{
collump[x] = -1; // use the cached block
colofs[x] = texturecompositesize[texnum];
if (texturecompositesize[texnum] > 0x10000-texture->height)
I_Error ("R_GenerateLookup: texture %i is >64k",texnum);
texturecompositesize[texnum] += texture->height;
}
}
}
/*
================
=
= R_GetColumn
=
================
*/
byte *R_GetColumn (int tex, int col)
{
int lump, ofs;
col &= texturewidthmask[tex];
lump = texturecolumnlump[tex][col];
ofs = texturecolumnofs[tex][col];
if (lump > 0)
return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs;
if (!texturecomposite[tex])
R_GenerateComposite (tex);
return texturecomposite[tex] + ofs;
}
/*
==================
=
= R_InitTextures
=
= Initializes the texture list with the textures from the world map
=
==================
*/
void R_InitTextures (void)
{
maptexture_t *mtexture;
texture_t *texture;
mappatch_t *mpatch;
texpatch_t *patch;
int i,j;
int *maptex, *maptex2, *maptex1;
char name[9], *names, *name_p;
int *patchlookup;
int totalwidth;
int nummappatches;
int offset, maxoff, maxoff2;
int numtextures1, numtextures2;
int *directory;
//
// load the patch names from pnames.lmp
//
name[8] = 0;
names = W_CacheLumpName ("PNAMES", PU_STATIC);
nummappatches = LONG ( *((int *)names) );
name_p = names+4;
patchlookup = alloca (nummappatches*sizeof(*patchlookup));
for (i=0 ; i<nummappatches ; i++)
{
strncpy (name,name_p+i*8, 8);
patchlookup[i] = W_CheckNumForName (name);
}
Z_Free (names);
//
// load the map texture definitions from textures.lmp
//
maptex = maptex1 = W_CacheLumpName ("TEXTURE1", PU_STATIC);
numtextures1 = LONG(*maptex);
maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
directory = maptex+1;
if (W_CheckNumForName ("TEXTURE2") != -1)
{
maptex2 = W_CacheLumpName ("TEXTURE2", PU_STATIC);
numtextures2 = LONG(*maptex2);
maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
}
else
{
maptex2 = NULL;
numtextures2 = 0;
maxoff2 = 0;
}
numtextures = numtextures1 + numtextures2;
//
// Init the startup thermometer at this point...
//
{
int spramount;
spramount = W_GetNumForName("S_END") - W_GetNumForName("S_START") + 1;
InitThermo(spramount + numtextures + 6);
}
textures = Z_Malloc (numtextures*4, PU_STATIC, 0);
texturecolumnlump = Z_Malloc (numtextures*4, PU_STATIC, 0);
texturecolumnofs = Z_Malloc (numtextures*4, PU_STATIC, 0);
texturecomposite = Z_Malloc (numtextures*4, PU_STATIC, 0);
texturecompositesize = Z_Malloc (numtextures*4, PU_STATIC, 0);
texturewidthmask = Z_Malloc (numtextures*4, PU_STATIC, 0);
textureheight = Z_Malloc (numtextures*4, PU_STATIC, 0);
totalwidth = 0;
for (i=0 ; i<numtextures ; i++, directory++)
{
#ifdef __NEXT__
if(!(i&63))
printf (".");
#else
IncThermo();
#endif
if (i == numtextures1)
{ // start looking in second texture file
maptex = maptex2;
maxoff = maxoff2;
directory = maptex+1;
}
offset = LONG(*directory);
if (offset > maxoff)
I_Error ("R_InitTextures: bad texture directory");
mtexture = (maptexture_t *) ( (byte *)maptex + offset);
texture = textures[i] = Z_Malloc (sizeof(texture_t)
+ sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), PU_STATIC,
0);
texture->width = SHORT(mtexture->width);
texture->height = SHORT(mtexture->height);
texture->patchcount = SHORT(mtexture->patchcount);
memcpy (texture->name, mtexture->name, sizeof(texture->name));
mpatch = &mtexture->patches[0];
patch = &texture->patches[0];
for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
{
patch->originx = SHORT(mpatch->originx);
patch->originy = SHORT(mpatch->originy);
patch->patch = patchlookup[SHORT(mpatch->patch)];
if (patch->patch == -1)
I_Error (
"R_InitTextures: Missing patch in texture %s",texture->name);
}
texturecolumnlump[i] = Z_Malloc (texture->width*2, PU_STATIC,0);
texturecolumnofs[i] = Z_Malloc (texture->width*2, PU_STATIC,0);
j = 1;
while (j*2 <= texture->width)
j<<=1;
texturewidthmask[i] = j-1;
textureheight[i] = texture->height<<FRACBITS;
totalwidth += texture->width;
}
Z_Free (maptex1);
if (maptex2)
Z_Free (maptex2);
//
// precalculate whatever possible
//
for(i = 0; i < numtextures; i++)
{
R_GenerateLookup(i);
CheckAbortStartup();
}
//
// translation table for global animation
//
texturetranslation = Z_Malloc ((numtextures+1)*4, PU_STATIC, 0);
for (i=0 ; i<numtextures ; i++)
texturetranslation[i] = i;
}
/*
================
=
= R_InitFlats
=
=================
*/
void R_InitFlats (void)
{
int i;
firstflat = W_GetNumForName ("F_START") + 1;
lastflat = W_GetNumForName ("F_END") - 1;
numflats = lastflat - firstflat + 1;
// translation table for global animation
flattranslation = Z_Malloc ((numflats+1)*4, PU_STATIC, 0);
for (i=0 ; i<numflats ; i++)
flattranslation[i] = i;
}
/*
================
=
= R_InitSpriteLumps
=
= Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
= need to be cached just for the header during rendering
=================
*/
void R_InitSpriteLumps (void)
{
int i;
patch_t *patch;
firstspritelump = W_GetNumForName ("S_START") + 1;
lastspritelump = W_GetNumForName ("S_END") - 1;
numspritelumps = lastspritelump - firstspritelump + 1;
spritewidth = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
spriteoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
spritetopoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
for (i=0 ; i< numspritelumps ; i++)
{
#ifdef __NEXT__
if (!(i&63))
printf (".");
#else
IncThermo();
#endif
patch = W_CacheLumpNum (firstspritelump+i, PU_CACHE);
spritewidth[i] = SHORT(patch->width)<<FRACBITS;
spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
}
}
/*
================
=
= R_InitColormaps
=
=================
*/
void R_InitColormaps (void)
{
int lump, length;
//
// load in the light tables
// 256 byte align tables
//
lump = W_GetNumForName("COLORMAP");
length = W_LumpLength (lump) + 255;
colormaps = Z_Malloc (length, PU_STATIC, 0);
colormaps = (byte *)( ((int)colormaps + 255)&~0xff);
W_ReadLump (lump,colormaps);
}
/*
================
=
= R_InitData
=
= Locates all the lumps that will be used by all views
= Must be called after W_Init
=================
*/
void R_InitData (void)
{
tprintf("\nR_InitTextures ",0);
R_InitTextures ();
//printf (".");
tprintf("R_InitFlats\n",0);
R_InitFlats ();
IncThermo();
//printf (".");
tprintf("R_InitSpriteLumps ",0);
R_InitSpriteLumps ();
IncThermo();
//printf (".");
R_InitColormaps ();
}
//=============================================================================
/*
================
=
= R_FlatNumForName
=
================
*/
int R_FlatNumForName (char *name)
{
int i;
char namet[9];
i = W_CheckNumForName (name);
if (i == -1)
{
namet[8] = 0;
memcpy (namet, name,8);
I_Error ("R_FlatNumForName: %s not found",namet);
}
return i - firstflat;
}
/*
================
=
= R_CheckTextureNumForName
=
================
*/
int R_CheckTextureNumForName (char *name)
{
int i;
if (name[0] == '-') // no texture marker
return 0;
for (i=0 ; i<numtextures ; i++)
if (!strncasecmp (textures[i]->name, name, 8) )
return i;
return -1;
}
/*
================
=
= R_TextureNumForName
=
================
*/
int R_TextureNumForName (char *name)
{
int i;
//char namet[9];
i = R_CheckTextureNumForName (name);
if (i==-1)
I_Error ("R_TextureNumForName: %s not found",name);
return i;
}
/*
=================
=
= R_PrecacheLevel
=
= Preloads all relevent graphics for the level
=================
*/
int flatmemory, texturememory, spritememory;
void R_PrecacheLevel (void)
{
char *flatpresent;
char *texturepresent;
char *spritepresent;
int i,j,k, lump;
texture_t *texture;
thinker_t *th;
spriteframe_t *sf;
if (demoplayback)
return;
//
// precache flats
//
flatpresent = alloca(numflats);
memset (flatpresent,0,numflats);
for (i=0 ; i<numsectors ; i++)
{
flatpresent[sectors[i].floorpic] = 1;
flatpresent[sectors[i].ceilingpic] = 1;
}
flatmemory = 0;
for (i=0 ; i<numflats ; i++)
if (flatpresent[i])
{
lump = firstflat + i;
flatmemory += lumpinfo[lump].size;
W_CacheLumpNum(lump, PU_CACHE);
}
//
// precache textures
//
texturepresent = alloca(numtextures);
memset (texturepresent,0, numtextures);
for (i=0 ; i<numsides ; i++)
{
texturepresent[sides[i].toptexture] = 1;
texturepresent[sides[i].midtexture] = 1;
texturepresent[sides[i].bottomtexture] = 1;
}
texturepresent[skytexture] = 1;
texturememory = 0;
for (i=0 ; i<numtextures ; i++)
{
if (!texturepresent[i])
continue;
texture = textures[i];
for (j=0 ; j<texture->patchcount ; j++)
{
lump = texture->patches[j].patch;
texturememory += lumpinfo[lump].size;
W_CacheLumpNum(lump , PU_CACHE);
}
}
//
// precache sprites
//
spritepresent = alloca(numsprites);
memset (spritepresent,0, numsprites);
for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
{
if (th->function == P_MobjThinker)
spritepresent[((mobj_t *)th)->sprite] = 1;
}
spritememory = 0;
for (i=0 ; i<numsprites ; i++)
{
if (!spritepresent[i])
continue;
for (j=0 ; j<sprites[i].numframes ; j++)
{
sf = &sprites[i].spriteframes[j];
for (k=0 ; k<8 ; k++)
{
lump = firstspritelump + sf->lump[k];
spritememory += lumpinfo[lump].size;
W_CacheLumpNum(lump , PU_CACHE);
}
}
}
}

498
Heretic Source/R_DRAW.C Normal file
View File

@ -0,0 +1,498 @@
// R_draw.c
#include "DoomDef.h"
#include "R_local.h"
/*
All drawing to the view buffer is accomplished in this file. The other refresh
files only know about ccordinates, not the architecture of the frame buffer.
*/
byte *viewimage;
int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
byte *ylookup[MAXHEIGHT];
int columnofs[MAXWIDTH];
byte translations[3][256]; // color tables for different players
byte *tinttable; // used for translucent sprites
/*
==================
=
= R_DrawColumn
=
= Source is the top of the column to scale
=
==================
*/
lighttable_t *dc_colormap;
int dc_x;
int dc_yl;
int dc_yh;
fixed_t dc_iscale;
fixed_t dc_texturemid;
byte *dc_source; // first pixel in a column (possibly virtual)
int dccount; // just for profiling
#ifndef __WATCOMC__
#ifndef __i386
#ifndef __m68k
void R_DrawColumn (void)
{
int count;
byte *dest;
fixed_t frac, fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
do
{
*dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
}
#endif // __m68k
#endif // __i386
#endif
void R_DrawColumnLow (void)
{
int count;
byte *dest;
fixed_t frac, fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
// dccount++;
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
do
{
*dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
}
#define FUZZTABLE 50
#define FUZZOFF (SCREENWIDTH)
int fuzzoffset[FUZZTABLE] = {
FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
};
int fuzzpos = 0;
void R_DrawFuzzColumn (void)
{
int count;
byte *dest;
fixed_t frac, fracstep;
if (!dc_yl)
dc_yl = 1;
if (dc_yh == viewheight-1)
dc_yh = viewheight - 2;
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
// OLD FUZZY INVISO SPRITE STUFF
/* do
{
*dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]];
if (++fuzzpos == FUZZTABLE)
fuzzpos = 0;
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
*/
do
{
*dest = tinttable[((*dest)<<8)+dc_colormap[dc_source[(frac>>FRACBITS)&127]]];
//*dest = dest[SCREENWIDTH*10+5];
// *dest = //tinttable[((*dest)<<8)+colormaps[dc_source[(frac>>FRACBITS)&127]]];
// *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
dest += SCREENWIDTH;
frac += fracstep;
} while(count--);
}
/*
========================
=
= R_DrawTranslatedColumn
=
========================
*/
byte *dc_translation;
byte *translationtables;
void R_DrawTranslatedColumn (void)
{
int count;
byte *dest;
fixed_t frac, fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
do
{
*dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
}
void R_DrawTranslatedFuzzColumn (void)
{
int count;
byte *dest;
fixed_t frac, fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
do
{
*dest = tinttable[((*dest)<<8)
+dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]];
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
}
//--------------------------------------------------------------------------
//
// PROC R_InitTranslationTables
//
//--------------------------------------------------------------------------
void R_InitTranslationTables (void)
{
int i;
// Load tint table
tinttable = W_CacheLumpName("TINTTAB", PU_STATIC);
// Allocate translation tables
translationtables = Z_Malloc(256*3+255, PU_STATIC, 0);
translationtables = (byte *)(( (int)translationtables + 255 )& ~255);
// Fill out the translation tables
for(i = 0; i < 256; i++)
{
if(i >= 225 && i <= 240)
{
translationtables[i] = 114+(i-225); // yellow
translationtables[i+256] = 145+(i-225); // red
translationtables[i+512] = 190+(i-225); // blue
}
else
{
translationtables[i] = translationtables[i+256]
= translationtables[i+512] = i;
}
}
}
/*
================
=
= R_DrawSpan
=
================
*/
int ds_y;
int ds_x1;
int ds_x2;
lighttable_t *ds_colormap;
fixed_t ds_xfrac;
fixed_t ds_yfrac;
fixed_t ds_xstep;
fixed_t ds_ystep;
byte *ds_source; // start of a 64*64 tile image
int dscount; // just for profiling
#ifndef __WATCOMC__
#ifndef __i386
#ifndef __m68k
void R_DrawSpan (void)
{
fixed_t xfrac, yfrac;
byte *dest;
int count, spot;
#ifdef RANGECHECK
if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
I_Error ("R_DrawSpan: %i to %i at %i",ds_x1,ds_x2,ds_y);
// dscount++;
#endif
xfrac = ds_xfrac;
yfrac = ds_yfrac;
dest = ylookup[ds_y] + columnofs[ds_x1];
count = ds_x2 - ds_x1;
do
{
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
*dest++ = ds_colormap[ds_source[spot]];
xfrac += ds_xstep;
yfrac += ds_ystep;
} while (count--);
}
#endif
#endif
#endif
void R_DrawSpanLow (void)
{
fixed_t xfrac, yfrac;
byte *dest;
int count, spot;
#ifdef RANGECHECK
if (ds_x2 < ds_x1 || ds_x1<0 || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
I_Error ("R_DrawSpan: %i to %i at %i",ds_x1,ds_x2,ds_y);
// dscount++;
#endif
xfrac = ds_xfrac;
yfrac = ds_yfrac;
dest = ylookup[ds_y] + columnofs[ds_x1];
count = ds_x2 - ds_x1;
do
{
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
*dest++ = ds_colormap[ds_source[spot]];
xfrac += ds_xstep;
yfrac += ds_ystep;
} while (count--);
}
/*
================
=
= R_InitBuffer
=
=================
*/
void R_InitBuffer (int width, int height)
{
int i;
viewwindowx = (SCREENWIDTH-width) >> 1;
for (i=0 ; i<width ; i++)
columnofs[i] = viewwindowx + i;
if (width == SCREENWIDTH)
viewwindowy = 0;
else
viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
for (i=0 ; i<height ; i++)
ylookup[i] = screen + (i+viewwindowy)*SCREENWIDTH;
}
/*
==================
=
= R_DrawViewBorder
=
= Draws the border around the view for different size windows
==================
*/
boolean BorderNeedRefresh;
void R_DrawViewBorder (void)
{
byte *src, *dest;
int x,y;
if (scaledviewwidth == SCREENWIDTH)
return;
if(shareware)
{
src = W_CacheLumpName ("FLOOR04", PU_CACHE);
}
else
{
src = W_CacheLumpName ("FLAT513", PU_CACHE);
}
dest = screen;
for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
for(x=viewwindowx; x < viewwindowx+viewwidth; x += 16)
{
V_DrawPatch(x, viewwindowy-4, W_CacheLumpName("bordt", PU_CACHE));
V_DrawPatch(x, viewwindowy+viewheight, W_CacheLumpName("bordb",
PU_CACHE));
}
for(y=viewwindowy; y < viewwindowy+viewheight; y += 16)
{
V_DrawPatch(viewwindowx-4, y, W_CacheLumpName("bordl", PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, y, W_CacheLumpName("bordr",
PU_CACHE));
}
V_DrawPatch(viewwindowx-4, viewwindowy-4, W_CacheLumpName("bordtl",
PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, viewwindowy-4,
W_CacheLumpName("bordtr", PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, viewwindowy+viewheight,
W_CacheLumpName("bordbr", PU_CACHE));
V_DrawPatch(viewwindowx-4, viewwindowy+viewheight,
W_CacheLumpName("bordbl", PU_CACHE));
}
/*
==================
=
= R_DrawTopBorder
=
= Draws the top border around the view for different size windows
==================
*/
boolean BorderTopRefresh;
void R_DrawTopBorder (void)
{
byte *src, *dest;
int x,y;
if (scaledviewwidth == SCREENWIDTH)
return;
if(shareware)
{
src = W_CacheLumpName ("FLOOR04", PU_CACHE);
}
else
{
src = W_CacheLumpName ("FLAT513", PU_CACHE);
}
dest = screen;
for (y=0 ; y<30 ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
if(viewwindowy < 25)
{
for(x=viewwindowx; x < viewwindowx+viewwidth; x += 16)
{
V_DrawPatch(x, viewwindowy-4, W_CacheLumpName("bordt", PU_CACHE));
}
V_DrawPatch(viewwindowx-4, viewwindowy, W_CacheLumpName("bordl",
PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, viewwindowy,
W_CacheLumpName("bordr", PU_CACHE));
V_DrawPatch(viewwindowx-4, viewwindowy+16, W_CacheLumpName("bordl",
PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, viewwindowy+16,
W_CacheLumpName("bordr", PU_CACHE));
V_DrawPatch(viewwindowx-4, viewwindowy-4, W_CacheLumpName("bordtl",
PU_CACHE));
V_DrawPatch(viewwindowx+viewwidth, viewwindowy-4,
W_CacheLumpName("bordtr", PU_CACHE));
}
}

468
Heretic Source/R_LOCAL.H Normal file
View File

@ -0,0 +1,468 @@
// R_local.h
#ifndef __R_LOCAL__
#define __R_LOCAL__
#define ANGLETOSKYSHIFT 22 // sky map is 256*128*4 maps
#define BASEYCENTER 100
#define MAXWIDTH 1120
#define MAXHEIGHT 832
#define PI 3.141592657
#define CENTERY (SCREENHEIGHT/2)
#define MINZ (FRACUNIT*4)
#define FIELDOFVIEW 2048 // fineangles in the SCREENWIDTH wide window
//
// lighting constants
//
#define LIGHTLEVELS 16
#define LIGHTSEGSHIFT 4
#define MAXLIGHTSCALE 48
#define LIGHTSCALESHIFT 12
#define MAXLIGHTZ 128
#define LIGHTZSHIFT 20
#define NUMCOLORMAPS 32 // number of diminishing
#define INVERSECOLORMAP 32
/*
==============================================================================
INTERNAL MAP TYPES
==============================================================================
*/
//================ used by play and refresh
typedef struct
{
fixed_t x,y;
} vertex_t;
struct line_s;
typedef struct
{
fixed_t floorheight, ceilingheight;
short floorpic, ceilingpic;
short lightlevel;
short special, tag;
int soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
mobj_t *soundtarget; // thing that made a sound (or null)
int blockbox[4]; // mapblock bounding box for height changes
degenmobj_t soundorg; // for any sounds played by the sector
int validcount; // if == validcount, already checked
mobj_t *thinglist; // list of mobjs in sector
void *specialdata; // thinker_t for reversable actions
int linecount;
struct line_s **lines; // [linecount] size
} sector_t;
typedef struct
{
fixed_t textureoffset; // add this to the calculated texture col
fixed_t rowoffset; // add this to the calculated texture top
short toptexture, bottomtexture, midtexture;
sector_t *sector;
} side_t;
typedef enum {ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE} slopetype_t;
typedef struct line_s
{
vertex_t *v1, *v2;
fixed_t dx,dy; // v2 - v1 for side checking
short flags;
short special, tag;
short sidenum[2]; // sidenum[1] will be -1 if one sided
fixed_t bbox[4];
slopetype_t slopetype; // to aid move clipping
sector_t *frontsector, *backsector;
int validcount; // if == validcount, already checked
void *specialdata; // thinker_t for reversable actions
} line_t;
typedef struct subsector_s
{
sector_t *sector;
short numlines;
short firstline;
} subsector_t;
typedef struct
{
vertex_t *v1, *v2;
fixed_t offset;
angle_t angle;
side_t *sidedef;
line_t *linedef;
sector_t *frontsector;
sector_t *backsector; // NULL for one sided lines
} seg_t;
typedef struct
{
fixed_t x,y,dx,dy; // partition line
fixed_t bbox[2][4]; // bounding box for each child
unsigned short children[2]; // if NF_SUBSECTOR its a subsector
} node_t;
/*
==============================================================================
OTHER TYPES
==============================================================================
*/
typedef byte lighttable_t; // this could be wider for >8 bit display
#define MAXVISPLANES 128
#define MAXOPENINGS SCREENWIDTH*64
typedef struct
{
fixed_t height;
int picnum;
int lightlevel;
int special;
int minx, maxx;
byte pad1; // leave pads for [minx-1]/[maxx+1]
byte top[SCREENWIDTH];
byte pad2;
byte pad3;
byte bottom[SCREENWIDTH];
byte pad4;
} visplane_t;
typedef struct drawseg_s
{
seg_t *curline;
int x1, x2;
fixed_t scale1, scale2, scalestep;
int silhouette; // 0=none, 1=bottom, 2=top, 3=both
fixed_t bsilheight; // don't clip sprites above this
fixed_t tsilheight; // don't clip sprites below this
// pointers to lists for sprite clipping
short *sprtopclip; // adjusted so [x1] is first value
short *sprbottomclip; // adjusted so [x1] is first value
short *maskedtexturecol; // adjusted so [x1] is first value
} drawseg_t;
#define SIL_NONE 0
#define SIL_BOTTOM 1
#define SIL_TOP 2
#define SIL_BOTH 3
#define MAXDRAWSEGS 256
// A vissprite_t is a thing that will be drawn during a refresh
typedef struct vissprite_s
{
struct vissprite_s *prev, *next;
int x1, x2;
fixed_t gx, gy; // for line side calculation
fixed_t gz, gzt; // global bottom / top for silhouette clipping
fixed_t startfrac; // horizontal position of x1
fixed_t scale;
fixed_t xiscale; // negative if flipped
fixed_t texturemid;
int patch;
lighttable_t *colormap;
int mobjflags; // for color translation and shadow draw
boolean psprite; // true if psprite
fixed_t footclip; // foot clipping
} vissprite_t;
extern visplane_t *floorplane, *ceilingplane;
// Sprites are patches with a special naming convention so they can be
// recognized by R_InitSprites. The sprite and frame specified by a
// thing_t is range checked at run time.
// a sprite is a patch_t that is assumed to represent a three dimensional
// object and may have multiple rotations pre drawn. Horizontal flipping
// is used to save space. Some sprites will only have one picture used
// for all views.
typedef struct
{
boolean rotate; // if false use 0 for any position
short lump[8]; // lump to use for view angles 0-7
byte flip[8]; // flip (1 = flip) to use for view angles 0-7
} spriteframe_t;
typedef struct
{
int numframes;
spriteframe_t *spriteframes;
} spritedef_t;
extern spritedef_t *sprites;
extern int numsprites;
//=============================================================================
extern int numvertexes;
extern vertex_t *vertexes;
extern int numsegs;
extern seg_t *segs;
extern int numsectors;
extern sector_t *sectors;
extern int numsubsectors;
extern subsector_t *subsectors;
extern int numnodes;
extern node_t *nodes;
extern int numlines;
extern line_t *lines;
extern int numsides;
extern side_t *sides;
extern fixed_t viewx, viewy, viewz;
extern angle_t viewangle;
extern player_t *viewplayer;
extern angle_t clipangle;
extern int viewangletox[FINEANGLES/2];
extern angle_t xtoviewangle[SCREENWIDTH+1];
extern fixed_t finetangent[FINEANGLES/2];
extern fixed_t rw_distance;
extern angle_t rw_normalangle;
//
// R_main.c
//
extern int viewwidth, viewheight, viewwindowx, viewwindowy;
extern int centerx, centery;
extern int flyheight;
extern fixed_t centerxfrac;
extern fixed_t centeryfrac;
extern fixed_t projection;
extern int validcount;
extern int sscount, linecount, loopcount;
extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
extern lighttable_t *scalelightfixed[MAXLIGHTSCALE];
extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
extern int extralight;
extern lighttable_t *fixedcolormap;
extern fixed_t viewcos, viewsin;
extern int detailshift; // 0 = high, 1 = low
extern void (*colfunc) (void);
extern void (*basecolfunc) (void);
extern void (*fuzzcolfunc) (void);
extern void (*spanfunc) (void);
int R_PointOnSide (fixed_t x, fixed_t y, node_t *node);
int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line);
angle_t R_PointToAngle (fixed_t x, fixed_t y);
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
fixed_t R_PointToDist (fixed_t x, fixed_t y);
fixed_t R_ScaleFromGlobalAngle (angle_t visangle);
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
void R_AddPointToBox (int x, int y, fixed_t *box);
//
// R_bsp.c
//
extern seg_t *curline;
extern side_t *sidedef;
extern line_t *linedef;
extern sector_t *frontsector, *backsector;
extern int rw_x;
extern int rw_stopx;
extern boolean segtextured;
extern boolean markfloor; // false if the back side is the same plane
extern boolean markceiling;
extern boolean skymap;
extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
extern lighttable_t **hscalelight, **vscalelight, **dscalelight;
typedef void (*drawfunc_t) (int start, int stop);
void R_ClearClipSegs (void);
void R_ClearDrawSegs (void);
void R_InitSkyMap (void);
void R_RenderBSPNode (int bspnum);
//
// R_segs.c
//
extern int rw_angle1; // angle to line origin
void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2);
//
// R_plane.c
//
typedef void (*planefunction_t) (int top, int bottom);
extern planefunction_t floorfunc, ceilingfunc;
extern int skyflatnum;
extern short openings[MAXOPENINGS], *lastopening;
extern short floorclip[SCREENWIDTH];
extern short ceilingclip[SCREENWIDTH];
extern fixed_t yslope[SCREENHEIGHT];
extern fixed_t distscale[SCREENWIDTH];
void R_InitPlanes (void);
void R_ClearPlanes (void);
void R_MapPlane (int y, int x1, int x2);
void R_MakeSpans (int x, int t1, int b1, int t2, int b2);
void R_DrawPlanes (void);
visplane_t *R_FindPlane (fixed_t height, int picnum, int lightlevel,
int special);
visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);
//
// R_debug.m
//
extern int drawbsp;
void RD_OpenMapWindow (void);
void RD_ClearMapWindow (void);
void RD_DisplayLine (int x1, int y1, int x2, int y2, float gray);
void RD_DrawNodeLine (node_t *node);
void RD_DrawLineCheck (seg_t *line);
void RD_DrawLine (seg_t *line);
void RD_DrawBBox (fixed_t *bbox);
//
// R_data.c
//
extern fixed_t *textureheight; // needed for texture pegging
extern fixed_t *spritewidth; // needed for pre rendering (fracs)
extern fixed_t *spriteoffset;
extern fixed_t *spritetopoffset;
extern lighttable_t *colormaps;
extern int viewwidth, scaledviewwidth, viewheight;
extern int firstflat;
extern int numflats;
extern int *flattranslation; // for global animation
extern int *texturetranslation; // for global animation
extern int firstspritelump, lastspritelump, numspritelumps;
byte *R_GetColumn (int tex, int col);
void R_InitData (void);
void R_PrecacheLevel (void);
//
// R_things.c
//
#define MAXVISSPRITES 128
extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
extern vissprite_t vsprsortedhead;
// constant arrays used for psprite clipping and initializing clipping
extern short negonearray[SCREENWIDTH];
extern short screenheightarray[SCREENWIDTH];
// vars for R_DrawMaskedColumn
extern short *mfloorclip;
extern short *mceilingclip;
extern fixed_t spryscale;
extern fixed_t sprtopscreen;
extern fixed_t sprbotscreen;
extern fixed_t pspritescale, pspriteiscale;
void R_DrawMaskedColumn (column_t *column, signed int baseclip);
void R_SortVisSprites (void);
void R_AddSprites (sector_t *sec);
void R_AddPSprites (void);
void R_DrawSprites (void);
void R_InitSprites (char **namelist);
void R_ClearSprites (void);
void R_DrawMasked (void);
void R_ClipVisSprite (vissprite_t *vis, int xl, int xh);
//=============================================================================
//
// R_draw.c
//
//=============================================================================
extern lighttable_t *dc_colormap;
extern int dc_x;
extern int dc_yl;
extern int dc_yh;
extern fixed_t dc_iscale;
extern fixed_t dc_texturemid;
extern byte *dc_source; // first pixel in a column
void R_DrawColumn (void);
void R_DrawColumnLow (void);
void R_DrawFuzzColumn (void);
void R_DrawFuzzColumnLow (void);
void R_DrawTranslatedColumn (void);
void R_DrawTranslatedFuzzColumn (void);
void R_DrawTranslatedColumnLow (void);
extern int ds_y;
extern int ds_x1;
extern int ds_x2;
extern lighttable_t *ds_colormap;
extern fixed_t ds_xfrac;
extern fixed_t ds_yfrac;
extern fixed_t ds_xstep;
extern fixed_t ds_ystep;
extern byte *ds_source; // start of a 64*64 tile image
extern byte *translationtables;
extern byte *dc_translation;
void R_DrawSpan (void);
void R_DrawSpanLow (void);
void R_InitBuffer (int width, int height);
void R_InitTranslationTables (void);
#endif // __R_LOCAL__

847
Heretic Source/R_MAIN.C Normal file
View File

@ -0,0 +1,847 @@
// R_main.c
#include <math.h>
#include "DoomDef.h"
#include "R_local.h"
/*
*/
int viewangleoffset;
#ifdef __WATCOMC__
int newViewAngleOff;
#endif
int validcount = 1; // increment every time a check is made
lighttable_t *fixedcolormap;
extern lighttable_t **walllights;
int centerx, centery;
fixed_t centerxfrac, centeryfrac;
fixed_t projection;
int framecount; // just for profiling purposes
int sscount, linecount, loopcount;
fixed_t viewx, viewy, viewz;
angle_t viewangle;
fixed_t viewcos, viewsin;
player_t *viewplayer;
int detailshift; // 0 = high, 1 = low
//
// precalculated math tables
//
angle_t clipangle;
// The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view
// angles to screen X coordinates, flattening the arc to a flat projection
// plane. There will be many angles mapped to the same X.
int viewangletox[FINEANGLES/2];
// The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle
// that maps back to x ranges from clipangle to -clipangle
angle_t xtoviewangle[SCREENWIDTH+1];
// the finetangentgent[angle+FINEANGLES/4] table holds the fixed_t tangent
// values for view angles, ranging from MININT to 0 to MAXINT.
// fixed_t finetangent[FINEANGLES/2];
// fixed_t finesine[5*FINEANGLES/4];
fixed_t *finecosine = &finesine[FINEANGLES/4];
lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t *scalelightfixed[MAXLIGHTSCALE];
lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
int extralight; // bumped light from gun blasts
void (*colfunc) (void);
void (*basecolfunc) (void);
void (*fuzzcolfunc) (void);
void (*transcolfunc) (void);
void (*spanfunc) (void);
/*
===================
=
= R_AddPointToBox
=
===================
*/
void R_AddPointToBox (int x, int y, fixed_t *box)
{
if (x< box[BOXLEFT])
box[BOXLEFT] = x;
if (x> box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y< box[BOXBOTTOM])
box[BOXBOTTOM] = y;
if (y> box[BOXTOP])
box[BOXTOP] = y;
}
/*
===============================================================================
=
= R_PointOnSide
=
= Returns side 0 (front) or 1 (back)
===============================================================================
*/
int R_PointOnSide (fixed_t x, fixed_t y, node_t *node)
{
fixed_t dx,dy;
fixed_t left, right;
if (!node->dx)
{
if (x <= node->x)
return node->dy > 0;
return node->dy < 0;
}
if (!node->dy)
{
if (y <= node->y)
return node->dx < 0;
return node->dx > 0;
}
dx = (x - node->x);
dy = (y - node->y);
// try to quickly decide by looking at sign bits
if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 )
{
if ( (node->dy ^ dx) & 0x80000000 )
return 1; // (left is negative)
return 0;
}
left = FixedMul ( node->dy>>FRACBITS , dx );
right = FixedMul ( dy , node->dx>>FRACBITS );
if (right < left)
return 0; // front side
return 1; // back side
}
int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line)
{
fixed_t lx, ly;
fixed_t ldx, ldy;
fixed_t dx,dy;
fixed_t left, right;
lx = line->v1->x;
ly = line->v1->y;
ldx = line->v2->x - lx;
ldy = line->v2->y - ly;
if (!ldx)
{
if (x <= lx)
return ldy > 0;
return ldy < 0;
}
if (!ldy)
{
if (y <= ly)
return ldx < 0;
return ldx > 0;
}
dx = (x - lx);
dy = (y - ly);
// try to quickly decide by looking at sign bits
if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 )
{
if ( (ldy ^ dx) & 0x80000000 )
return 1; // (left is negative)
return 0;
}
left = FixedMul ( ldy>>FRACBITS , dx );
right = FixedMul ( dy , ldx>>FRACBITS );
if (right < left)
return 0; // front side
return 1; // back side
}
/*
===============================================================================
=
= R_PointToAngle
=
===============================================================================
*/
// to get a global angle from cartesian coordinates, the coordinates are
// flipped until they are in the first octant of the coordinate system, then
// the y (<=x) is scaled and divided by x to get a tangent (slope) value
// which is looked up in the tantoangle[] table. The +1 size is to handle
// the case when x==y without additional checking.
#define SLOPERANGE 2048
#define SLOPEBITS 11
#define DBITS (FRACBITS-SLOPEBITS)
extern int tantoangle[SLOPERANGE+1]; // get from tables.c
// int tantoangle[SLOPERANGE+1];
int SlopeDiv (unsigned num, unsigned den)
{
unsigned ans;
if (den < 512)
return SLOPERANGE;
ans = (num<<3)/(den>>8);
return ans <= SLOPERANGE ? ans : SLOPERANGE;
}
angle_t R_PointToAngle (fixed_t x, fixed_t y)
{
x -= viewx;
y -= viewy;
if ( (!x) && (!y) )
return 0;
if (x>= 0)
{ // x >=0
if (y>= 0)
{ // y>= 0
if (x>y)
return tantoangle[ SlopeDiv(y,x)]; // octant 0
else
return ANG90-1-tantoangle[ SlopeDiv(x,y)]; // octant 1
}
else
{ // y<0
y = -y;
if (x>y)
return -tantoangle[SlopeDiv(y,x)]; // octant 8
else
return ANG270+tantoangle[ SlopeDiv(x,y)]; // octant 7
}
}
else
{ // x<0
x = -x;
if (y>= 0)
{ // y>= 0
if (x>y)
return ANG180-1-tantoangle[ SlopeDiv(y,x)]; // octant 3
else
return ANG90+ tantoangle[ SlopeDiv(x,y)]; // octant 2
}
else
{ // y<0
y = -y;
if (x>y)
return ANG180+tantoangle[ SlopeDiv(y,x)]; // octant 4
else
return ANG270-1-tantoangle[ SlopeDiv(x,y)]; // octant 5
}
}
return 0;
}
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{
viewx = x1;
viewy = y1;
return R_PointToAngle (x2, y2);
}
fixed_t R_PointToDist (fixed_t x, fixed_t y)
{
int angle;
fixed_t dx, dy, temp;
fixed_t dist;
dx = abs(x - viewx);
dy = abs(y - viewy);
if (dy>dx)
{
temp = dx;
dx = dy;
dy = temp;
}
angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
dist = FixedDiv (dx, finesine[angle] ); // use as cosine
return dist;
}
/*
=================
=
= R_InitPointToAngle
=
=================
*/
void R_InitPointToAngle (void)
{
// now getting from tables.c
#if 0
int i;
long t;
float f;
//
// slope (tangent) to angle lookup
//
for (i=0 ; i<=SLOPERANGE ; i++)
{
f = atan( (float)i/SLOPERANGE )/(3.141592657*2);
t = 0xffffffff*f;
tantoangle[i] = t;
}
#endif
}
//=============================================================================
/*
================
=
= R_ScaleFromGlobalAngle
=
= Returns the texture mapping scale for the current line at the given angle
= rw_distance must be calculated first
================
*/
fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
{
fixed_t scale;
int anglea, angleb;
int sinea, sineb;
fixed_t num,den;
#if 0
{
fixed_t dist,z;
fixed_t sinv, cosv;
sinv = finesine[(visangle-rw_normalangle)>>ANGLETOFINESHIFT];
dist = FixedDiv (rw_distance, sinv);
cosv = finecosine[(viewangle-visangle)>>ANGLETOFINESHIFT];
z = abs(FixedMul (dist, cosv));
scale = FixedDiv(projection, z);
return scale;
}
#endif
anglea = ANG90 + (visangle-viewangle);
angleb = ANG90 + (visangle-rw_normalangle);
// bothe sines are allways positive
sinea = finesine[anglea>>ANGLETOFINESHIFT];
sineb = finesine[angleb>>ANGLETOFINESHIFT];
num = FixedMul(projection,sineb)<<detailshift;
den = FixedMul(rw_distance,sinea);
if (den > num>>16)
{
scale = FixedDiv (num, den);
if (scale > 64*FRACUNIT)
scale = 64*FRACUNIT;
else if (scale < 256)
scale = 256;
}
else
scale = 64*FRACUNIT;
return scale;
}
/*
=================
=
= R_InitTables
=
=================
*/
void R_InitTables (void)
{
// now getting from tables.c
#if 0
int i;
float a, fv;
int t;
//
// viewangle tangent table
//
for (i=0 ; i<FINEANGLES/2 ; i++)
{
a = (i-FINEANGLES/4+0.5)*PI*2/FINEANGLES;
fv = FRACUNIT*tan (a);
t = fv;
finetangent[i] = t;
}
//
// finesine table
//
for (i=0 ; i<5*FINEANGLES/4 ; i++)
{
// OPTIMIZE: mirror...
a = (i+0.5)*PI*2/FINEANGLES;
t = FRACUNIT*sin (a);
finesine[i] = t;
}
#endif
}
/*
=================
=
= R_InitTextureMapping
=
=================
*/
void R_InitTextureMapping (void)
{
int i;
int x;
int t;
fixed_t focallength;
//
// use tangent table to generate viewangletox
// viewangletox will give the next greatest x after the view angle
//
// calc focallength so FIELDOFVIEW angles covers SCREENWIDTH
focallength = FixedDiv (centerxfrac
, finetangent[FINEANGLES/4+FIELDOFVIEW/2] );
for (i=0 ; i<FINEANGLES/2 ; i++)
{
if (finetangent[i] > FRACUNIT*2)
t = -1;
else if (finetangent[i] < -FRACUNIT*2)
t = viewwidth+1;
else
{
t = FixedMul (finetangent[i], focallength);
t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS;
if (t < -1)
t = -1;
else if (t>viewwidth+1)
t = viewwidth+1;
}
viewangletox[i] = t;
}
//
// scan viewangletox[] to generate xtoviewangleangle[]
//
// xtoviewangle will give the smallest view angle that maps to x
for (x=0;x<=viewwidth;x++)
{
i = 0;
while (viewangletox[i]>x)
i++;
xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
}
//
// take out the fencepost cases from viewangletox
//
for (i=0 ; i<FINEANGLES/2 ; i++)
{
t = FixedMul (finetangent[i], focallength);
t = centerx - t;
if (viewangletox[i] == -1)
viewangletox[i] = 0;
else if (viewangletox[i] == viewwidth+1)
viewangletox[i] = viewwidth;
}
clipangle = xtoviewangle[0];
}
//=============================================================================
/*
====================
=
= R_InitLightTables
=
= Only inits the zlight table, because the scalelight table changes
= with view size
=
====================
*/
#define DISTMAP 2
void R_InitLightTables (void)
{
int i,j, level, startmap;
int scale;
//
// Calculate the light levels to use for each level / distance combination
//
for (i=0 ; i< LIGHTLEVELS ; i++)
{
startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
for (j=0 ; j<MAXLIGHTZ ; j++)
{
scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
scale >>= LIGHTSCALESHIFT;
level = startmap - scale/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS-1;
zlight[i][j] = colormaps + level*256;
}
}
}
/*
==============
=
= R_SetViewSize
=
= Don't really change anything here, because i might be in the middle of
= a refresh. The change will take effect next refresh.
=
==============
*/
boolean setsizeneeded;
int setblocks, setdetail;
void R_SetViewSize (int blocks, int detail)
{
setsizeneeded = true;
setblocks = blocks;
setdetail = detail;
}
/*
==============
=
= R_ExecuteSetViewSize
=
==============
*/
void R_ExecuteSetViewSize (void)
{
fixed_t cosadj, dy;
int i,j, level, startmap;
setsizeneeded = false;
if (setblocks == 11)
{
scaledviewwidth = SCREENWIDTH;
viewheight = SCREENHEIGHT;
}
else
{
scaledviewwidth = setblocks*32;
viewheight = (setblocks*158/10);
}
detailshift = setdetail;
viewwidth = scaledviewwidth>>detailshift;
centery = viewheight/2;
centerx = viewwidth/2;
centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS;
projection = centerxfrac;
if (!detailshift)
{
colfunc = basecolfunc = R_DrawColumn;
fuzzcolfunc = R_DrawFuzzColumn;
transcolfunc = R_DrawTranslatedColumn;
spanfunc = R_DrawSpan;
}
else
{
colfunc = basecolfunc = R_DrawColumnLow;
fuzzcolfunc = R_DrawFuzzColumn;
transcolfunc = R_DrawTranslatedColumn;
spanfunc = R_DrawSpanLow;
}
R_InitBuffer (scaledviewwidth, viewheight);
R_InitTextureMapping ();
//
// psprite scales
//
pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
//
// thing clipping
//
for (i=0 ; i<viewwidth ; i++)
screenheightarray[i] = viewheight;
//
// planes
//
for (i=0 ; i<viewheight ; i++)
{
dy = ((i-viewheight/2)<<FRACBITS)+FRACUNIT/2;
dy = abs(dy);
yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT, dy);
}
for (i=0 ; i<viewwidth ; i++)
{
cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
distscale[i] = FixedDiv (FRACUNIT,cosadj);
}
//
// Calculate the light levels to use for each level / scale combination
//
for (i=0 ; i< LIGHTLEVELS ; i++)
{
startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
for (j=0 ; j<MAXLIGHTSCALE ; j++)
{
level = startmap - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS-1;
scalelight[i][j] = colormaps + level*256;
}
}
//
// draw the border
//
R_DrawViewBorder (); // erase old menu stuff
}
/*
==============
=
= R_Init
=
==============
*/
int detailLevel;
int screenblocks;
void R_Init (void)
{
tprintf("R_InitData ",1);
R_InitData ();
//printf (".");
tprintf("R_InitPointToAngle\n",0);
R_InitPointToAngle ();
//printf (".");
tprintf("R_InitTables ",0);
R_InitTables ();
// viewwidth / viewheight / detailLevel are set by the defaults
//printf (".");
R_SetViewSize (screenblocks, detailLevel);
tprintf("R_InitPlanes\n",0);
R_InitPlanes ();
//printf (".");
tprintf("R_InitLightTables ",0);
R_InitLightTables ();
//printf (".");
tprintf("R_InitSkyMap\n",0);
R_InitSkyMap ();
//printf (".");
R_InitTranslationTables();
framecount = 0;
}
/*
==============
=
= R_PointInSubsector
=
==============
*/
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
{
node_t *node;
int side, nodenum;
if (!numnodes) // single subsector is a special case
return subsectors;
nodenum = numnodes-1;
while (! (nodenum & NF_SUBSECTOR) )
{
node = &nodes[nodenum];
side = R_PointOnSide (x, y, node);
nodenum = node->children[side];
}
return &subsectors[nodenum & ~NF_SUBSECTOR];
}
//----------------------------------------------------------------------------
//
// PROC R_SetupFrame
//
//----------------------------------------------------------------------------
void R_SetupFrame(player_t *player)
{
int i;
int tableAngle;
int tempCentery;
//drawbsp = 1;
viewplayer = player;
#ifdef __WATCOMC__
viewangleoffset = newViewAngleOff<<ANGLETOFINESHIFT;
#endif
viewangle = player->mo->angle+viewangleoffset;
tableAngle = viewangle>>ANGLETOFINESHIFT;
if(player->chickenTics && player->chickenPeck)
{ // Set chicken attack view position
viewx = player->mo->x+player->chickenPeck*finecosine[tableAngle];
viewy = player->mo->y+player->chickenPeck*finesine[tableAngle];
}
else
{ // Normal view position
viewx = player->mo->x;
viewy = player->mo->y;
}
extralight = player->extralight;
viewz = player->viewz;
tempCentery = viewheight/2+(player->lookdir)*screenblocks/10;
if(centery != tempCentery)
{
centery = tempCentery;
centeryfrac = centery<<FRACBITS;
for(i = 0; i < viewheight; i++)
{
yslope[i] = FixedDiv ((viewwidth<<detailshift)/2*FRACUNIT,
abs(((i-centery)<<FRACBITS)+FRACUNIT/2));
}
}
viewsin = finesine[tableAngle];
viewcos = finecosine[tableAngle];
sscount = 0;
if(player->fixedcolormap)
{
fixedcolormap = colormaps+player->fixedcolormap
*256*sizeof(lighttable_t);
walllights = scalelightfixed;
for(i = 0; i < MAXLIGHTSCALE; i++)
{
scalelightfixed[i] = fixedcolormap;
}
}
else
{
fixedcolormap = 0;
}
framecount++;
validcount++;
if(BorderNeedRefresh)
{
if(setblocks < 10)
{
R_DrawViewBorder();
}
BorderNeedRefresh = false;
BorderTopRefresh = false;
UpdateState |= I_FULLSCRN;
}
if(BorderTopRefresh)
{
if(setblocks < 10)
{
R_DrawTopBorder();
}
BorderTopRefresh = false;
UpdateState |= I_MESSAGES;
}
#ifdef __NeXT__
RD_ClearMapWindow ();
#endif
#ifdef __WATCOMC__
destview = destscreen+(viewwindowx>>2)+viewwindowy*80;
#endif
#if 0
{
static int frame;
memset (screen, frame, SCREENWIDTH*SCREENHEIGHT);
frame++;
}
#endif
}
/*
==============
=
= R_RenderView
=
==============
*/
void R_RenderPlayerView (player_t *player)
{
R_SetupFrame (player);
R_ClearClipSegs ();
R_ClearDrawSegs ();
R_ClearPlanes ();
R_ClearSprites ();
NetUpdate (); // check for new console commands
R_RenderBSPNode (numnodes-1); // the head node is the last node output
NetUpdate (); // check for new console commands
R_DrawPlanes ();
NetUpdate (); // check for new console commands
R_DrawMasked ();
NetUpdate (); // check for new console commands
}

472
Heretic Source/R_PLANE.C Normal file
View File

@ -0,0 +1,472 @@
// R_planes.c
#include "DoomDef.h"
#include "R_local.h"
planefunction_t floorfunc, ceilingfunc;
//
// sky mapping
//
int skyflatnum;
int skytexture;
int skytexturemid;
fixed_t skyiscale;
//
// opening
//
visplane_t visplanes[MAXVISPLANES], *lastvisplane;
visplane_t *floorplane, *ceilingplane;
short openings[MAXOPENINGS], *lastopening;
//
// clip values are the solid pixel bounding the range
// floorclip starts out SCREENHEIGHT
// ceilingclip starts out -1
//
short floorclip[SCREENWIDTH];
short ceilingclip[SCREENWIDTH];
//
// spanstart holds the start of a plane span
// initialized to 0 at start
//
int spanstart[SCREENHEIGHT];
int spanstop[SCREENHEIGHT];
//
// texture mapping
//
lighttable_t **planezlight;
fixed_t planeheight;
fixed_t yslope[SCREENHEIGHT];
fixed_t distscale[SCREENWIDTH];
fixed_t basexscale, baseyscale;
fixed_t cachedheight[SCREENHEIGHT];
fixed_t cacheddistance[SCREENHEIGHT];
fixed_t cachedxstep[SCREENHEIGHT];
fixed_t cachedystep[SCREENHEIGHT];
/*
================
=
= R_InitSkyMap
=
= Called whenever the view size changes
=
================
*/
void R_InitSkyMap (void)
{
skyflatnum = R_FlatNumForName ("F_SKY1");
skytexturemid = 200*FRACUNIT;
skyiscale = FRACUNIT;
}
/*
====================
=
= R_InitPlanes
=
= Only at game startup
====================
*/
void R_InitPlanes (void)
{
}
/*
================
=
= R_MapPlane
=
global vars:
planeheight
ds_source
basexscale
baseyscale
viewx
viewy
BASIC PRIMITIVE
================
*/
void R_MapPlane (int y, int x1, int x2)
{
angle_t angle;
fixed_t distance, length;
unsigned index;
#ifdef RANGECHECK
if (x2 < x1 || x1<0 || x2>=viewwidth || (unsigned)y>viewheight)
I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
#endif
if (planeheight != cachedheight[y])
{
cachedheight[y] = planeheight;
distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale);
ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale);
}
else
{
distance = cacheddistance[y];
ds_xstep = cachedxstep[y];
ds_ystep = cachedystep[y];
}
length = FixedMul (distance,distscale[x1]);
angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
ds_xfrac = viewx + FixedMul(finecosine[angle], length);
ds_yfrac = -viewy - FixedMul(finesine[angle], length);
if (fixedcolormap)
ds_colormap = fixedcolormap;
else
{
index = distance >> LIGHTZSHIFT;
if (index >= MAXLIGHTZ )
index = MAXLIGHTZ-1;
ds_colormap = planezlight[index];
}
ds_y = y;
ds_x1 = x1;
ds_x2 = x2;
spanfunc (); // high or low detail
}
//=============================================================================
/*
====================
=
= R_ClearPlanes
=
= At begining of frame
====================
*/
void R_ClearPlanes (void)
{
int i;
angle_t angle;
//
// opening / clipping determination
//
for (i=0 ; i<viewwidth ; i++)
{
floorclip[i] = viewheight;
ceilingclip[i] = -1;
}
lastvisplane = visplanes;
lastopening = openings;
//
// texture calculation
//
memset (cachedheight, 0, sizeof(cachedheight));
angle = (viewangle-ANG90)>>ANGLETOFINESHIFT; // left to right mapping
// scale will be unit scale at SCREENWIDTH/2 distance
basexscale = FixedDiv (finecosine[angle],centerxfrac);
baseyscale = -FixedDiv (finesine[angle],centerxfrac);
}
/*
===============
=
= R_FindPlane
=
===============
*/
visplane_t *R_FindPlane(fixed_t height, int picnum,
int lightlevel, int special)
{
visplane_t *check;
if(picnum == skyflatnum)
{
// all skies map together
height = 0;
lightlevel = 0;
}
for(check = visplanes; check < lastvisplane; check++)
{
if(height == check->height
&& picnum == check->picnum
&& lightlevel == check->lightlevel
&& special == check->special)
break;
}
if(check < lastvisplane)
{
return(check);
}
if(lastvisplane-visplanes == MAXVISPLANES)
{
I_Error("R_FindPlane: no more visplanes");
}
lastvisplane++;
check->height = height;
check->picnum = picnum;
check->lightlevel = lightlevel;
check->special = special;
check->minx = SCREENWIDTH;
check->maxx = -1;
memset(check->top,0xff,sizeof(check->top));
return(check);
}
/*
===============
=
= R_CheckPlane
=
===============
*/
visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
{
int intrl, intrh;
int unionl, unionh;
int x;
if (start < pl->minx)
{
intrl = pl->minx;
unionl = start;
}
else
{
unionl = pl->minx;
intrl = start;
}
if (stop > pl->maxx)
{
intrh = pl->maxx;
unionh = stop;
}
else
{
unionh = pl->maxx;
intrh = stop;
}
for (x=intrl ; x<= intrh ; x++)
if (pl->top[x] != 0xff)
break;
if (x > intrh)
{
pl->minx = unionl;
pl->maxx = unionh;
return pl; // use the same one
}
// make a new visplane
lastvisplane->height = pl->height;
lastvisplane->picnum = pl->picnum;
lastvisplane->lightlevel = pl->lightlevel;
lastvisplane->special = pl->special;
pl = lastvisplane++;
pl->minx = start;
pl->maxx = stop;
memset (pl->top,0xff,sizeof(pl->top));
return pl;
}
//=============================================================================
/*
================
=
= R_MakeSpans
=
================
*/
void R_MakeSpans (int x, int t1, int b1, int t2, int b2)
{
while (t1 < t2 && t1<=b1)
{
R_MapPlane (t1,spanstart[t1],x-1);
t1++;
}
while (b1 > b2 && b1>=t1)
{
R_MapPlane (b1,spanstart[b1],x-1);
b1--;
}
while (t2 < t1 && t2<=b2)
{
spanstart[t2] = x;
t2++;
}
while (b2 > b1 && b2>=t2)
{
spanstart[b2] = x;
b2--;
}
}
/*
================
=
= R_DrawPlanes
=
= At the end of each frame
================
*/
void R_DrawPlanes (void)
{
visplane_t *pl;
int light;
int x, stop;
int angle;
byte *tempSource;
byte *dest;
int count;
fixed_t frac, fracstep;
extern byte *ylookup[MAXHEIGHT];
extern int columnofs[MAXWIDTH];
#ifdef RANGECHECK
if (ds_p - drawsegs > MAXDRAWSEGS)
I_Error ("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
if (lastvisplane - visplanes > MAXVISPLANES)
I_Error ("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes);
if (lastopening - openings > MAXOPENINGS)
I_Error ("R_DrawPlanes: opening overflow (%i)", lastopening - openings);
#endif
for (pl = visplanes ; pl < lastvisplane ; pl++)
{
if (pl->minx > pl->maxx)
continue;
//
// sky flat
//
if (pl->picnum == skyflatnum)
{
dc_iscale = skyiscale;
dc_colormap = colormaps;// sky is allways drawn full bright
dc_texturemid = skytexturemid;
for (x=pl->minx ; x <= pl->maxx ; x++)
{
dc_yl = pl->top[x];
dc_yh = pl->bottom[x];
if (dc_yl <= dc_yh)
{
angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
dc_x = x;
dc_source = R_GetColumn(skytexture, angle);
count = dc_yh - dc_yl;
if (count < 0)
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = 1;
frac = (dc_texturemid>>FRACBITS) + (dc_yl-centery);
do
{
*dest = dc_source[frac];
dest += SCREENWIDTH;
frac += fracstep;
} while (count--);
// colfunc ();
}
}
continue;
}
//
// regular flat
//
tempSource = W_CacheLumpNum(firstflat +
flattranslation[pl->picnum], PU_STATIC);
switch(pl->special)
{
case 25: case 26: case 27: case 28: case 29: // Scroll_North
ds_source = tempSource;
break;
case 20: case 21: case 22: case 23: case 24: // Scroll_East
ds_source = tempSource+((63-((leveltime>>1)&63))<<
(pl->special-20)&63);
//ds_source = tempSource+((leveltime>>1)&63);
break;
case 30: case 31: case 32: case 33: case 34: // Scroll_South
ds_source = tempSource;
break;
case 35: case 36: case 37: case 38: case 39: // Scroll_West
ds_source = tempSource;
break;
case 4: // Scroll_EastLavaDamage
ds_source = tempSource+(((63-((leveltime>>1)&63))<<3)&63);
break;
default:
ds_source = tempSource;
}
planeheight = abs(pl->height-viewz);
light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
if (light >= LIGHTLEVELS)
light = LIGHTLEVELS-1;
if (light < 0)
light = 0;
planezlight = zlight[light];
pl->top[pl->maxx+1] = 0xff;
pl->top[pl->minx-1] = 0xff;
stop = pl->maxx + 1;
for (x=pl->minx ; x<= stop ; x++)
R_MakeSpans (x,pl->top[x-1],pl->bottom[x-1]
,pl->top[x],pl->bottom[x]);
Z_ChangeTag (tempSource, PU_CACHE);
}
}

645
Heretic Source/R_SEGS.C Normal file
View File

@ -0,0 +1,645 @@
//**************************************************************************
//**
//** R_SEGS.C
//**
//** This version has the tall-sector-crossing-precision-bug fixed.
//**
//**************************************************************************
#include "DoomDef.h"
#include "R_local.h"
// OPTIMIZE: closed two sided lines as single sided
boolean segtextured; // true if any of the segs textures might be vis
boolean markfloor; // false if the back side is the same plane
boolean markceiling;
boolean maskedtexture;
int toptexture, bottomtexture, midtexture;
angle_t rw_normalangle;
int rw_angle1; // angle to line origin
//
// wall
//
int rw_x;
int rw_stopx;
angle_t rw_centerangle;
fixed_t rw_offset;
fixed_t rw_distance;
fixed_t rw_scale;
fixed_t rw_scalestep;
fixed_t rw_midtexturemid;
fixed_t rw_toptexturemid;
fixed_t rw_bottomtexturemid;
int worldtop, worldbottom, worldhigh, worldlow;
fixed_t pixhigh, pixlow;
fixed_t pixhighstep, pixlowstep;
fixed_t topfrac, topstep;
fixed_t bottomfrac, bottomstep;
lighttable_t **walllights;
short *maskedtexturecol;
/*
================
=
= R_RenderMaskedSegRange
=
================
*/
void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
{
unsigned index;
column_t *col;
int lightnum;
int texnum;
//
// calculate light table
// use different light tables for horizontal / vertical / diagonal
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
curline = ds->curline;
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = texturetranslation[curline->sidedef->midtexture];
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
if (lightnum < 0)
walllights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
walllights = scalelight[LIGHTLEVELS-1];
else
walllights = scalelight[lightnum];
maskedtexturecol = ds->maskedtexturecol;
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
mfloorclip = ds->sprbottomclip;
mceilingclip = ds->sprtopclip;
//
// find positioning
//
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
dc_texturemid = frontsector->floorheight > backsector->floorheight
? frontsector->floorheight : backsector->floorheight;
dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
}
else
{
dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
? frontsector->ceilingheight : backsector->ceilingheight;
dc_texturemid = dc_texturemid - viewz;
}
dc_texturemid += curline->sidedef->rowoffset;
if (fixedcolormap)
dc_colormap = fixedcolormap;
//
// draw the columns
//
for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
{
// calculate lighting
if (maskedtexturecol[dc_x] != MAXSHORT)
{
if (!fixedcolormap)
{
index = spryscale>>LIGHTSCALESHIFT;
if (index >= MAXLIGHTSCALE )
index = MAXLIGHTSCALE-1;
dc_colormap = walllights[index];
}
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
dc_iscale = 0xffffffffu / (unsigned)spryscale;
//
// draw the texture
//
col = (column_t *)(
(byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
R_DrawMaskedColumn (col, -1);
maskedtexturecol[dc_x] = MAXSHORT;
}
spryscale += rw_scalestep;
}
}
/*
================
=
= R_RenderSegLoop
=
= Draws zero, one, or two textures (and possibly a masked texture) for walls
= Can draw or mark the starting pixel of floor and ceiling textures
=
= CALLED: CORE LOOPING ROUTINE
================
*/
#define HEIGHTBITS 12
#define HEIGHTUNIT (1<<HEIGHTBITS)
void R_RenderSegLoop (void)
{
angle_t angle;
unsigned index;
int yl, yh, mid;
fixed_t texturecolumn;
int top, bottom;
// texturecolumn = 0; // shut up compiler warning
for ( ; rw_x < rw_stopx ; rw_x++)
{
//
// mark floor / ceiling areas
//
yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
if (yl < ceilingclip[rw_x]+1)
yl = ceilingclip[rw_x]+1; // no space above wall
if (markceiling)
{
top = ceilingclip[rw_x]+1;
bottom = yl-1;
if (bottom >= floorclip[rw_x])
bottom = floorclip[rw_x]-1;
if (top <= bottom)
{
ceilingplane->top[rw_x] = top;
ceilingplane->bottom[rw_x] = bottom;
}
}
yh = bottomfrac>>HEIGHTBITS;
if (yh >= floorclip[rw_x])
yh = floorclip[rw_x]-1;
if (markfloor)
{
top = yh+1;
bottom = floorclip[rw_x]-1;
if (top <= ceilingclip[rw_x])
top = ceilingclip[rw_x]+1;
if (top <= bottom)
{
floorplane->top[rw_x] = top;
floorplane->bottom[rw_x] = bottom;
}
}
//
// texturecolumn and lighting are independent of wall tiers
//
if (segtextured)
{
// calculate texture offset
angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
texturecolumn >>= FRACBITS;
// calculate lighting
index = rw_scale>>LIGHTSCALESHIFT;
if (index >= MAXLIGHTSCALE )
index = MAXLIGHTSCALE-1;
dc_colormap = walllights[index];
dc_x = rw_x;
dc_iscale = 0xffffffffu / (unsigned)rw_scale;
}
//
// draw the wall tiers
//
if (midtexture)
{ // single sided line
dc_yl = yl;
dc_yh = yh;
dc_texturemid = rw_midtexturemid;
dc_source = R_GetColumn(midtexture,texturecolumn);
colfunc ();
ceilingclip[rw_x] = viewheight;
floorclip[rw_x] = -1;
}
else
{ // two sided line
if (toptexture)
{ // top wall
mid = pixhigh>>HEIGHTBITS;
pixhigh += pixhighstep;
if (mid >= floorclip[rw_x])
mid = floorclip[rw_x]-1;
if (mid >= yl)
{
dc_yl = yl;
dc_yh = mid;
dc_texturemid = rw_toptexturemid;
dc_source = R_GetColumn(toptexture,texturecolumn);
colfunc ();
ceilingclip[rw_x] = mid;
}
else
ceilingclip[rw_x] = yl-1;
}
else
{ // no top wall
if (markceiling)
ceilingclip[rw_x] = yl-1;
}
if (bottomtexture)
{ // bottom wall
mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
pixlow += pixlowstep;
if (mid <= ceilingclip[rw_x])
mid = ceilingclip[rw_x]+1; // no space above wall
if (mid <= yh)
{
dc_yl = mid;
dc_yh = yh;
dc_texturemid = rw_bottomtexturemid;
dc_source = R_GetColumn(bottomtexture,
texturecolumn);
colfunc ();
floorclip[rw_x] = mid;
}
else
floorclip[rw_x] = yh+1;
}
else
{ // no bottom wall
if (markfloor)
floorclip[rw_x] = yh+1;
}
if (maskedtexture)
{ // save texturecol for backdrawing of masked mid texture
maskedtexturecol[rw_x] = texturecolumn;
}
}
rw_scale += rw_scalestep;
topfrac += topstep;
bottomfrac += bottomstep;
}
}
/*
=====================
=
= R_StoreWallRange
=
= A wall segment will be drawn between start and stop pixels (inclusive)
=
======================
*/
void R_StoreWallRange (int start, int stop)
{
fixed_t hyp;
fixed_t sineval;
angle_t distangle, offsetangle;
fixed_t vtop;
int lightnum;
if (ds_p == &drawsegs[MAXDRAWSEGS])
return; // don't overflow and crash
#ifdef RANGECHECK
if (start >=viewwidth || start > stop)
I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
#endif
#ifdef __NeXT__
RD_DrawLine (curline);
#endif
sidedef = curline->sidedef;
linedef = curline->linedef;
// mark the segment as visible for auto map
linedef->flags |= ML_MAPPED;
//
// calculate rw_distance for scale calculation
//
rw_normalangle = curline->angle + ANG90;
offsetangle = abs(rw_normalangle-rw_angle1);
if (offsetangle > ANG90)
offsetangle = ANG90;
distangle = ANG90 - offsetangle;
hyp = R_PointToDist (curline->v1->x, curline->v1->y);
sineval = finesine[distangle>>ANGLETOFINESHIFT];
rw_distance = FixedMul (hyp, sineval);
ds_p->x1 = rw_x = start;
ds_p->x2 = stop;
ds_p->curline = curline;
rw_stopx = stop+1;
//
// calculate scale at both ends and step
//
ds_p->scale1 = rw_scale =
R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
if (stop > start )
{
ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
ds_p->scalestep = rw_scalestep =
(ds_p->scale2 - rw_scale) / (stop-start);
}
else
{
//
// try to fix the stretched line bug
//
#if 0
if (rw_distance < FRACUNIT/2)
{
fixed_t trx,try;
fixed_t gxt,gyt;
trx = curline->v1->x - viewx;
try = curline->v1->y - viewy;
gxt = FixedMul(trx,viewcos);
gyt = -FixedMul(try,viewsin);
ds_p->scale1 = FixedDiv(projection, gxt-gyt);
}
#endif
ds_p->scale2 = ds_p->scale1;
}
//
// calculate texture boundaries and decide if floor / ceiling marks
// are needed
//
worldtop = frontsector->ceilingheight - viewz;
worldbottom = frontsector->floorheight - viewz;
midtexture = toptexture = bottomtexture = maskedtexture = 0;
ds_p->maskedtexturecol = NULL;
if (!backsector)
{
//
// single sided line
//
midtexture = texturetranslation[sidedef->midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
if (linedef->flags & ML_DONTPEGBOTTOM)
{
vtop = frontsector->floorheight +
textureheight[sidedef->midtexture];
rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
}
else
rw_midtexturemid = worldtop; // top of texture at top
rw_midtexturemid += sidedef->rowoffset;
ds_p->silhouette = SIL_BOTH;
ds_p->sprtopclip = screenheightarray;
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = MAXINT;
ds_p->tsilheight = MININT;
}
else
{
//
// two sided line
//
ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
ds_p->silhouette = 0;
if (frontsector->floorheight > backsector->floorheight)
{
ds_p->silhouette = SIL_BOTTOM;
ds_p->bsilheight = frontsector->floorheight;
}
else if (backsector->floorheight > viewz)
{
ds_p->silhouette = SIL_BOTTOM;
ds_p->bsilheight = MAXINT;
// ds_p->sprbottomclip = negonearray;
}
if (frontsector->ceilingheight < backsector->ceilingheight)
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = frontsector->ceilingheight;
}
else if (backsector->ceilingheight < viewz)
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = MININT;
// ds_p->sprtopclip = screenheightarray;
}
if (backsector->ceilingheight <= frontsector->floorheight)
{
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = MAXINT;
ds_p->silhouette |= SIL_BOTTOM;
}
if (backsector->floorheight >= frontsector->ceilingheight)
{
ds_p->sprtopclip = screenheightarray;
ds_p->tsilheight = MININT;
ds_p->silhouette |= SIL_TOP;
}
worldhigh = backsector->ceilingheight - viewz;
worldlow = backsector->floorheight - viewz;
// hack to allow height changes in outdoor areas
if (frontsector->ceilingpic == skyflatnum
&& backsector->ceilingpic == skyflatnum)
worldtop = worldhigh;
if (worldlow != worldbottom
|| backsector->floorpic != frontsector->floorpic
|| backsector->lightlevel != frontsector->lightlevel)
markfloor = true;
else
markfloor = false; // same plane on both sides
if (worldhigh != worldtop
|| backsector->ceilingpic != frontsector->ceilingpic
|| backsector->lightlevel != frontsector->lightlevel)
markceiling = true;
else
markceiling = false; // same plane on both sides
if (backsector->ceilingheight <= frontsector->floorheight
|| backsector->floorheight >= frontsector->ceilingheight)
markceiling = markfloor = true; // closed door
if (worldhigh < worldtop)
{ // top texture
toptexture = texturetranslation[sidedef->toptexture];
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = worldtop; // top of texture at top
else
{
vtop = backsector->ceilingheight +
textureheight[sidedef->toptexture];
rw_toptexturemid = vtop - viewz; // bottom of texture
}
}
if (worldlow > worldbottom)
{ // bottom texture
bottomtexture = texturetranslation[sidedef->bottomtexture];
if (linedef->flags & ML_DONTPEGBOTTOM )
{ // bottom of texture at bottom
rw_bottomtexturemid = worldtop;// top of texture at top
}
else // top of texture at top
rw_bottomtexturemid = worldlow;
}
rw_toptexturemid += sidedef->rowoffset;
rw_bottomtexturemid += sidedef->rowoffset;
//
// allocate space for masked texture tables
//
if (sidedef->midtexture)
{ // masked midtexture
maskedtexture = true;
ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
lastopening += rw_stopx - rw_x;
}
}
//
// calculate rw_offset (only needed for textured lines)
//
segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
if (segtextured)
{
offsetangle = rw_normalangle-rw_angle1;
if (offsetangle > ANG180)
offsetangle = -offsetangle;
if (offsetangle > ANG90)
offsetangle = ANG90;
sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
rw_offset = FixedMul (hyp, sineval);
if (rw_normalangle-rw_angle1 < ANG180)
rw_offset = -rw_offset;
rw_offset += sidedef->textureoffset + curline->offset;
rw_centerangle = ANG90 + viewangle - rw_normalangle;
//
// calculate light table
// use different light tables for horizontal / vertical / diagonal
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
if (!fixedcolormap)
{
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
if (curline->v1->y == curline->v2->y)
lightnum--;
else if (curline->v1->x == curline->v2->x)
lightnum++;
if (lightnum < 0)
walllights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
walllights = scalelight[LIGHTLEVELS-1];
else
walllights = scalelight[lightnum];
}
}
//
// if a floor / ceiling plane is on the wrong side of the view plane
// it is definately invisible and doesn't need to be marked
//
if (frontsector->floorheight >= viewz)
markfloor = false; // above view plane
if (frontsector->ceilingheight <= viewz
&& frontsector->ceilingpic != skyflatnum)
markceiling = false; // below view plane
//
// calculate incremental stepping values for texture edges
//
worldtop >>= 4;
worldbottom >>= 4;
topstep = -FixedMul (rw_scalestep, worldtop);
topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
bottomstep = -FixedMul (rw_scalestep,worldbottom);
bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
if (backsector)
{
worldhigh >>= 4;
worldlow >>= 4;
if (worldhigh < worldtop)
{
pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
pixhighstep = -FixedMul (rw_scalestep,worldhigh);
}
if (worldlow > worldbottom)
{
pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
pixlowstep = -FixedMul (rw_scalestep,worldlow);
}
}
//
// render it
//
if (markceiling)
ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
if (markfloor)
floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
R_RenderSegLoop ();
//
// save sprite clipping info
//
if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
{
memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
ds_p->sprtopclip = lastopening - start;
lastopening += rw_stopx - start;
}
if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip)
{
memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
ds_p->sprbottomclip = lastopening - start;
lastopening += rw_stopx - start;
}
if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = MININT;
}
if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
{
ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = MAXINT;
}
ds_p++;
}

992
Heretic Source/R_THINGS.C Normal file
View File

@ -0,0 +1,992 @@
// R_things.c
#include <stdio.h>
#include <stdlib.h>
#include "DoomDef.h"
#include "R_local.h"
void R_DrawColumn (void);
void R_DrawFuzzColumn (void);
typedef struct
{
int x1, x2;
int column;
int topclip;
int bottomclip;
} maskdraw_t;
/*
Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis.
This is not the same as the angle, which increases counter clockwise
(protractor). There was a lot of stuff grabbed wrong, so I changed it...
*/
fixed_t pspritescale, pspriteiscale;
lighttable_t **spritelights;
// constant arrays used for psprite clipping and initializing clipping
short negonearray[SCREENWIDTH];
short screenheightarray[SCREENWIDTH];
/*
===============================================================================
INITIALIZATION FUNCTIONS
===============================================================================
*/
// variables used to look up and range check thing_t sprites patches
spritedef_t *sprites;
int numsprites;
spriteframe_t sprtemp[26];
int maxframe;
char *spritename;
/*
=================
=
= R_InstallSpriteLump
=
= Local function for R_InitSprites
=================
*/
void R_InstallSpriteLump (int lump, unsigned frame, unsigned rotation, boolean flipped)
{
int r;
if (frame >= 26 || rotation > 8)
I_Error ("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
if ((int)frame > maxframe)
maxframe = frame;
if (rotation == 0)
{
// the lump should be used for all rotations
if (sprtemp[frame].rotate == false)
I_Error ("R_InitSprites: Sprite %s frame %c has multip rot=0 lump"
, spritename, 'A'+frame);
if (sprtemp[frame].rotate == true)
I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump"
, spritename, 'A'+frame);
sprtemp[frame].rotate = false;
for (r=0 ; r<8 ; r++)
{
sprtemp[frame].lump[r] = lump - firstspritelump;
sprtemp[frame].flip[r] = (byte)flipped;
}
return;
}
// the lump is only used for one rotation
if (sprtemp[frame].rotate == false)
I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump"
, spritename, 'A'+frame);
sprtemp[frame].rotate = true;
rotation--; // make 0 based
if (sprtemp[frame].lump[rotation] != -1)
I_Error ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it"
,spritename, 'A'+frame, '1'+rotation);
sprtemp[frame].lump[rotation] = lump - firstspritelump;
sprtemp[frame].flip[rotation] = (byte)flipped;
}
/*
=================
=
= R_InitSpriteDefs
=
= Pass a null terminated list of sprite names (4 chars exactly) to be used
= Builds the sprite rotation matrixes to account for horizontally flipped
= sprites. Will report an error if the lumps are inconsistant
= Only called at startup
=
= Sprite lump names are 4 characters for the actor, a letter for the frame,
= and a number for the rotation, A sprite that is flippable will have an
= additional letter/number appended. The rotation character can be 0 to
= signify no rotations
=================
*/
void R_InitSpriteDefs (char **namelist)
{
char **check;
int i, l, intname, frame, rotation;
int start, end;
// count the number of sprite names
check = namelist;
while (*check != NULL)
check++;
numsprites = check-namelist;
if (!numsprites)
return;
sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
start = firstspritelump-1;
end = lastspritelump+1;
// scan all the lump names for each of the names, noting the highest
// frame letter
// Just compare 4 characters as ints
for (i=0 ; i<numsprites ; i++)
{
spritename = namelist[i];
memset (sprtemp,-1, sizeof(sprtemp));
maxframe = -1;
intname = *(int *)namelist[i];
//
// scan the lumps, filling in the frames for whatever is found
//
for (l=start+1 ; l<end ; l++)
if (*(int *)lumpinfo[l].name == intname)
{
frame = lumpinfo[l].name[4] - 'A';
rotation = lumpinfo[l].name[5] - '0';
R_InstallSpriteLump (l, frame, rotation, false);
if (lumpinfo[l].name[6])
{
frame = lumpinfo[l].name[6] - 'A';
rotation = lumpinfo[l].name[7] - '0';
R_InstallSpriteLump (l, frame, rotation, true);
}
}
//
// check the frames that were found for completeness
//
if (maxframe == -1)
{
//continue;
sprites[i].numframes = 0;
if (shareware)
continue;
I_Error ("R_InitSprites: No lumps found for sprite %s"
,namelist[i]);
}
maxframe++;
for (frame = 0 ; frame < maxframe ; frame++)
{
switch ((int)sprtemp[frame].rotate)
{
case -1: // no rotations were found for that frame at all
I_Error ("R_InitSprites: No patches found for %s frame %c"
, namelist[i], frame+'A');
case 0: // only the first rotation is needed
break;
case 1: // must have all 8 frames
for (rotation=0 ; rotation<8 ; rotation++)
if (sprtemp[frame].lump[rotation] == -1)
I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations"
, namelist[i], frame+'A');
}
}
//
// allocate space for the frames present and copy sprtemp to it
//
sprites[i].numframes = maxframe;
sprites[i].spriteframes =
Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
}
}
/*
===============================================================================
GAME FUNCTIONS
===============================================================================
*/
vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
int newvissprite;
/*
===================
=
= R_InitSprites
=
= Called at program start
===================
*/
void R_InitSprites (char **namelist)
{
int i;
for (i=0 ; i<SCREENWIDTH ; i++)
{
negonearray[i] = -1;
}
R_InitSpriteDefs (namelist);
}
/*
===================
=
= R_ClearSprites
=
= Called at frame start
===================
*/
void R_ClearSprites (void)
{
vissprite_p = vissprites;
}
/*
===================
=
= R_NewVisSprite
=
===================
*/
vissprite_t overflowsprite;
vissprite_t *R_NewVisSprite (void)
{
if (vissprite_p == &vissprites[MAXVISSPRITES])
return &overflowsprite;
vissprite_p++;
return vissprite_p-1;
}
/*
================
=
= R_DrawMaskedColumn
=
= Used for sprites and masked mid textures
================
*/
short *mfloorclip;
short *mceilingclip;
fixed_t spryscale;
fixed_t sprtopscreen;
fixed_t sprbotscreen;
void R_DrawMaskedColumn (column_t *column, signed int baseclip)
{
int topscreen, bottomscreen;
fixed_t basetexturemid;
basetexturemid = dc_texturemid;
for ( ; column->topdelta != 0xff ; )
{
// calculate unclipped screen coordinates for post
topscreen = sprtopscreen + spryscale*column->topdelta;
bottomscreen = topscreen + spryscale*column->length;
dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
if (dc_yh >= mfloorclip[dc_x])
dc_yh = mfloorclip[dc_x]-1;
if (dc_yl <= mceilingclip[dc_x])
dc_yl = mceilingclip[dc_x]+1;
if(dc_yh >= baseclip && baseclip != -1)
dc_yh = baseclip;
if (dc_yl <= dc_yh)
{
dc_source = (byte *)column + 3;
dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
// dc_source = (byte *)column + 3 - column->topdelta;
colfunc (); // either R_DrawColumn or R_DrawFuzzColumn
}
column = (column_t *)( (byte *)column + column->length + 4);
}
dc_texturemid = basetexturemid;
}
/*
================
=
= R_DrawVisSprite
=
= mfloorclip and mceilingclip should also be set
================
*/
void R_DrawVisSprite (vissprite_t *vis, int x1, int x2)
{
column_t *column;
int texturecolumn;
fixed_t frac;
patch_t *patch;
fixed_t baseclip;
patch = W_CacheLumpNum(vis->patch+firstspritelump, PU_CACHE);
dc_colormap = vis->colormap;
// if(!dc_colormap)
// colfunc = fuzzcolfunc; // NULL colormap = shadow draw
if(vis->mobjflags&MF_SHADOW)
{
if(vis->mobjflags&MF_TRANSLATION)
{
colfunc = R_DrawTranslatedFuzzColumn;
dc_translation = translationtables - 256 +
((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8));
}
else
{ // Draw using shadow column function
colfunc = fuzzcolfunc;
}
}
else if(vis->mobjflags&MF_TRANSLATION)
{
// Draw using translated column function
colfunc = R_DrawTranslatedColumn;
dc_translation = translationtables - 256 +
( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
}
dc_iscale = abs(vis->xiscale)>>detailshift;
dc_texturemid = vis->texturemid;
frac = vis->startfrac;
spryscale = vis->scale;
sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
// check to see if weapon is a vissprite
if(vis->psprite)
{
dc_texturemid += FixedMul(((centery-viewheight/2)<<FRACBITS),
vis->xiscale);
sprtopscreen += (viewheight/2-centery)<<FRACBITS;
}
if(vis->footclip && !vis->psprite)
{
sprbotscreen = sprtopscreen+FixedMul(patch->height<<FRACBITS,
spryscale);
baseclip = (sprbotscreen-FixedMul(vis->footclip<<FRACBITS,
spryscale))>>FRACBITS;
}
else
{
baseclip = -1;
}
for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale)
{
texturecolumn = frac>>FRACBITS;
#ifdef RANGECHECK
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
I_Error ("R_DrawSpriteRange: bad texturecolumn");
#endif
column = (column_t *) ((byte *)patch +
LONG(patch->columnofs[texturecolumn]));
R_DrawMaskedColumn (column, baseclip);
}
colfunc = basecolfunc;
}
/*
===================
=
= R_ProjectSprite
=
= Generates a vissprite for a thing if it might be visible
=
===================
*/
void R_ProjectSprite (mobj_t *thing)
{
fixed_t trx,try;
fixed_t gxt,gyt;
fixed_t tx,tz;
fixed_t xscale;
int x1, x2;
spritedef_t *sprdef;
spriteframe_t *sprframe;
int lump;
unsigned rot;
boolean flip;
int index;
vissprite_t *vis;
angle_t ang;
fixed_t iscale;
if(thing->flags2&MF2_DONTDRAW)
{ // Never make a vissprite when MF2_DONTDRAW is flagged.
return;
}
//
// transform the origin point
//
trx = thing->x - viewx;
try = thing->y - viewy;
gxt = FixedMul(trx,viewcos);
gyt = -FixedMul(try,viewsin);
tz = gxt-gyt;
if (tz < MINZ)
return; // thing is behind view plane
xscale = FixedDiv(projection, tz);
gxt = -FixedMul(trx,viewsin);
gyt = FixedMul(try,viewcos);
tx = -(gyt+gxt);
if (abs(tx)>(tz<<2))
return; // too far off the side
//
// decide which patch to use for sprite reletive to player
//
#ifdef RANGECHECK
if ((unsigned)thing->sprite >= numsprites)
I_Error ("R_ProjectSprite: invalid sprite number %i ",thing->sprite);
#endif
sprdef = &sprites[thing->sprite];
#ifdef RANGECHECK
if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes )
I_Error ("R_ProjectSprite: invalid sprite frame %i : %i "
,thing->sprite, thing->frame);
#endif
sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
if (sprframe->rotate)
{ // choose a different rotation based on player view
ang = R_PointToAngle (thing->x, thing->y);
rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
lump = sprframe->lump[rot];
flip = (boolean)sprframe->flip[rot];
}
else
{ // use single rotation for all views
lump = sprframe->lump[0];
flip = (boolean)sprframe->flip[0];
}
//
// calculate edges of the shape
//
tx -= spriteoffset[lump];
x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
if (x1 > viewwidth)
return; // off the right side
tx += spritewidth[lump];
x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
if (x2 < 0)
return; // off the left side
//
// store information in a vissprite
//
vis = R_NewVisSprite ();
vis->mobjflags = thing->flags;
vis->psprite = false;
vis->scale = xscale<<detailshift;
vis->gx = thing->x;
vis->gy = thing->y;
vis->gz = thing->z;
vis->gzt = thing->z + spritetopoffset[lump];
// foot clipping
if(thing->flags2&MF2_FEETARECLIPPED
&& thing->z <= thing->subsector->sector->floorheight)
{
vis->footclip = 10;
}
else vis->footclip = 0;
vis->texturemid = vis->gzt - viewz - (vis->footclip<<FRACBITS);
vis->x1 = x1 < 0 ? 0 : x1;
vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
iscale = FixedDiv (FRACUNIT, xscale);
if (flip)
{
vis->startfrac = spritewidth[lump]-1;
vis->xiscale = -iscale;
}
else
{
vis->startfrac = 0;
vis->xiscale = iscale;
}
if (vis->x1 > x1)
vis->startfrac += vis->xiscale*(vis->x1-x1);
vis->patch = lump;
//
// get light level
//
// if (thing->flags & MF_SHADOW)
// vis->colormap = NULL; // shadow draw
// else ...
if (fixedcolormap)
vis->colormap = fixedcolormap; // fixed map
else if (thing->frame & FF_FULLBRIGHT)
vis->colormap = colormaps; // full bright
else
{ // diminished light
index = xscale>>(LIGHTSCALESHIFT-detailshift);
if (index >= MAXLIGHTSCALE)
index = MAXLIGHTSCALE-1;
vis->colormap = spritelights[index];
}
}
/*
========================
=
= R_AddSprites
=
========================
*/
void R_AddSprites (sector_t *sec)
{
mobj_t *thing;
int lightnum;
if (sec->validcount == validcount)
return; // already added
sec->validcount = validcount;
lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
if (lightnum < 0)
spritelights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
spritelights = scalelight[LIGHTLEVELS-1];
else
spritelights = scalelight[lightnum];
for (thing = sec->thinglist ; thing ; thing = thing->snext)
R_ProjectSprite (thing);
}
/*
========================
=
= R_DrawPSprite
=
========================
*/
int PSpriteSY[NUMWEAPONS] =
{
0, // staff
5*FRACUNIT, // goldwand
15*FRACUNIT, // crossbow
15*FRACUNIT, // blaster
15*FRACUNIT, // skullrod
15*FRACUNIT, // phoenix rod
15*FRACUNIT, // mace
15*FRACUNIT, // gauntlets
15*FRACUNIT // beak
};
void R_DrawPSprite (pspdef_t *psp)
{
fixed_t tx;
int x1, x2;
spritedef_t *sprdef;
spriteframe_t *sprframe;
int lump;
boolean flip;
vissprite_t *vis, avis;
int tempangle;
//
// decide which patch to use
//
#ifdef RANGECHECK
if ( (unsigned)psp->state->sprite >= numsprites)
I_Error ("R_ProjectSprite: invalid sprite number %i "
, psp->state->sprite);
#endif
sprdef = &sprites[psp->state->sprite];
#ifdef RANGECHECK
if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
I_Error ("R_ProjectSprite: invalid sprite frame %i : %i "
, psp->state->sprite, psp->state->frame);
#endif
sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
lump = sprframe->lump[0];
flip = (boolean)sprframe->flip[0];
//
// calculate edges of the shape
//
tx = psp->sx-160*FRACUNIT;
tx -= spriteoffset[lump];
if(viewangleoffset)
{
tempangle = ((centerxfrac/1024)*(viewangleoffset>>ANGLETOFINESHIFT));
}
else
{
tempangle = 0;
}
x1 = (centerxfrac + FixedMul (tx,pspritescale)+tempangle ) >>FRACBITS;
if (x1 > viewwidth)
return; // off the right side
tx += spritewidth[lump];
x2 = ((centerxfrac + FixedMul (tx, pspritescale)+tempangle ) >>FRACBITS) - 1;
if (x2 < 0)
return; // off the left side
//
// store information in a vissprite
//
vis = &avis;
vis->mobjflags = 0;
vis->psprite = true;
vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]);
if(viewheight == SCREENHEIGHT)
{
vis->texturemid -= PSpriteSY[players[consoleplayer].readyweapon];
}
vis->x1 = x1 < 0 ? 0 : x1;
vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
vis->scale = pspritescale<<detailshift;
if (flip)
{
vis->xiscale = -pspriteiscale;
vis->startfrac = spritewidth[lump]-1;
}
else
{
vis->xiscale = pspriteiscale;
vis->startfrac = 0;
}
if (vis->x1 > x1)
vis->startfrac += vis->xiscale*(vis->x1-x1);
vis->patch = lump;
if(viewplayer->powers[pw_invisibility] > 4*32 ||
viewplayer->powers[pw_invisibility] & 8)
{
// Invisibility
vis->colormap = spritelights[MAXLIGHTSCALE-1];
vis->mobjflags |= MF_SHADOW;
}
else if(fixedcolormap)
{
// Fixed color
vis->colormap = fixedcolormap;
}
else if(psp->state->frame & FF_FULLBRIGHT)
{
// Full bright
vis->colormap = colormaps;
}
else
{
// local light
vis->colormap = spritelights[MAXLIGHTSCALE-1];
}
R_DrawVisSprite(vis, vis->x1, vis->x2);
}
/*
========================
=
= R_DrawPlayerSprites
=
========================
*/
void R_DrawPlayerSprites (void)
{
int i, lightnum;
pspdef_t *psp;
//
// get light level
//
lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT)
+extralight;
if (lightnum < 0)
spritelights = scalelight[0];
else if (lightnum >= LIGHTLEVELS)
spritelights = scalelight[LIGHTLEVELS-1];
else
spritelights = scalelight[lightnum];
//
// clip to screen bounds
//
mfloorclip = screenheightarray;
mceilingclip = negonearray;
//
// add all active psprites
//
for (i=0, psp=viewplayer->psprites ; i<NUMPSPRITES ; i++,psp++)
if (psp->state)
R_DrawPSprite (psp);
}
/*
========================
=
= R_SortVisSprites
=
========================
*/
vissprite_t vsprsortedhead;
void R_SortVisSprites (void)
{
int i, count;
vissprite_t *ds, *best;
vissprite_t unsorted;
fixed_t bestscale;
count = vissprite_p - vissprites;
unsorted.next = unsorted.prev = &unsorted;
if (!count)
return;
for (ds=vissprites ; ds<vissprite_p ; ds++)
{
ds->next = ds+1;
ds->prev = ds-1;
}
vissprites[0].prev = &unsorted;
unsorted.next = &vissprites[0];
(vissprite_p-1)->next = &unsorted;
unsorted.prev = vissprite_p-1;
//
// pull the vissprites out by scale
//
best = 0; // shut up the compiler warning
vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
for (i=0 ; i<count ; i++)
{
bestscale = MAXINT;
for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
{
if (ds->scale < bestscale)
{
bestscale = ds->scale;
best = ds;
}
}
best->next->prev = best->prev;
best->prev->next = best->next;
best->next = &vsprsortedhead;
best->prev = vsprsortedhead.prev;
vsprsortedhead.prev->next = best;
vsprsortedhead.prev = best;
}
}
/*
========================
=
= R_DrawSprite
=
========================
*/
void R_DrawSprite (vissprite_t *spr)
{
drawseg_t *ds;
short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
int x, r1, r2;
fixed_t scale, lowscale;
int silhouette;
for (x = spr->x1 ; x<=spr->x2 ; x++)
clipbot[x] = cliptop[x] = -2;
//
// scan drawsegs from end to start for obscuring segs
// the first drawseg that has a greater scale is the clip seg
//
for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
{
//
// determine if the drawseg obscures the sprite
//
if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
(!ds->silhouette && !ds->maskedtexturecol) )
continue; // doesn't cover sprite
r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
if (ds->scale1 > ds->scale2)
{
lowscale = ds->scale2;
scale = ds->scale1;
}
else
{
lowscale = ds->scale1;
scale = ds->scale2;
}
if (scale < spr->scale || ( lowscale < spr->scale
&& !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) )
{
if (ds->maskedtexturecol) // masked mid texture
R_RenderMaskedSegRange (ds, r1, r2);
continue; // seg is behind sprite
}
//
// clip this piece of the sprite
//
silhouette = ds->silhouette;
if (spr->gz >= ds->bsilheight)
silhouette &= ~SIL_BOTTOM;
if (spr->gzt <= ds->tsilheight)
silhouette &= ~SIL_TOP;
if (silhouette == 1)
{ // bottom sil
for (x=r1 ; x<=r2 ; x++)
if (clipbot[x] == -2)
clipbot[x] = ds->sprbottomclip[x];
}
else if (silhouette == 2)
{ // top sil
for (x=r1 ; x<=r2 ; x++)
if (cliptop[x] == -2)
cliptop[x] = ds->sprtopclip[x];
}
else if (silhouette == 3)
{ // both
for (x=r1 ; x<=r2 ; x++)
{
if (clipbot[x] == -2)
clipbot[x] = ds->sprbottomclip[x];
if (cliptop[x] == -2)
cliptop[x] = ds->sprtopclip[x];
}
}
}
//
// all clipping has been performed, so draw the sprite
//
// check for unclipped columns
for (x = spr->x1 ; x<=spr->x2 ; x++)
{
if (clipbot[x] == -2)
clipbot[x] = viewheight;
if (cliptop[x] == -2)
cliptop[x] = -1;
}
mfloorclip = clipbot;
mceilingclip = cliptop;
R_DrawVisSprite (spr, spr->x1, spr->x2);
}
/*
========================
=
= R_DrawMasked
=
========================
*/
void R_DrawMasked (void)
{
vissprite_t *spr;
drawseg_t *ds;
R_SortVisSprites ();
if (vissprite_p > vissprites)
{
// draw all vissprites back to front
for (spr = vsprsortedhead.next ; spr != &vsprsortedhead
; spr=spr->next)
R_DrawSprite (spr);
}
//
// render any remaining masked mid textures
//
for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
if (ds->maskedtexturecol)
R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
//
// draw the psprites on top of everything
//
// Added for the sideviewing with an external device
if (viewangleoffset <= 1024<<ANGLETOFINESHIFT || viewangleoffset >=
-1024<<ANGLETOFINESHIFT)
{ // don't draw on side views
R_DrawPlayerSprites ();
}
// if (!viewangleoffset) // don't draw on side views
// R_DrawPlayerSprites ();
}

1456
Heretic Source/SB_BAR.C Normal file

File diff suppressed because it is too large Load Diff

220
Heretic Source/SOUNDS.C Normal file
View File

@ -0,0 +1,220 @@
// sounds.c
#include "DoomDef.h"
#include "sounds.h"
// Music info
musicinfo_t S_music[] =
{
{ "MUS_E1M1", 0 }, // 1-1
{ "MUS_E1M2", 0 },
{ "MUS_E1M3", 0 },
{ "MUS_E1M4", 0 },
{ "MUS_E1M5", 0 },
{ "MUS_E1M6", 0 },
{ "MUS_E1M7", 0 },
{ "MUS_E1M8", 0 },
{ "MUS_E1M9", 0 },
{ "MUS_E2M1", 0 }, // 2-1
{ "MUS_E2M2", 0 },
{ "MUS_E2M3", 0 },
{ "MUS_E2M4", 0 },
{ "MUS_E1M4", 0 },
{ "MUS_E2M6", 0 },
{ "MUS_E2M7", 0 },
{ "MUS_E2M8", 0 },
{ "MUS_E2M9", 0 },
{ "MUS_E1M1", 0 }, // 3-1
{ "MUS_E3M2", 0 },
{ "MUS_E3M3", 0 },
{ "MUS_E1M6", 0 },
{ "MUS_E1M3", 0 },
{ "MUS_E1M2", 0 },
{ "MUS_E1M5", 0 },
{ "MUS_E1M9", 0 },
{ "MUS_E2M6", 0 },
{ "MUS_E1M6", 0 }, // 4-1
{ "MUS_E1M2", 0 },
{ "MUS_E1M3", 0 },
{ "MUS_E1M4", 0 },
{ "MUS_E1M5", 0 },
{ "MUS_E1M1", 0 },
{ "MUS_E1M7", 0 },
{ "MUS_E1M8", 0 },
{ "MUS_E1M9", 0 },
{ "MUS_E2M1", 0 }, // 5-1
{ "MUS_E2M2", 0 },
{ "MUS_E2M3", 0 },
{ "MUS_E2M4", 0 },
{ "MUS_E1M4", 0 },
{ "MUS_E2M6", 0 },
{ "MUS_E2M7", 0 },
{ "MUS_E2M8", 0 },
{ "MUS_E2M9", 0 },
{ "MUS_E3M2", 0 }, // 6-1
{ "MUS_E3M3", 0 }, // 6-2
{ "MUS_E1M6", 0 }, // 6-3
{ "MUS_TITL", 0 },
{ "MUS_INTR", 0 },
{ "MUS_CPTD", 0 }
};
// Sound info
sfxinfo_t S_sfx[] =
{
{ {0,0,0,0,0,0,0,0}, NULL, 0, -1, NULL, 0, 0 },
{ "gldhit", NULL, 32, -1, NULL, 0, 2 },
{ "gntful", NULL, 32, -1, NULL, 0, -1 },
{ "gnthit", NULL, 32, -1, NULL, 0, -1 },
{ "gntpow", NULL, 32, -1, NULL, 0, -1 },
{ "gntact", NULL, 32, -1, NULL, 0, -1 },
{ "gntuse", NULL, 32, -1, NULL, 0, -1 },
{ "phosht", NULL, 32, -1, NULL, 0, 2 },
{ "phohit", NULL, 32, -1, NULL, 0, -1 },
{ "-phopow", &S_sfx[sfx_hedat1], 32, -1, NULL, 0, 1 },
{ "lobsht", NULL, 20, -1, NULL, 0, 2 },
{ "lobhit", NULL, 20, -1, NULL, 0, 2 },
{ "lobpow", NULL, 20, -1, NULL, 0, 2 },
{ "hrnsht", NULL, 32, -1, NULL, 0, 2 },
{ "hrnhit", NULL, 32, -1, NULL, 0, 2 },
{ "hrnpow", NULL, 32, -1, NULL, 0, 2 },
{ "ramphit", NULL, 32, -1, NULL, 0, 2 },
{ "ramrain", NULL, 10, -1, NULL, 0, 2 },
{ "bowsht", NULL, 32, -1, NULL, 0, 2 },
{ "stfhit", NULL, 32, -1, NULL, 0, 2 },
{ "stfpow", NULL, 32, -1, NULL, 0, 2 },
{ "stfcrk", NULL, 32, -1, NULL, 0, 2 },
{ "impsit", NULL, 32, -1, NULL, 0, 2 },
{ "impat1", NULL, 32, -1, NULL, 0, 2 },
{ "impat2", NULL, 32, -1, NULL, 0, 2 },
{ "impdth", NULL, 80, -1, NULL, 0, 2 },
{ "-impact", &S_sfx[sfx_impsit], 20, -1, NULL, 0, 2 },
{ "imppai", NULL, 32, -1, NULL, 0, 2 },
{ "mumsit", NULL, 32, -1, NULL, 0, 2 },
{ "mumat1", NULL, 32, -1, NULL, 0, 2 },
{ "mumat2", NULL, 32, -1, NULL, 0, 2 },
{ "mumdth", NULL, 80, -1, NULL, 0, 2 },
{ "-mumact", &S_sfx[sfx_mumsit], 20, -1, NULL, 0, 2 },
{ "mumpai", NULL, 32, -1, NULL, 0, 2 },
{ "mumhed", NULL, 32, -1, NULL, 0, 2 },
{ "bstsit", NULL, 32, -1, NULL, 0, 2 },
{ "bstatk", NULL, 32, -1, NULL, 0, 2 },
{ "bstdth", NULL, 80, -1, NULL, 0, 2 },
{ "bstact", NULL, 20, -1, NULL, 0, 2 },
{ "bstpai", NULL, 32, -1, NULL, 0, 2 },
{ "clksit", NULL, 32, -1, NULL, 0, 2 },
{ "clkatk", NULL, 32, -1, NULL, 0, 2 },
{ "clkdth", NULL, 80, -1, NULL, 0, 2 },
{ "clkact", NULL, 20, -1, NULL, 0, 2 },
{ "clkpai", NULL, 32, -1, NULL, 0, 2 },
{ "snksit", NULL, 32, -1, NULL, 0, 2 },
{ "snkatk", NULL, 32, -1, NULL, 0, 2 },
{ "snkdth", NULL, 80, -1, NULL, 0, 2 },
{ "snkact", NULL, 20, -1, NULL, 0, 2 },
{ "snkpai", NULL, 32, -1, NULL, 0, 2 },
{ "kgtsit", NULL, 32, -1, NULL, 0, 2 },
{ "kgtatk", NULL, 32, -1, NULL, 0, 2 },
{ "kgtat2", NULL, 32, -1, NULL, 0, 2 },
{ "kgtdth", NULL, 80, -1, NULL, 0, 2 },
{ "-kgtact", &S_sfx[sfx_kgtsit], 20, -1, NULL, 0, 2 },
{ "kgtpai", NULL, 32, -1, NULL, 0, 2 },
{ "wizsit", NULL, 32, -1, NULL, 0, 2 },
{ "wizatk", NULL, 32, -1, NULL, 0, 2 },
{ "wizdth", NULL, 80, -1, NULL, 0, 2 },
{ "wizact", NULL, 20, -1, NULL, 0, 2 },
{ "wizpai", NULL, 32, -1, NULL, 0, 2 },
{ "minsit", NULL, 32, -1, NULL, 0, 2 },
{ "minat1", NULL, 32, -1, NULL, 0, 2 },
{ "minat2", NULL, 32, -1, NULL, 0, 2 },
{ "minat3", NULL, 32, -1, NULL, 0, 2 },
{ "mindth", NULL, 80, -1, NULL, 0, 2 },
{ "minact", NULL, 20, -1, NULL, 0, 2 },
{ "minpai", NULL, 32, -1, NULL, 0, 2 },
{ "hedsit", NULL, 32, -1, NULL, 0, 2 },
{ "hedat1", NULL, 32, -1, NULL, 0, 2 },
{ "hedat2", NULL, 32, -1, NULL, 0, 2 },
{ "hedat3", NULL, 32, -1, NULL, 0, 2 },
{ "heddth", NULL, 80, -1, NULL, 0, 2 },
{ "hedact", NULL, 20, -1, NULL, 0, 2 },
{ "hedpai", NULL, 32, -1, NULL, 0, 2 },
{ "sorzap", NULL, 32, -1, NULL, 0, 2 },
{ "sorrise", NULL, 32, -1, NULL, 0, 2 },
{ "sorsit", NULL, 200, -1, NULL, 0, 2 },
{ "soratk", NULL, 32, -1, NULL, 0, 2 },
{ "soract", NULL, 200, -1, NULL, 0, 2 },
{ "sorpai", NULL, 200, -1, NULL, 0, 2 },
{ "sordsph", NULL, 200, -1, NULL, 0, 2 },
{ "sordexp", NULL, 200, -1, NULL, 0, 2 },
{ "sordbon", NULL, 200, -1, NULL, 0, 2 },
{ "-sbtsit", &S_sfx[sfx_bstsit], 32, -1, NULL, 0, 2 },
{ "-sbtatk", &S_sfx[sfx_bstatk], 32, -1, NULL, 0, 2 },
{ "sbtdth", NULL, 80, -1, NULL, 0, 2 },
{ "sbtact", NULL, 20, -1, NULL, 0, 2 },
{ "sbtpai", NULL, 32, -1, NULL, 0, 2 },
{ "plroof", NULL, 32, -1, NULL, 0, 2 },
{ "plrpai", NULL, 32, -1, NULL, 0, 2 },
{ "plrdth", NULL, 80, -1, NULL, 0, 2 },
{ "gibdth", NULL, 100, -1, NULL, 0, 2 },
{ "plrwdth", NULL, 80, -1, NULL, 0, 2 },
{ "plrcdth", NULL, 100, -1, NULL, 0, 2 },
{ "itemup", NULL, 32, -1, NULL, 0, 2 },
{ "wpnup", NULL, 32, -1, NULL, 0, 2 },
{ "telept", NULL, 50, -1, NULL, 0, 2 },
{ "doropn", NULL, 40, -1, NULL, 0, 2 },
{ "dorcls", NULL, 40, -1, NULL, 0, 2 },
{ "dormov", NULL, 40, -1, NULL, 0, 2 },
{ "artiup", NULL, 32, -1, NULL, 0, 2 },
{ "switch", NULL, 40, -1, NULL, 0, 2 },
{ "pstart", NULL, 40, -1, NULL, 0, 2 },
{ "pstop", NULL, 40, -1, NULL, 0, 2 },
{ "stnmov", NULL, 40, -1, NULL, 0, 2 },
{ "chicpai", NULL, 32, -1, NULL, 0, 2 },
{ "chicatk", NULL, 32, -1, NULL, 0, 2 },
{ "chicdth", NULL, 40, -1, NULL, 0, 2 },
{ "chicact", NULL, 32, -1, NULL, 0, 2 },
{ "chicpk1", NULL, 32, -1, NULL, 0, 2 },
{ "chicpk2", NULL, 32, -1, NULL, 0, 2 },
{ "chicpk3", NULL, 32, -1, NULL, 0, 2 },
{ "keyup", NULL, 50, -1, NULL, 0, 2 },
{ "ripslop", NULL, 16, -1, NULL, 0, 2 },
{ "newpod", NULL, 16, -1, NULL, 0, -1 },
{ "podexp", NULL, 40, -1, NULL, 0, -1 },
{ "bounce", NULL, 16, -1, NULL, 0, 2 },
{ "-volsht", &S_sfx[sfx_bstatk], 16, -1, NULL, 0, 2 },
{ "-volhit", &S_sfx[sfx_lobhit], 16, -1, NULL, 0, 2 },
{ "burn", NULL, 10, -1, NULL, 0, 2 },
{ "splash", NULL, 10, -1, NULL, 0, 1 },
{ "gloop", NULL, 10, -1, NULL, 0, 2 },
{ "respawn", NULL, 10, -1, NULL, 0, 1 },
{ "blssht", NULL, 32, -1, NULL, 0, 2 },
{ "blshit", NULL, 32, -1, NULL, 0, 2 },
{ "chat", NULL, 100, -1, NULL, 0, 1 },
{ "artiuse", NULL, 32, -1, NULL, 0, 1 },
{ "gfrag", NULL, 100, -1, NULL, 0, 1 },
{ "waterfl", NULL, 16, -1, NULL, 0, 2 },
// Monophonic sounds
{ "wind", NULL, 16, -1, NULL, 0, 1 },
{ "amb1", NULL, 1, -1, NULL, 0, 1 },
{ "amb2", NULL, 1, -1, NULL, 0, 1 },
{ "amb3", NULL, 1, -1, NULL, 0, 1 },
{ "amb4", NULL, 1, -1, NULL, 0, 1 },
{ "amb5", NULL, 1, -1, NULL, 0, 1 },
{ "amb6", NULL, 1, -1, NULL, 0, 1 },
{ "amb7", NULL, 1, -1, NULL, 0, 1 },
{ "amb8", NULL, 1, -1, NULL, 0, 1 },
{ "amb9", NULL, 1, -1, NULL, 0, 1 },
{ "amb10", NULL, 1, -1, NULL, 0, 1 },
{ "amb11", NULL, 1, -1, NULL, 0, 0 }
};

269
Heretic Source/SOUNDS.H Normal file
View File

@ -0,0 +1,269 @@
// sounds.h
#ifndef __SOUNDSH__
#define __SOUNDSH__
#define MAX_SND_DIST 1600
#define MAX_CHANNELS 16
// Music identifiers
typedef enum
{
mus_e1m1,
mus_e1m2,
mus_e1m3,
mus_e1m4,
mus_e1m5,
mus_e1m6,
mus_e1m7,
mus_e1m8,
mus_e1m9,
mus_e2m1,
mus_e2m2,
mus_e2m3,
mus_e2m4,
mus_e2m5,
mus_e2m6,
mus_e2m7,
mus_e2m8,
mus_e2m9,
mus_e3m1,
mus_e3m2,
mus_e3m3,
mus_e3m4,
mus_e3m5,
mus_e3m6,
mus_e3m7,
mus_e3m8,
mus_e3m9,
mus_e4m1,
mus_e4m2,
mus_e4m3,
mus_e4m4,
mus_e4m5,
mus_e4m6,
mus_e4m7,
mus_e4m8,
mus_e4m9,
mus_e5m1,
mus_e5m2,
mus_e5m3,
mus_e5m4,
mus_e5m5,
mus_e5m6,
mus_e5m7,
mus_e5m8,
mus_e5m9,
mus_e6m1,
mus_e6m2,
mus_e6m3,
mus_titl,
mus_intr,
mus_cptd,
NUMMUSIC
} musicenum_t;
typedef struct
{
char name[8];
int p1;
} musicinfo_t;
typedef struct sfxinfo_s
{
char name[8];
struct sfxinfo_s *link; // Make alias for another sound
unsigned short priority; // Higher priority takes precendence
int usefulness; // Determines when a sound should be cached out
void *snd_ptr;
int lumpnum;
int numchannels; // total number of channels a sound type may occupy
} sfxinfo_t;
typedef struct
{
mobj_t *mo;
long sound_id;
long handle;
long pitch;
int priority;
} channel_t;
typedef struct
{
long id;
unsigned short priority;
char *name;
mobj_t *mo;
int distance;
} ChanInfo_t;
typedef struct
{
int channelCount;
int musicVolume;
int soundVolume;
ChanInfo_t chan[8];
} SoundInfo_t;
// Sound identifiers
typedef enum
{
sfx_None,
sfx_gldhit,
sfx_gntful,
sfx_gnthit,
sfx_gntpow,
sfx_gntact,
sfx_gntuse,
sfx_phosht,
sfx_phohit,
sfx_phopow,
sfx_lobsht,
sfx_lobhit,
sfx_lobpow,
sfx_hrnsht,
sfx_hrnhit,
sfx_hrnpow,
sfx_ramphit,
sfx_ramrain,
sfx_bowsht,
sfx_stfhit,
sfx_stfpow,
sfx_stfcrk,
sfx_impsit,
sfx_impat1,
sfx_impat2,
sfx_impdth,
sfx_impact,
sfx_imppai,
sfx_mumsit,
sfx_mumat1,
sfx_mumat2,
sfx_mumdth,
sfx_mumact,
sfx_mumpai,
sfx_mumhed,
sfx_bstsit,
sfx_bstatk,
sfx_bstdth,
sfx_bstact,
sfx_bstpai,
sfx_clksit,
sfx_clkatk,
sfx_clkdth,
sfx_clkact,
sfx_clkpai,
sfx_snksit,
sfx_snkatk,
sfx_snkdth,
sfx_snkact,
sfx_snkpai,
sfx_kgtsit,
sfx_kgtatk,
sfx_kgtat2,
sfx_kgtdth,
sfx_kgtact,
sfx_kgtpai,
sfx_wizsit,
sfx_wizatk,
sfx_wizdth,
sfx_wizact,
sfx_wizpai,
sfx_minsit,
sfx_minat1,
sfx_minat2,
sfx_minat3,
sfx_mindth,
sfx_minact,
sfx_minpai,
sfx_hedsit,
sfx_hedat1,
sfx_hedat2,
sfx_hedat3,
sfx_heddth,
sfx_hedact,
sfx_hedpai,
sfx_sorzap,
sfx_sorrise,
sfx_sorsit,
sfx_soratk,
sfx_soract,
sfx_sorpai,
sfx_sordsph,
sfx_sordexp,
sfx_sordbon,
sfx_sbtsit,
sfx_sbtatk,
sfx_sbtdth,
sfx_sbtact,
sfx_sbtpai,
sfx_plroof,
sfx_plrpai,
sfx_plrdth, // Normal
sfx_gibdth, // Extreme
sfx_plrwdth, // Wimpy
sfx_plrcdth, // Crazy
sfx_itemup,
sfx_wpnup,
sfx_telept,
sfx_doropn,
sfx_dorcls,
sfx_dormov,
sfx_artiup,
sfx_switch,
sfx_pstart,
sfx_pstop,
sfx_stnmov,
sfx_chicpai,
sfx_chicatk,
sfx_chicdth,
sfx_chicact,
sfx_chicpk1,
sfx_chicpk2,
sfx_chicpk3,
sfx_keyup,
sfx_ripslop,
sfx_newpod,
sfx_podexp,
sfx_bounce,
sfx_volsht,
sfx_volhit,
sfx_burn,
sfx_splash,
sfx_gloop,
sfx_respawn,
sfx_blssht,
sfx_blshit,
sfx_chat,
sfx_artiuse,
sfx_gfrag,
sfx_waterfl,
// Monophonic sounds
sfx_wind,
sfx_amb1,
sfx_amb2,
sfx_amb3,
sfx_amb4,
sfx_amb5,
sfx_amb6,
sfx_amb7,
sfx_amb8,
sfx_amb9,
sfx_amb10,
sfx_amb11,
NUMSFX
} sfxenum_t;
#endif

23
Heretic Source/SOUNDST.H Normal file
View File

@ -0,0 +1,23 @@
// soundst.h
#ifndef __SOUNDSTH__
#define __SOUNDSTH__
extern int snd_MaxVolume;
extern int snd_MusicVolume;
void S_Start(void);
void S_StartSound(mobj_t *origin, int sound_id);
void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume);
void S_StopSound(mobj_t *origin);
void S_PauseSound(void);
void S_ResumeSound(void);
void S_UpdateSounds(mobj_t *listener);
void S_StartSong(int song, boolean loop);
void S_Init(void);
void S_GetChannelInfo(SoundInfo_t *s);
void S_SetMaxVolume(boolean fullprocess);
void S_SetMusicVolume(void);
#endif

2062
Heretic Source/TABLES.C Normal file

File diff suppressed because it is too large Load Diff

62
Heretic Source/TIC.LNK Normal file
View File

@ -0,0 +1,62 @@
# TIC.EXE Linker directive file
option quiet
option map
option stack=65536
option stub=wstub
debug all
libpath %WATCOM%\lib386
libpath %WATCOM%\lib386\dos
lib noemu387.lib
lib dmx
format os2 le
name tic
file i_cyber.obj
file i_ibm.obj
file i_ibm_a.obj
file i_sound.obj
file linear.obj
file am_map.obj
file ct_chat.obj
file d_main.obj
file d_net.obj
file g_game.obj
file f_finale.obj
file info.obj
file in_lude.obj
file mn_menu.obj
file m_misc.obj
file p_ceilng.obj
file p_doors.obj
file p_enemy.obj
file p_floor.obj
file p_inter.obj
file p_lights.obj
file p_map.obj
file p_maputl.obj
file p_mobj.obj
file p_plats.obj
file p_pspr.obj
file p_setup.obj
file p_sight.obj
file p_spec.obj
file p_switch.obj
file p_telept.obj
file p_tick.obj
file p_user.obj
file r_bsp.obj
file r_data.obj
file r_draw.obj
file r_main.obj
file r_plane.obj
file r_segs.obj
file r_things.obj
file sb_bar.obj
file sounds.obj
file tables.obj
file v_video.obj
file w_wad.obj
file z_zone.obj

2231
Heretic Source/TIC.MAP Normal file

File diff suppressed because it is too large Load Diff

BIN
Heretic Source/TINTTAB.LMP Normal file

Binary file not shown.

24
Heretic Source/VGAVIEW.H Normal file
View File

@ -0,0 +1,24 @@
#import <appkit/appkit.h>
#import "DoomDef.h"
// a few globals
extern byte *bytebuffer;
@interface VGAView:View
{
id game;
int nextpalette[256]; // color lookup table
int *nextimage; // palette expanded and scaled
unsigned scale;
NXWindowDepth depth;
}
- updateView;
- (unsigned)scale;
- setPalette:(byte *)pal;
- setScale:(int)newscale;
@end

200
Heretic Source/V_VIDEO.C Normal file
View File

@ -0,0 +1,200 @@
// V_video.c
#include "DoomDef.h"
#define SC_INDEX 0x3c4
byte *screen;
int dirtybox[4];
int usegamma;
byte gammatable[5][256] =
{
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
{2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255},
{4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255},
{8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255},
{16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255}
};
//---------------------------------------------------------------------------
//
// PROC V_DrawPatch
//
// Draws a column based masked pic to the screen.
//
//---------------------------------------------------------------------------
void V_DrawPatch(int x, int y, patch_t *patch)
{
int count;
int col;
column_t *column;
byte *desttop;
byte *dest;
byte *source;
int w;
y -= SHORT(patch->topoffset);
x -= SHORT(patch->leftoffset);
if(x < 0 || x+SHORT(patch->width) > SCREENWIDTH || y < 0
|| y+SHORT(patch->height) > SCREENHEIGHT)
{
I_Error("Bad V_DrawPatch");
}
col = 0;
desttop = screen+y*SCREENWIDTH+x;
w = SHORT(patch->width);
for(; col < w; x++, col++, desttop++)
{
column = (column_t *)((byte *)patch+LONG(patch->columnofs[col]));
// Step through the posts in a column
while(column->topdelta != 0xff)
{
source = (byte *)column+3;
dest = desttop+column->topdelta*SCREENWIDTH;
count = column->length;
while(count--)
{
*dest = *source++;
dest += SCREENWIDTH;
}
column = (column_t *)((byte *)column+column->length+4);
}
}
}
/*
==================
=
= V_DrawFuzzPatch
=
= Masks a column based translucent masked pic to the screen.
=
==================
*/
extern byte *tinttable;
void V_DrawFuzzPatch (int x, int y, patch_t *patch)
{
int count,col;
column_t *column;
byte *desttop, *dest, *source;
int w;
y -= SHORT(patch->topoffset);
x -= SHORT(patch->leftoffset);
if (x<0||x+SHORT(patch->width) >SCREENWIDTH || y<0 || y+SHORT(patch->height)>SCREENHEIGHT )
I_Error ("Bad V_DrawPatch");
col = 0;
desttop = screen+y*SCREENWIDTH+x;
w = SHORT(patch->width);
for ( ; col<w ; x++, col++, desttop++)
{
column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
// step through the posts in a column
while (column->topdelta != 0xff )
{
source = (byte *)column + 3;
dest = desttop + column->topdelta*SCREENWIDTH;
count = column->length;
while (count--)
{
*dest = tinttable[((*dest)<<8) + *source++];
dest += SCREENWIDTH;
}
column = (column_t *)( (byte *)column + column->length
+ 4 );
}
}
}
/*
==================
=
= V_DrawShadowedPatch
=
= Masks a column based masked pic to the screen.
=
==================
*/
void V_DrawShadowedPatch(int x, int y, patch_t *patch)
{
int count,col;
column_t *column;
byte *desttop, *dest, *source;
byte *desttop2, *dest2;
int w;
y -= SHORT(patch->topoffset);
x -= SHORT(patch->leftoffset);
if (x<0||x+SHORT(patch->width) >SCREENWIDTH || y<0 || y+SHORT(patch->height)>SCREENHEIGHT )
I_Error ("Bad V_DrawPatch");
col = 0;
desttop = screen+y*SCREENWIDTH+x;
desttop2 = screen+(y+2)*SCREENWIDTH+x+2;
w = SHORT(patch->width);
for ( ; col<w ; x++, col++, desttop++, desttop2++)
{
column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
// step through the posts in a column
while (column->topdelta != 0xff )
{
source = (byte *)column + 3;
dest = desttop + column->topdelta*SCREENWIDTH;
dest2 = desttop2 + column->topdelta*SCREENWIDTH;
count = column->length;
while (count--)
{
*dest2 = tinttable[((*dest2)<<8)];
dest2 += SCREENWIDTH;
*dest = *source++;
dest += SCREENWIDTH;
}
column = (column_t *)( (byte *)column + column->length
+ 4 );
}
}
}
//---------------------------------------------------------------------------
//
// PROC V_DrawRawScreen
//
//---------------------------------------------------------------------------
void V_DrawRawScreen(byte *raw)
{
memcpy(screen, raw, SCREENWIDTH*SCREENHEIGHT);
}
//---------------------------------------------------------------------------
//
// PROC V_Init
//
//---------------------------------------------------------------------------
void V_Init(void)
{
// I_AllocLow will put screen in low dos memory on PCs.
screen = I_AllocLow(SCREENWIDTH*SCREENHEIGHT);
}

319
Heretic Source/WADLINK.TXT Normal file
View File

@ -0,0 +1,319 @@
//--------------------------------------------------------------------------
//
// WADLINK.TXT
//
//--------------------------------------------------------------------------
; WAD NAME
#ifdef EXTENDED
; Extended version
$WADNAME extended/heretic
#elif defined(REGISTERED)
; Registered version
$WADNAME heretic
#else
; Shareware version
$WADNAME heretic1
#endif
#ifdef EXTENDED
\data\extended.txt
#endif
; PALETTES AND COLOR MAPS
\art\palette\playpal.lmp
\art\palette\colormap.lmp
\art\palette\tinttab.lmp
; DEMOS AND DOS SCREENS
\data\txtscr_s\loading.bin
#ifdef EXTENDED
; Extended version
$shootwad \art\screens\scrn_e.wad
\data\txtscr_e\endtext.bin
\data\demos_r\demo1.lmp
\data\demos_r\demo2.lmp
\data\demos_r\demo3.lmp
#elif defined(REGISTERED)
; Registered version
$shootwad \art\screens\scrn_r.wad
\data\txtscr_r\endtext.bin
\data\demos_r\demo1.lmp
\data\demos_r\demo2.lmp
\data\demos_r\demo3.lmp
#else
; Shareware version
$shootwad \art\screens\scrn_s.wad
\data\txtscr_s\endtext.bin
\data\demos_s\demo1.lmp
\data\demos_s\demo2.lmp
\data\demos_s\demo3.lmp
#endif
; LEVEL MAPS
$shootwad \data\e1m1
$shootwad \data\e1m2
$shootwad \data\e1m3
$shootwad \data\e1m4
$shootwad \data\e1m5
$shootwad \data\e1m6
$shootwad \data\e1m7
$shootwad \data\e1m8
$shootwad \data\e1m9
#ifdef REGISTERED
$shootwad \data\e2m1
$shootwad \data\e2m2
$shootwad \data\e2m3
$shootwad \data\e2m4
$shootwad \data\e2m5
$shootwad \data\e2m6
$shootwad \data\e2m7
$shootwad \data\e2m8
$shootwad \data\e2m9
$shootwad \data\e3m1
$shootwad \data\e3m2
$shootwad \data\e3m3
$shootwad \data\e3m4
$shootwad \data\e3m5
$shootwad \data\e3m6
$shootwad \data\e3m7
$shootwad \data\e3m8
$shootwad \data\e3m9
#ifdef EXTENDED
$shootwad \data\e4m1
$shootwad \data\e4m2
$shootwad \data\e4m3
$shootwad \data\e4m4
$shootwad \data\e4m5
$shootwad \data\e4m6
$shootwad \data\e4m7
$shootwad \data\e4m8
$shootwad \data\e4m9
$shootwad \data\e5m1
$shootwad \data\e5m2
$shootwad \data\e5m3
$shootwad \data\e5m4
$shootwad \data\e5m5
$shootwad \data\e5m6
$shootwad \data\e5m7
$shootwad \data\e5m8
$shootwad \data\e5m9
$shootwad \data\e6m1
$shootwad \data\e6m2
$shootwad \data\e6m3
#else
$shootwad \data\e4m1map
#endif
#endif
; TEXTURE INFO AND PATCH NAMES
\data\texture1.lmp
#ifdef REGISTERED
\data\texture2.lmp
#endif
\data\pnames.lmp
; AUTOMAP
$shootwad \art\automap\automap
; SOUND
\data\genmidi.op2
; \data\dmxgus.ini ;included in wavwad.wads...
\sound\samples\sndcurve.lmp
#ifdef REGISTERED
$shootwad \sound\samples\wavwad
#else
$shootwad \sound\samples\wavwad1
#endif
; SCREENS
;$shootwad \gfx\screens\help
;$shootwad \gfx\screens\credits
#ifdef REGISTERED
;$shootwad \gfx\screens\victory2
;$shootwad \gfx\screens\title
;$shootwad \gfx\screens\pfub
;$shootwad \gfx\screens\end
#else
;$shootwad \gfx\screens\stitle
#endif
; INTERMISSION
#ifdef REGISTERED
$shootwad \art\intermsn\intermsn.wad
#else
$shootwad \art\intermsn\interm1.wad
#endif
; STATUS BAR
#ifdef REGISTERED
$shootwad \art\statbar\statbar
#else
$shootwad \art\statbar\statbar1
#endif
; MENU
$shootwad \art\menu\menu
; FONTS
$label fonta_s
$shootwad \art\fonts\fonta
$label fonta_e
$label fontb_s
$shootwad \art\fonts\fontb
$label fontb_e
; START SPRITES
$label s_start
; EPISODE 1 WINDOW WEAPONS
$shootwad \art\weapons\staff\staff.wad
$shootwad \art\weapons\goldwand\goldwand.wad
$shootwad \art\weapons\crossbow\crossbow.wad
$shootwad \art\weapons\blaster\blaster
$shootwad \art\weapons\gauntlet\gauntlet.wad
$shootwad \art\weapons\beak\beak.wad
#ifdef REGISTERED
; EPISODE 2 AND 3 WINDOW WEAPONS
; Fire mace
$shootwad \art\weapons\mace\mace.wad
; Hellstaff
$shootwad \art\weapons\hornrod\hornrod.wad
; Phoenix rod
$shootwad \art\weapons\phoenix\phoenix.wad
#endif
; PLAYER
$shootwad \art\player\player
$shootwad \art\player\player2
; EPISODE 1 MONSTERS
; Chicken
$shootwad \art\monsters\chicken\chicken
; Imp (Gargoyle)
$shootwad \art\monsters\imp\imp
; Mummy (Golem)
$shootwad \art\monsters\mummy\mummy
; Knight (Undead warrior)
$shootwad \art\monsters\knight\knight
; Wizard (Disciple of D'Sparil)
$shootwad \art\monsters\wizard\wizard
; Head (Ironlich)
$shootwad \art\monsters\head\head
#ifdef REGISTERED
; EPISODE 2 AND 3 MONSTERS
; Clink (Sabreclaw)
$shootwad \art\monsters\clink\clink
; Beast (Weredragon)
$shootwad \art\monsters\beast\beast
; Snake (Ophidian)
$shootwad \art\monsters\snake\snake
; Minotaur (Maulotaur)
$shootwad \art\monsters\minotaur\walk
$shootwad \art\monsters\minotaur\pain
$shootwad \art\monsters\minotaur\death
$shootwad \art\monsters\minotaur\attack
$shootwad \art\monsters\minotaur\fx
; Sorcerer (D'Sparil)
$shootwad \art\monsters\sorcerer\d1
$shootwad \art\monsters\sorcerer\d2
$shootwad \art\monsters\sorcerer\s1
$shootwad \art\monsters\sorcerer\s2
#endif
; STATIC SPRITES
$shootwad \art\sprites\e1spr
#ifdef REGISTERED
$shootwad \art\weapons\images\images
$shootwad \art\artifcts\artifcts
$shootwad \art\items\items
$shootwad \art\ammo\ammo
#else
$shootwad \art\weapons\images\images1
$shootwad \art\artifcts\arti1
$shootwad \art\items\items1
$shootwad \art\ammo\ammo1
#endif
#ifdef REGISTERED
$shootwad \art\sprites\e23spr
#endif
; END SPRITES
$label s_end
; START PATCHES
$label p_start
; EPSIDOE 1 PATCHES
$label p1_start
$shootwad \art\walls\e1\e1walls
$shootwad \art\backdrop\e1sky
$label p1_end
; EPISODE 2 AND 3 PATCHES
#ifdef REGISTERED
$label p2_start
$shootwad \art\walls\e23\e23walls
$shootwad \art\backdrop\e23sky
$label p2_end
#endif
; END PATCHES
$label p_end
; START FLATS
$label f_start
; EPISODE 1 FLATS
$label f1_start
$shootwad \art\flats\e1\e1flats
$label f1_end
; EPISODE 2 AND 3 FLATS
#ifdef REGISTERED
$label f2_start
$shootwad \art\flats\e23\e23flats
$label f2_end
#endif
; END FLATS
$label f_end

285
Heretic Source/WADLINK.WL Normal file
View File

@ -0,0 +1,285 @@
; WAD NAME
; Extended version
$WADNAME extended/heretic
\data\extended.txt
; PALETTES AND COLOR MAPS
\art\palette\playpal.lmp
\art\palette\colormap.lmp
\art\palette\tinttab.lmp
; DEMOS AND DOS SCREENS
\data\txtscr_s\loading.bin
; Extended version
$shootwad \art\screens\scrn_e.wad
\data\txtscr_e\endtext.bin
\data\demos_r\demo1.lmp
\data\demos_r\demo2.lmp
\data\demos_r\demo3.lmp
; LEVEL MAPS
$shootwad \data\e1m1
$shootwad \data\e1m2
$shootwad \data\e1m3
$shootwad \data\e1m4
$shootwad \data\e1m5
$shootwad \data\e1m6
$shootwad \data\e1m7
$shootwad \data\e1m8
$shootwad \data\e1m9
$shootwad \data\e2m1
$shootwad \data\e2m2
$shootwad \data\e2m3
$shootwad \data\e2m4
$shootwad \data\e2m5
$shootwad \data\e2m6
$shootwad \data\e2m7
$shootwad \data\e2m8
$shootwad \data\e2m9
$shootwad \data\e3m1
$shootwad \data\e3m2
$shootwad \data\e3m3
$shootwad \data\e3m4
$shootwad \data\e3m5
$shootwad \data\e3m6
$shootwad \data\e3m7
$shootwad \data\e3m8
$shootwad \data\e3m9
$shootwad \data\e4m1
$shootwad \data\e4m2
$shootwad \data\e4m3
$shootwad \data\e4m4
$shootwad \data\e4m5
$shootwad \data\e4m6
$shootwad \data\e4m7
$shootwad \data\e4m8
$shootwad \data\e4m9
$shootwad \data\e5m1
$shootwad \data\e5m2
$shootwad \data\e5m3
$shootwad \data\e5m4
$shootwad \data\e5m5
$shootwad \data\e5m6
$shootwad \data\e5m7
$shootwad \data\e5m8
$shootwad \data\e5m9
$shootwad \data\e6m1
$shootwad \data\e6m2
$shootwad \data\e6m3
; TEXTURE INFO AND PATCH NAMES
\data\texture1.lmp
\data\texture2.lmp
\data\pnames.lmp
; AUTOMAP
$shootwad \art\automap\automap
; SOUND
\data\genmidi.op2
; \data\dmxgus.ini ;included in wavwad.wads...
\sound\samples\sndcurve.lmp
$shootwad \sound\samples\wavwad
; SCREENS
;$shootwad \gfx\screens\help
;$shootwad \gfx\screens\credits
;$shootwad \gfx\screens\victory2
;$shootwad \gfx\screens\title
;$shootwad \gfx\screens\pfub
;$shootwad \gfx\screens\end
; INTERMISSION
$shootwad \art\intermsn\intermsn.wad
; STATUS BAR
$shootwad \art\statbar\statbar
; MENU
$shootwad \art\menu\menu
; FONTS
$label fonta_s
$shootwad \art\fonts\fonta
$label fonta_e
$label fontb_s
$shootwad \art\fonts\fontb
$label fontb_e
; START SPRITES
$label s_start
; EPISODE 1 WINDOW WEAPONS
$shootwad \art\weapons\staff\staff.wad
$shootwad \art\weapons\goldwand\goldwand.wad
$shootwad \art\weapons\crossbow\crossbow.wad
$shootwad \art\weapons\blaster\blaster
$shootwad \art\weapons\gauntlet\gauntlet.wad
$shootwad \art\weapons\beak\beak.wad
; EPISODE 2 AND 3 WINDOW WEAPONS
; Fire mace
$shootwad \art\weapons\mace\mace.wad
; Hellstaff
$shootwad \art\weapons\hornrod\hornrod.wad
; Phoenix rod
$shootwad \art\weapons\phoenix\phoenix.wad
; PLAYER
$shootwad \art\player\player
$shootwad \art\player\player2
; EPISODE 1 MONSTERS
; Chicken
$shootwad \art\monsters\chicken\chicken
; Imp (Gargoyle)
$shootwad \art\monsters\imp\imp
; Mummy (Golem)
$shootwad \art\monsters\mummy\mummy
; Knight (Undead warrior)
$shootwad \art\monsters\knight\knight
; Wizard (Disciple of D'Sparil)
$shootwad \art\monsters\wizard\wizard
; Head (Ironlich)
$shootwad \art\monsters\head\head
; EPISODE 2 AND 3 MONSTERS
; Clink (Sabreclaw)
$shootwad \art\monsters\clink\clink
; Beast (Weredragon)
$shootwad \art\monsters\beast\beast
; Snake (Ophidian)
$shootwad \art\monsters\snake\snake
; Minotaur (Maulotaur)
$shootwad \art\monsters\minotaur\walk
$shootwad \art\monsters\minotaur\pain
$shootwad \art\monsters\minotaur\death
$shootwad \art\monsters\minotaur\attack
$shootwad \art\monsters\minotaur\fx
; Sorcerer (D'Sparil)
$shootwad \art\monsters\sorcerer\d1
$shootwad \art\monsters\sorcerer\d2
$shootwad \art\monsters\sorcerer\s1
$shootwad \art\monsters\sorcerer\s2
; STATIC SPRITES
$shootwad \art\sprites\e1spr
$shootwad \art\weapons\images\images
$shootwad \art\artifcts\artifcts
$shootwad \art\items\items
$shootwad \art\ammo\ammo
$shootwad \art\sprites\e23spr
; END SPRITES
$label s_end
; START PATCHES
$label p_start
; EPSIDOE 1 PATCHES
$label p1_start
$shootwad \art\walls\e1\e1walls
$shootwad \art\backdrop\e1sky
$label p1_end
; EPISODE 2 AND 3 PATCHES
$label p2_start
$shootwad \art\walls\e23\e23walls
$shootwad \art\backdrop\e23sky
$label p2_end
; END PATCHES
$label p_end
; START FLATS
$label f_start
; EPISODE 1 FLATS
$label f1_start
$shootwad \art\flats\e1\e1flats
$label f1_end
; EPISODE 2 AND 3 FLATS
$label f2_start
$shootwad \art\flats\e23\e23flats
$label f2_end
; END FLATS
$label f_end

6
Heretic Source/WS.BAT Normal file
View File

@ -0,0 +1,6 @@
@echo off
echo Making shareware WAD (HERETIC1.WAD)
echo Preprocessing: wadlink.txt to wadlink.wl
\tools\wcc386 /p /fo=wadlink.wl wadlink.txt
echo wadlinking ...
\tools\exe\wadlink

495
Heretic Source/W_WAD.C Normal file
View File

@ -0,0 +1,495 @@
// W_wad.c
#ifdef NeXT
#include <libc.h>
#include <ctype.h>
// next doesn't need a binary flag in open call
#define O_BINARY 0
#else
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#include "DoomDef.h"
//===============
// TYPES
//===============
typedef struct
{
char identification[4]; // should be IWAD
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int size;
char name[8];
} filelump_t;
//=============
// GLOBALS
//=============
lumpinfo_t *lumpinfo; // location of each lump on disk
int numlumps;
void **lumpcache;
//===================
#ifdef NeXT
#define strcmpi strcasecmp
void strupr (char *s)
{
while (*s)
*s++ = toupper(*s);
}
/*
================
=
= filelength
=
================
*/
int filelength (int handle)
{
struct stat fileinfo;
if (fstat (handle,&fileinfo) == -1)
I_Error ("Error fstating");
return fileinfo.st_size;
}
#endif
void ExtractFileBase (char *path, char *dest)
{
char *src;
int length;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != '\\' && *(src-1) != '/')
src--;
//
// copy up to eight characters
//
memset (dest,0,8);
length = 0;
while (*src && *src != '.')
{
if (++length == 9)
I_Error ("Filename base of %s >8 chars",path);
*dest++ = toupper((int)*src++);
}
}
/*
============================================================================
LUMP BASED ROUTINES
============================================================================
*/
/*
====================
=
= W_AddFile
=
= All files are optional, but at least one file must be found
= Files with a .wad extension are wadlink files with multiple lumps
= Other files are single lumps with the base filename for the lump name
=
====================
*/
void W_AddFile (char *filename)
{
wadinfo_t header;
lumpinfo_t *lump_p;
unsigned i;
int handle, length;
int startlump;
filelump_t *fileinfo, singleinfo;
//
// open the file and add to directory
//
if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1)
return;
startlump = numlumps;
if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
{
// single lump file
fileinfo = &singleinfo;
singleinfo.filepos = 0;
singleinfo.size = LONG(filelength(handle));
ExtractFileBase (filename, singleinfo.name);
numlumps++;
}
else
{
// WAD file
read (handle, &header, sizeof(header));
if (strncmp(header.identification,"IWAD",4))
{
if (strncmp(header.identification,"PWAD",4))
I_Error ("Wad file %s doesn't have IWAD or PWAD id\n"
,filename);
}
header.numlumps = LONG(header.numlumps);
header.infotableofs = LONG(header.infotableofs);
length = header.numlumps*sizeof(filelump_t);
fileinfo = alloca (length);
lseek (handle, header.infotableofs, SEEK_SET);
read (handle, fileinfo, length);
numlumps += header.numlumps;
}
//
// Fill in lumpinfo
//
lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
if (!lumpinfo)
I_Error ("Couldn't realloc lumpinfo");
lump_p = &lumpinfo[startlump];
for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
{
lump_p->handle = handle;
lump_p->position = LONG(fileinfo->filepos);
lump_p->size = LONG(fileinfo->size);
strncpy (lump_p->name, fileinfo->name, 8);
}
}
/*
====================
=
= W_InitMultipleFiles
=
= Pass a null terminated list of files to use.
=
= All files are optional, but at least one file must be found
=
= Files with a .wad extension are idlink files with multiple lumps
=
= Other files are single lumps with the base filename for the lump name
=
= Lump names can appear multiple times. The name searcher looks backwards,
= so a later file can override an earlier one.
=
====================
*/
void W_InitMultipleFiles (char **filenames)
{
int size;
//
// open all the files, load headers, and count lumps
//
numlumps = 0;
lumpinfo = malloc(1); // will be realloced as lumps are added
for ( ; *filenames ; filenames++)
W_AddFile (*filenames);
if (!numlumps)
I_Error ("W_InitFiles: no files found");
//
// set up caching
//
size = numlumps * sizeof(*lumpcache);
lumpcache = malloc (size);
if (!lumpcache)
I_Error ("Couldn't allocate lumpcache");
memset (lumpcache,0, size);
}
/*
====================
=
= W_InitFile
=
= Just initialize from a single file
=
====================
*/
void W_InitFile (char *filename)
{
char *names[2];
names[0] = filename;
names[1] = NULL;
W_InitMultipleFiles (names);
}
/*
====================
=
= W_NumLumps
=
====================
*/
int W_NumLumps (void)
{
return numlumps;
}
/*
====================
=
= W_CheckNumForName
=
= Returns -1 if name not found
=
====================
*/
int W_CheckNumForName (char *name)
{
char name8[9];
int v1,v2;
lumpinfo_t *lump_p;
// make the name into two integers for easy compares
strncpy (name8,name,8);
name8[8] = 0; // in case the name was a fill 8 chars
strupr (name8); // case insensitive
v1 = *(int *)name8;
v2 = *(int *)&name8[4];
// scan backwards so patch lump files take precedence
lump_p = lumpinfo + numlumps;
while (lump_p-- != lumpinfo)
if ( *(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
return lump_p - lumpinfo;
return -1;
}
/*
====================
=
= W_GetNumForName
=
= Calls W_CheckNumForName, but bombs out if not found
=
====================
*/
int W_GetNumForName (char *name)
{
int i;
i = W_CheckNumForName (name);
if (i != -1)
return i;
I_Error ("W_GetNumForName: %s not found!",name);
return -1;
}
/*
====================
=
= W_LumpLength
=
= Returns the buffer size needed to load the given lump
=
====================
*/
int W_LumpLength (int lump)
{
if (lump >= numlumps)
I_Error ("W_LumpLength: %i >= numlumps",lump);
return lumpinfo[lump].size;
}
/*
====================
=
= W_ReadLump
=
= Loads the lump into the given buffer, which must be >= W_LumpLength()
=
====================
*/
void W_ReadLump (int lump, void *dest)
{
int c;
lumpinfo_t *l;
if (lump >= numlumps)
I_Error ("W_ReadLump: %i >= numlumps",lump);
l = lumpinfo+lump;
I_BeginRead ();
lseek (l->handle, l->position, SEEK_SET);
c = read (l->handle, dest, l->size);
if (c < l->size)
I_Error ("W_ReadLump: only read %i of %i on lump %i",c,l->size,lump);
I_EndRead ();
}
/*
====================
=
= W_CacheLumpNum
=
====================
*/
void *W_CacheLumpNum (int lump, int tag)
{
byte *ptr;
if ((unsigned)lump >= numlumps)
I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
if (!lumpcache[lump])
{ // read the lump in
//printf ("cache miss on lump %i\n",lump);
ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
W_ReadLump (lump, lumpcache[lump]);
}
else
{
//printf ("cache hit on lump %i\n",lump);
Z_ChangeTag (lumpcache[lump],tag);
}
return lumpcache[lump];
}
/*
====================
=
= W_CacheLumpName
=
====================
*/
void *W_CacheLumpName (char *name, int tag)
{
return W_CacheLumpNum (W_GetNumForName(name), tag);
}
/*
====================
=
= W_Profile
=
====================
*/
// Ripped out for Heretic
/*
int info[2500][10];
int profilecount;
void W_Profile (void)
{
int i;
memblock_t *block;
void *ptr;
char ch;
FILE *f;
int j;
char name[9];
for (i=0 ; i<numlumps ; i++)
{
ptr = lumpcache[i];
if (!ptr)
{
ch = ' ';
continue;
}
else
{
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->tag < PU_PURGELEVEL)
ch = 'S';
else
ch = 'P';
}
info[i][profilecount] = ch;
}
profilecount++;
f = fopen ("waddump.txt","w");
name[8] = 0;
for (i=0 ; i<numlumps ; i++)
{
memcpy (name,lumpinfo[i].name,8);
for (j=0 ; j<8 ; j++)
if (!name[j])
break;
for ( ; j<8 ; j++)
name[j] = ' ';
fprintf (f,"%s ",name);
for (j=0 ; j<profilecount ; j++)
fprintf (f," %c",info[i][j]);
fprintf (f,"\n");
}
fclose (f);
}
*/

389
Heretic Source/Z_ZONE.C Normal file
View File

@ -0,0 +1,389 @@
// Z_zone.c
#include <stdlib.h>
#include "DoomDef.h"
/*
==============================================================================
ZONE MEMORY ALLOCATION
There is never any space between memblocks, and there will never be two
contiguous free memblocks.
The rover can be left pointing at a non-empty block
It is of no value to free a cachable block, because it will get overwritten
automatically if needed
==============================================================================
*/
#define ZONEID 0x1d4a11
typedef struct
{
int size; // total bytes malloced, including header
memblock_t blocklist; // start / end cap for linked list
memblock_t *rover;
} memzone_t;
boolean MallocFailureOk;
memzone_t *mainzone;
/*
========================
=
= Z_ClearZone
=
========================
*/
void Z_ClearZone (memzone_t *zone)
{
memblock_t *block;
// set the entire zone to one free block
zone->blocklist.next = zone->blocklist.prev = block =
(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
zone->blocklist.user = (void *)zone;
zone->blocklist.tag = PU_STATIC;
zone->rover = block;
block->prev = block->next = &zone->blocklist;
block->user = NULL; // free block
block->size = zone->size - sizeof(memzone_t);
}
/*
========================
=
= Z_Init
=
========================
*/
void Z_Init (void)
{
memblock_t *block;
int size;
MallocFailureOk = false;
mainzone = (memzone_t *)I_ZoneBase (&size);
mainzone->size = size;
// set the entire zone to one free block
mainzone->blocklist.next = mainzone->blocklist.prev = block =
(memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
mainzone->blocklist.user = (void *)mainzone;
mainzone->blocklist.tag = PU_STATIC;
mainzone->rover = block;
block->prev = block->next = &mainzone->blocklist;
block->user = NULL; // free block
block->size = mainzone->size - sizeof(memzone_t);
}
/*
========================
=
= Z_Free
=
========================
*/
void Z_Free (void *ptr)
{
memblock_t *block, *other;
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->id != ZONEID)
I_Error ("Z_Free: freed a pointer without ZONEID");
if (block->user > (void **)0x100) // smaller values are not pointers
*block->user = 0; // clear the user's mark
block->user = NULL; // mark as free
block->tag = 0;
block->id = 0;
other = block->prev;
if (!other->user)
{ // merge with previous free block
other->size += block->size;
other->next = block->next;
other->next->prev = other;
if (block == mainzone->rover)
mainzone->rover = other;
block = other;
}
other = block->next;
if (!other->user)
{ // merge the next free block onto the end
block->size += other->size;
block->next = other->next;
block->next->prev = block;
if (other == mainzone->rover)
mainzone->rover = block;
}
}
/*
========================
=
= Z_Malloc
=
= You can pass a NULL user if the tag is < PU_PURGELEVEL
========================
*/
#define MINFRAGMENT 64
void *Z_Malloc (int size, int tag, void *user)
{
int extra;
memblock_t *start, *rover, *new, *base;
//
// scan through the block list looking for the first free block
// of sufficient size, throwing out any purgable blocks along the way
//
size += sizeof(memblock_t); // account for size of block header
//
// if there is a free block behind the rover, back up over them
//
base = mainzone->rover;
if (!base->prev->user)
base = base->prev;
rover = base;
start = base->prev;
do
{
if(rover == start)
{ // Scanned all the way around the list
if(MallocFailureOk == true)
{
return NULL;
}
else
{
I_Error("Z_Malloc: failed on allocation of %i bytes", size);
}
}
if (rover->user)
{
if (rover->tag < PU_PURGELEVEL)
// hit a block that can't be purged, so move base past it
base = rover = rover->next;
else
{
// free the rover block (adding the size to base)
base = base->prev; // the rover can be the base block
Z_Free ((byte *)rover+sizeof(memblock_t));
base = base->next;
rover = base->next;
}
}
else
rover = rover->next;
} while (base->user || base->size < size);
//
// found a block big enough
//
extra = base->size - size;
if (extra > MINFRAGMENT)
{ // there will be a free fragment after the allocated block
new = (memblock_t *) ((byte *)base + size );
new->size = extra;
new->user = NULL; // free block
new->tag = 0;
new->prev = base;
new->next = base->next;
new->next->prev = new;
base->next = new;
base->size = size;
}
if (user)
{
base->user = user; // mark as an in use block
*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
}
else
{
if (tag >= PU_PURGELEVEL)
I_Error ("Z_Malloc: an owner is required for purgable blocks");
base->user = (void *)2; // mark as in use, but unowned
}
base->tag = tag;
mainzone->rover = base->next; // next allocation will start looking here
base->id = ZONEID;
return (void *) ((byte *)base + sizeof(memblock_t));
}
/*
========================
=
= Z_FreeTags
=
========================
*/
void Z_FreeTags (int lowtag, int hightag)
{
memblock_t *block, *next;
for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
; block = next)
{
next = block->next; // get link before freeing
if (!block->user)
continue; // free block
if (block->tag >= lowtag && block->tag <= hightag)
Z_Free ( (byte *)block+sizeof(memblock_t));
}
}
/*
========================
=
= Z_DumpHeap
=
========================
*/
void Z_DumpHeap (int lowtag, int hightag)
{
memblock_t *block;
printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
printf ("tag range: %i to %i\n",lowtag, hightag);
for (block = mainzone->blocklist.next ; ; block = block->next)
{
if (block->tag >= lowtag && block->tag <= hightag)
printf ("block:%p size:%7i user:%p tag:%3i\n",
block, block->size, block->user, block->tag);
if (block->next == &mainzone->blocklist)
break; // all blocks have been hit
if ( (byte *)block + block->size != (byte *)block->next)
printf ("ERROR: block size does not touch the next block\n");
if ( block->next->prev != block)
printf ("ERROR: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
printf ("ERROR: two consecutive free blocks\n");
}
}
/*
========================
=
= Z_FileDumpHeap
=
========================
*/
void Z_FileDumpHeap (FILE *f)
{
memblock_t *block;
fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone);
for (block = mainzone->blocklist.next ; ; block = block->next)
{
fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
block, block->size, block->user, block->tag);
if (block->next == &mainzone->blocklist)
break; // all blocks have been hit
if ( (byte *)block + block->size != (byte *)block->next)
fprintf (f,"ERROR: block size does not touch the next block\n");
if ( block->next->prev != block)
fprintf (f,"ERROR: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
fprintf (f,"ERROR: two consecutive free blocks\n");
}
}
/*
========================
=
= Z_CheckHeap
=
========================
*/
void Z_CheckHeap (void)
{
memblock_t *block;
for (block = mainzone->blocklist.next ; ; block = block->next)
{
if (block->next == &mainzone->blocklist)
break; // all blocks have been hit
if ( (byte *)block + block->size != (byte *)block->next)
I_Error ("Z_CheckHeap: block size does not touch the next block\n");
if ( block->next->prev != block)
I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
I_Error ("Z_CheckHeap: two consecutive free blocks\n");
}
}
/*
========================
=
= Z_ChangeTag
=
========================
*/
void Z_ChangeTag2 (void *ptr, int tag)
{
memblock_t *block;
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->id != ZONEID)
I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
block->tag = tag;
}
/*
========================
=
= Z_FreeMemory
=
========================
*/
int Z_FreeMemory (void)
{
memblock_t *block;
int free;
free = 0;
for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
; block = block->next)
if (!block->user || block->tag >= PU_PURGELEVEL)
free += block->size;
return free;
}

339
LICENSE.txt Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

7
SourceReadme.txt Normal file
View File

@ -0,0 +1,7 @@
Activision and Raven are releasing this code for people to learn from and play with.
This code is copyright Activision 1996-1998
[edit 2 Sep 2008] The code is release under GNU GPLv2 (see LICENSE)
Issues:
The DMX sound library is not included with the source due to license issues,
so you won't be able to link until those sound calls are replaced or removed.