/programs/games/doom/trunk/d_main.c |
---|
436,7 → 436,7 |
S_UpdateSounds (players[consoleplayer].mo);// move positional sounds |
D_Display (); |
// I_UpdateSound(); |
// I_UpdateSound(); |
XXX(105); |
} |
} |
1120,8 → 1120,8 |
printf ("D_CheckNetGame: Checking network game status.\n\r"); |
D_CheckNetGame (); |
// printf ("S_Init: Setting up sound.\n\r"); |
// S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); |
printf ("S_Init: Setting up sound.\n\r"); |
S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); |
printf ("HU_Init: Setting up heads up display.\n\r"); |
HU_Init (); |
/programs/games/doom/trunk/h/doomdata.h |
---|
42,17 → 42,17 |
// to provide a complete scene geometry description. |
enum |
{ |
ML_LABEL, // A separator, name, ExMx or MAPxx |
ML_THINGS, // Monsters, items.. |
ML_LINEDEFS, // LineDefs, from editing |
ML_SIDEDEFS, // SideDefs, from editing |
ML_VERTEXES, // Vertices, edited and BSP splits generated |
ML_SEGS, // LineSegs, from LineDefs split by BSP |
ML_SSECTORS, // SubSectors, list of LineSegs |
ML_NODES, // BSP nodes |
ML_SECTORS, // Sectors, from editing |
ML_REJECT, // LUT, sector-sector visibility |
ML_BLOCKMAP // LUT, motion clipping, walls/grid element |
ML_LABEL, // A separator, name, ExMx or MAPxx |
ML_THINGS, // Monsters, items.. |
ML_LINEDEFS, // LineDefs, from editing |
ML_SIDEDEFS, // SideDefs, from editing |
ML_VERTEXES, // Vertices, edited and BSP splits generated |
ML_SEGS, // LineSegs, from LineDefs split by BSP |
ML_SSECTORS, // SubSectors, list of LineSegs |
ML_NODES, // BSP nodes |
ML_SECTORS, // Sectors, from editing |
ML_REJECT, // LUT, sector-sector visibility |
ML_BLOCKMAP // LUT, motion clipping, walls/grid element |
}; |
59,8 → 59,8 |
// A single Vertex. |
typedef struct |
{ |
short x; |
short y; |
short x; |
short y; |
} mapvertex_t; |
68,13 → 68,13 |
// by setting textures and offsets. |
typedef struct |
{ |
short textureoffset; |
short rowoffset; |
char toptexture[8]; |
char bottomtexture[8]; |
char midtexture[8]; |
short textureoffset; |
short rowoffset; |
char toptexture[8]; |
char bottomtexture[8]; |
char midtexture[8]; |
// Front sector, towards viewer. |
short sector; |
short sector; |
} mapsidedef_t; |
83,13 → 83,13 |
// to the BSP builder. |
typedef struct |
{ |
short v1; |
short v2; |
short flags; |
short special; |
short tag; |
short v1; |
short v2; |
short flags; |
short special; |
short tag; |
// sidenum[1] will be -1 if one sided |
short sidenum[2]; |
short sidenum[2]; |
} maplinedef_t; |
98,14 → 98,14 |
// |
// Solid, is an obstacle. |
#define ML_BLOCKING 1 |
#define ML_BLOCKING 1 |
// Blocks monsters only. |
#define ML_BLOCKMONSTERS 2 |
#define ML_BLOCKMONSTERS 2 |
// Backside will not be present at all |
// if not two sided. |
#define ML_TWOSIDED 4 |
#define ML_TWOSIDED 4 |
// If a texture is pegged, the texture will have |
// the end exposed to air held constant at the |
117,44 → 117,44 |
// top and bottom textures (use next to windows). |
// upper texture unpegged |
#define ML_DONTPEGTOP 8 |
#define ML_DONTPEGTOP 8 |
// lower texture unpegged |
#define ML_DONTPEGBOTTOM 16 |
#define ML_DONTPEGBOTTOM 16 |
// In AutoMap: don't map as two sided: IT'S A SECRET! |
#define ML_SECRET 32 |
#define ML_SECRET 32 |
// Sound rendering: don't let sound cross two of these. |
#define ML_SOUNDBLOCK 64 |
#define ML_SOUNDBLOCK 64 |
// Don't draw on the automap at all. |
#define ML_DONTDRAW 128 |
#define ML_DONTDRAW 128 |
// Set if already seen, thus drawn in automap. |
#define ML_MAPPED 256 |
#define ML_MAPPED 256 |
// Sector definition, from editing. |
typedef struct |
typedef struct |
{ |
short floorheight; |
short ceilingheight; |
char floorpic[8]; |
char ceilingpic[8]; |
short lightlevel; |
short special; |
short tag; |
short floorheight; |
short ceilingheight; |
char floorpic[8]; |
char ceilingpic[8]; |
short lightlevel; |
short special; |
short tag; |
} mapsector_t; |
// SubSector, as generated by BSP. |
typedef struct |
{ |
short numsegs; |
short numsegs; |
// Index of first one, segs are stored sequentially. |
short firstseg; |
short firstseg; |
} mapsubsector_t; |
162,12 → 162,12 |
// using partition lines selected by BSP builder. |
typedef struct |
{ |
short v1; |
short v2; |
short angle; |
short linedef; |
short side; |
short offset; |
short v1; |
short v2; |
short angle; |
short linedef; |
short side; |
short offset; |
} mapseg_t; |
175,23 → 175,23 |
// BSP node structure. |
// Indicate a leaf. |
#define NF_SUBSECTOR 0x8000 |
#define NF_SUBSECTOR 0x8000 |
typedef struct |
{ |
// Partition line from (x,y) to x+dx,y+dy) |
short x; |
short y; |
short dx; |
short dy; |
short x; |
short y; |
short dx; |
short dy; |
// Bounding box for each child, |
// clip against view frustum. |
short bbox[2][4]; |
short bbox[2][4]; |
// If NF_SUBSECTOR its a subsector, |
// else it's a node of another subtree. |
unsigned short children[2]; |
unsigned short children[2]; |
} mapnode_t; |
202,11 → 202,11 |
// plus skill/visibility flags and attributes. |
typedef struct |
{ |
short x; |
short y; |
short angle; |
short type; |
short options; |
short x; |
short y; |
short angle; |
short type; |
short options; |
} mapthing_t; |
213,7 → 213,7 |
#endif // __DOOMDATA__ |
#endif // __DOOMDATA__ |
//----------------------------------------------------------------------------- |
// |
// $Log:$ |
/programs/games/doom/trunk/h/r_defs.h |
---|
23,7 → 23,7 |
#ifndef __R_DEFS__ |
#define __R_DEFS__ |
#include "doomtype.h" |
// Screenwidth. |
#include "doomdef.h" |
/programs/games/doom/trunk/i_sound.c |
---|
1,671 → 1,685 |
// Emacs style mode select -*- C++ -*- |
//----------------------------------------------------------------------------- |
// |
// $Id:$ |
// |
// Copyright (C) 1993-1996 by id Software, Inc. |
// |
// This source is available for distribution and/or modification |
// only under the terms of the DOOM Source Code License as |
// published by id Software. All rights reserved. |
// |
// The source is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
// for more details. |
// |
// $Log:$ |
// |
// DESCRIPTION: |
// System interface for sound. |
// |
//----------------------------------------------------------------------------- |
static const char |
rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdarg.h> |
#include <math.h> |
#include <sys/types.h> |
#include <fcntl.h> |
// Timer stuff. Experimental. |
#include <time.h> |
#include <signal.h> |
#include "z_zone.h" |
#include "i_system.h" |
#include "i_sound.h" |
#include "m_argv.h" |
#include "m_misc.h" |
#include "w_wad.h" |
#include "doomdef.h" |
// The number of internal mixing channels, |
// the samples calculated for each mixing step, |
// the size of the 16bit, 2 hardware channel (stereo) |
// mixing buffer, and the samplerate of the raw data. |
// Needed for calling the actual sound output. |
#define SAMPLECOUNT 512 |
#define NUM_CHANNELS 16 |
// It is 2 for 16bit, and 2 for two channels. |
#define BUFMUL 4 |
#define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL) |
#define SAMPLERATE 11025 // Hz |
#define SAMPLESIZE 2 // 16bit |
// The actual lengths of all sound effects. |
int lengths[NUMSFX]; |
// The actual output device. |
int audio_fd; |
// The global mixing buffer. |
// Basically, samples from all active internal channels |
// are modifed and added, and stored in the buffer |
// that is submitted to the audio device. |
signed short mixbuffer[MIXBUFFERSIZE]; |
// The channel step amount... |
unsigned int channelstep[NUM_CHANNELS]; |
// ... and a 0.16 bit remainder of last step. |
unsigned int channelstepremainder[NUM_CHANNELS]; |
// The channel data pointers, start and end. |
unsigned char* channels[NUM_CHANNELS]; |
unsigned char* channelsend[NUM_CHANNELS]; |
// Time/gametic that the channel started playing, |
// used to determine oldest, which automatically |
// has lowest priority. |
// In case number of active sounds exceeds |
// available channels. |
int channelstart[NUM_CHANNELS]; |
// The sound in channel handles, |
// determined on registration, |
// might be used to unregister/stop/modify, |
// currently unused. |
int channelhandles[NUM_CHANNELS]; |
// SFX id of the playing sound effect. |
// Used to catch duplicates (like chainsaw). |
int channelids[NUM_CHANNELS]; |
// Pitch to stepping lookup, unused. |
int steptable[256]; |
// Volume lookups. |
int vol_lookup[128*256]; |
// Hardware left and right channel volume lookup. |
int* channelleftvol_lookup[NUM_CHANNELS]; |
int* channelrightvol_lookup[NUM_CHANNELS]; |
// |
// This function loads the sound data from the WAD lump, |
// for single sound. |
// |
void* getsfx (char* sfxname, int* len) |
{ |
unsigned char* sfx; |
unsigned char* paddedsfx; |
int i; |
int size; |
int paddedsize; |
char name[20]; |
int sfxlump; |
// Get the sound data from the WAD, allocate lump |
// in zone memory. |
sprintf(name, "ds%s", sfxname); |
// Now, there is a severe problem with the |
// sound handling, in it is not (yet/anymore) |
// gamemode aware. That means, sounds from |
// DOOM II will be requested even with DOOM |
// shareware. |
// The sound list is wired into sounds.c, |
// which sets the external variable. |
// I do not do runtime patches to that |
// variable. Instead, we will use a |
// default sound for replacement. |
if ( W_CheckNumForName(name) == -1 ) |
sfxlump = W_GetNumForName("dspistol"); |
else |
sfxlump = W_GetNumForName(name); |
size = W_LumpLength( sfxlump ); |
// Debug. |
// fprintf( stderr, "." ); |
//fprintf( stderr, " -loading %s (lump %d, %d bytes)\n", |
// sfxname, sfxlump, size ); |
//fflush( stderr ); |
sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC ); |
// Pads the sound effect out to the mixing buffer size. |
// The original realloc would interfere with zone memory. |
paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT; |
// Allocate from zone memory. |
paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 ); |
// ddt: (unsigned char *) realloc(sfx, paddedsize+8); |
// This should interfere with zone memory handling, |
// which does not kick in in the soundserver. |
// Now copy and pad. |
memcpy( paddedsfx, sfx, size ); |
for (i=size ; i<paddedsize+8 ; i++) |
paddedsfx[i] = 128; |
// Remove the cached lump. |
Z_Free( sfx ); |
// Preserve padded length. |
*len = paddedsize; |
// Return allocated padded data. |
return (void *) (paddedsfx + 8); |
} |
// |
// This function adds a sound to the |
// list of currently active sounds, |
// which is maintained as a given number |
// (eight, usually) of internal channels. |
// Returns a handle. |
// |
static unsigned short handlenums = 0; |
int addsfx(int sfxid, int volume, int step, int seperation) |
{ |
int i; |
int rc = -1; |
int oldest = gametic; |
int oldestnum = 0; |
int slot; |
int rightvol; |
int leftvol; |
// Chainsaw troubles. |
// Play these sound effects only one at a time. |
if ( sfxid == sfx_sawup |
|| sfxid == sfx_sawidl |
|| sfxid == sfx_sawful |
|| sfxid == sfx_sawhit |
|| sfxid == sfx_stnmov |
|| sfxid == sfx_pistol ) |
{ |
// Loop all channels, check. |
for (i=0 ; i<NUM_CHANNELS ; i++) |
{ |
// Active, and using the same SFX? |
if ( (channels[i]) |
&& (channelids[i] == sfxid) ) |
{ |
// Reset. |
channels[i] = 0; |
// We are sure that iff, |
// there will only be one. |
break; |
} |
} |
} |
// Loop all channels to find oldest SFX. |
for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++) |
{ |
if (channelstart[i] < oldest) |
{ |
oldestnum = i; |
oldest = channelstart[i]; |
} |
} |
// Tales from the cryptic. |
// If we found a channel, fine. |
// If not, we simply overwrite the first one, 0. |
// Probably only happens at startup. |
if (i == NUM_CHANNELS) |
slot = oldestnum; |
else |
slot = i; |
// Okay, in the less recent channel, |
// we will handle the new SFX. |
// Set pointer to raw data. |
channels[slot] = (unsigned char *) S_sfx[sfxid].data; |
// Set pointer to end of raw data. |
channelsend[slot] = channels[slot] + lengths[sfxid]; |
// Reset current handle number, limited to 0..100. |
if (!handlenums) |
handlenums = 100; |
// Assign current handle number. |
// Preserved so sounds could be stopped (unused). |
channelhandles[slot] = rc = handlenums++; |
channelstep[slot] = step; |
channelstepremainder[slot] = 0; |
// Should be gametic, I presume. |
channelstart[slot] = gametic; |
// Separation, that is, orientation/stereo. |
// range is: 1 - 256 |
seperation += 1; |
volume *=7; |
// Per left/right channel. |
// x^2 seperation, |
// adjust volume properly. |
leftvol = |
volume - ((volume*seperation*seperation) >> 16); ///(256*256); |
seperation = seperation - 257; |
rightvol = |
volume - ((volume*seperation*seperation) >> 16); |
// Sanity check, clamp volume. |
if (rightvol < 0 || rightvol > 127) |
I_Error("rightvol out of bounds"); |
if (leftvol < 0 || leftvol > 127) |
I_Error("leftvol out of bounds"); |
// Get the proper lookup table piece |
// for this volume level??? |
channelleftvol_lookup[slot] = &vol_lookup[leftvol*256]; |
channelrightvol_lookup[slot] = &vol_lookup[rightvol*256]; |
// Preserve sound SFX id, |
// e.g. for avoiding duplicates of chainsaw. |
channelids[slot] = sfxid; |
// You tell me. |
return rc; |
} |
// |
// SFX API |
// Note: this was called by S_Init. |
// However, whatever they did in the |
// old DPMS based DOS version, this |
// were simply dummies in the Linux |
// version. |
// See soundserver initdata(). |
// |
void I_SetChannels() |
{ |
// Init internal lookups (raw data, mixing buffer, channels). |
// This function sets up internal lookups used during |
// the mixing process. |
int i; |
int j; |
int* steptablemid = steptable + 128; |
// Okay, reset internal mixing channels to zero. |
for (i=0; i<NUM_CHANNELS; i++) |
{ |
channels[i] = 0; |
} |
// for (i=-128 ; i<128 ; i++) |
// steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0); |
// Generates volume lookup tables |
// which also turn the unsigned samples |
// into signed samples. |
for (i=0 ; i<128 ; i++) |
for (j=0 ; j<256 ; j++) |
vol_lookup[i*256+j] = (i*(j-128)*256)/127; |
} |
void I_SetSfxVolume(int volume) |
{ |
// Identical to DOS. |
// Basically, this should propagate |
// the menu/config file setting |
// to the state variable used in |
// the mixing. |
snd_SfxVolume = volume; |
} |
// MUSIC API - dummy. Some code from DOS version. |
void I_SetMusicVolume(int volume) |
{ |
// Internal state variable. |
snd_MusicVolume = volume; |
} |
// |
// Retrieve the raw data lump index |
// for a given SFX name. |
// |
int I_GetSfxLumpNum(sfxinfo_t* sfx) |
{ |
char namebuf[9]; |
sprintf(namebuf, "ds%s", sfx->name); |
return W_GetNumForName(namebuf); |
} |
// |
// Starting a sound means adding it |
// to the current list of active sounds |
// in the internal channels. |
// As the SFX info struct contains |
// e.g. a pointer to the raw data, |
// it is ignored. |
// As our sound handling does not handle |
// priority, it is ignored. |
// Pitching (that is, increased speed of playback) |
// |
int I_StartSound(int id, int vol, int sep, |
int pitch, int priority ) |
{ |
// Returns a handle (not used). |
id = addsfx( id, vol, steptable[pitch], sep ); |
return id; |
} |
void I_StopSound (int handle) |
{ |
// You need the handle returned by StartSound. |
// Would be looping all channels, |
// tracking down the handle, |
// an setting the channel to zero. |
// UNUSED. |
handle = 0; |
} |
int I_SoundIsPlaying(int handle) |
{ |
// Ouch. |
return gametic < handle; |
} |
// |
// This function loops all active (internal) sound |
// channels, retrieves a given number of samples |
// from the raw sound data, modifies it according |
// to the current (internal) channel parameters, |
// mixes the per channel samples into the global |
// mixbuffer, clamping it to the allowed range, |
// and sets up everything for transferring the |
// contents of the mixbuffer to the (two) |
// hardware channels (left and right, that is). |
// |
// This function currently supports only 16bit. |
// |
void I_UpdateSound( void ) |
{ |
// Mix current sound data. |
// Data, from raw sound, for right and left. |
register unsigned int sample; |
register int dl; |
register int dr; |
// Pointers in global mixbuffer, left, right, end. |
signed short* leftout; |
signed short* rightout; |
signed short* leftend; |
// Step in mixbuffer, left and right, thus two. |
int step; |
// Mixing channel index. |
int chan; |
// Left and right channel |
// are in global mixbuffer, alternating. |
leftout = mixbuffer; |
rightout = mixbuffer+1; |
step = 2; |
// Determine end, for left channel only |
// (right channel is implicit). |
leftend = mixbuffer + SAMPLECOUNT*step; |
// Mix sounds into the mixing buffer. |
// Loop over step*SAMPLECOUNT, |
// that is 512 values for two channels. |
while (leftout != leftend) |
{ |
// Reset left/right value. |
dl = 0; |
dr = 0; |
// Love thy L2 chache - made this a loop. |
// Now more channels could be set at compile time |
// as well. Thus loop those channels. |
for ( chan = 0; chan < NUM_CHANNELS; chan++ ) |
{ |
// Check channel, if active. |
if (channels[ chan ]) |
{ |
// Get the raw data from the channel. |
sample = *channels[ chan ]; |
// Add left and right part |
// for this channel (sound) |
// to the current data. |
// Adjust volume accordingly. |
dl += channelleftvol_lookup[ chan ][sample]; |
dr += channelrightvol_lookup[ chan ][sample]; |
channelstepremainder[ chan ] += channelstep[ chan ]; |
channels[ chan ] += channelstepremainder[ chan ] >> 16; |
channelstepremainder[ chan ] &= 65536-1; |
// Check whether we are done. |
if (channels[ chan ] >= channelsend[ chan ]) |
channels[ chan ] = 0; |
} |
} |
// Clamp to range. Left hardware channel. |
// Has been char instead of short. |
// if (dl > 127) *leftout = 127; |
// else if (dl < -128) *leftout = -128; |
// else *leftout = dl; |
if (dl > 0x7fff) |
*leftout = 0x7fff; |
else if (dl < -0x8000) |
*leftout = -0x8000; |
else |
*leftout = dl; |
// Same for right hardware channel. |
if (dr > 0x7fff) |
*rightout = 0x7fff; |
else if (dr < -0x8000) |
*rightout = -0x8000; |
else |
*rightout = dr; |
// Increment current pointers in mixbuffer. |
leftout += step; |
rightout += step; |
} |
// I_SubmitSound(mixbuffer); |
} |
// |
// This would be used to write out the mixbuffer |
// during each game loop update. |
// Updates sound buffer and audio device at runtime. |
// It is called during Timer interrupt with SNDINTR. |
// Mixing now done synchronous, and |
// only output be done asynchronous? |
// |
//void I_SubmitSound(void) |
//{ |
// Write it to DSP device. |
// write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); |
//} |
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch) |
{ |
// I fail too see that this is used. |
// Would be using the handle to identify |
// on which channel the sound might be active, |
// and resetting the channel parameters. |
// UNUSED. |
handle = vol = sep = pitch = 0; |
} |
void I_ShutdownSound(void) |
{ |
// Wait till all pending sounds are finished. |
int done = 0; |
int i; |
// FIXME (below). |
printf( "I_ShutdownSound: NOT finishing pending sounds\n"); |
while ( !done ) |
{ |
for( i=0 ; i<8 && !channels[i] ; i++); |
// FIXME. No proper channel output. |
//if (i==8) |
done=1; |
} |
return; |
} |
void I_InitSound() |
{ int i; |
printf("I_InitSound: "); |
for (i=1 ; i<NUMSFX ; i++) |
{ |
// Alias? Example is the chaingun sound linked to pistol. |
if (!S_sfx[i].link) |
{ |
// Load data from WAD file. |
S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] ); |
} |
else |
{ |
// Previously loaded already? |
S_sfx[i].data = S_sfx[i].link->data; |
lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; |
} |
} |
printf( " pre-cached all sound data\n"); |
// Now initialize mixbuffer with zero. |
for ( i = 0; i< MIXBUFFERSIZE; i++ ) |
mixbuffer[i] = 0; |
// Finished initialization. |
printf("I_InitSound: sound module ready\n"); |
} |
// |
// MUSIC API. |
// Still no music done. |
// Remains. Dummies. |
// |
void I_InitMusic(void) { } |
void I_ShutdownMusic(void) { } |
static int looping=0; |
static int musicdies=-1; |
void I_PlaySong(int handle, int looping) |
{ |
// UNUSED. |
handle = looping = 0; |
musicdies = gametic + TICRATE*30; |
} |
void I_PauseSong (int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
void I_ResumeSong (int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
void I_StopSong(int handle) |
{ |
// UNUSED. |
handle = 0; |
looping = 0; |
musicdies = 0; |
} |
void I_UnRegisterSong(int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
int I_RegisterSong(void* data) |
{ |
// UNUSED. |
data = NULL; |
return 1; |
} |
// Is the song playing? |
int I_QrySongPlaying(int handle) |
{ |
// UNUSED. |
handle = 0; |
return looping || musicdies > gametic; |
} |
// Interrupt handler. |
void I_HandleSoundTimer( int ignore ) |
{ |
// UNUSED, but required. |
ignore = 0; |
return; |
} |
// Emacs style mode select -*- C++ -*- |
//----------------------------------------------------------------------------- |
// |
// $Id:$ |
// |
// Copyright (C) 1993-1996 by id Software, Inc. |
// |
// This source is available for distribution and/or modification |
// only under the terms of the DOOM Source Code License as |
// published by id Software. All rights reserved. |
// |
// The source is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
// for more details. |
// |
// $Log:$ |
// |
// DESCRIPTION: |
// System interface for sound. |
// |
//----------------------------------------------------------------------------- |
static const char |
rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdarg.h> |
#include <math.h> |
#include <sys/types.h> |
#include <fcntl.h> |
// Timer stuff. Experimental. |
#include <time.h> |
#include <signal.h> |
#include "z_zone.h" |
#include "i_system.h" |
#include "i_sound.h" |
#include "m_argv.h" |
#include "m_misc.h" |
#include "w_wad.h" |
#include "doomdef.h" |
#include "kolibri.h" |
// The number of internal mixing channels, |
// the samples calculated for each mixing step, |
// the size of the 16bit, 2 hardware channel (stereo) |
// mixing buffer, and the samplerate of the raw data. |
// Needed for calling the actual sound output. |
#define SAMPLECOUNT 8192 |
#define NUM_CHANNELS 16 |
// It is 2 for 16bit, and 2 for two channels. |
#define BUFMUL 4 |
#define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL) |
#define SAMPLERATE 11025 // Hz |
#define SAMPLESIZE 2 // 16bit |
// The actual lengths of all sound effects. |
int lengths[NUMSFX]; |
// The actual output device. |
int audio_fd; |
// The global mixing buffer. |
// Basically, samples from all active internal channels |
// are modifed and added, and stored in the buffer |
// that is submitted to the audio device. |
signed short mixbuffer[MIXBUFFERSIZE]; |
// The channel step amount... |
unsigned int channelstep[NUM_CHANNELS]; |
// ... and a 0.16 bit remainder of last step. |
unsigned int channelstepremainder[NUM_CHANNELS]; |
// The channel data pointers, start and end. |
unsigned char* channels[NUM_CHANNELS]; |
unsigned char* channelsend[NUM_CHANNELS]; |
// Time/gametic that the channel started playing, |
// used to determine oldest, which automatically |
// has lowest priority. |
// In case number of active sounds exceeds |
// available channels. |
int channelstart[NUM_CHANNELS]; |
// The sound in channel handles, |
// determined on registration, |
// might be used to unregister/stop/modify, |
// currently unused. |
int channelhandles[NUM_CHANNELS]; |
// SFX id of the playing sound effect. |
// Used to catch duplicates (like chainsaw). |
int channelids[NUM_CHANNELS]; |
// Pitch to stepping lookup, unused. |
int steptable[256]; |
// Volume lookups. |
int vol_lookup[128*256]; |
// Hardware left and right channel volume lookup. |
int* channelleftvol_lookup[NUM_CHANNELS]; |
int* channelrightvol_lookup[NUM_CHANNELS]; |
// |
// This function loads the sound data from the WAD lump, |
// for single sound. |
// |
void* getsfx (char* sfxname, int* len) |
{ |
unsigned char* sfx; |
unsigned char* paddedsfx; |
int i; |
int size; |
int paddedsize; |
char name[20]; |
int sfxlump; |
// Get the sound data from the WAD, allocate lump |
// in zone memory. |
sprintf(name, "ds%s", sfxname); |
// Now, there is a severe problem with the |
// sound handling, in it is not (yet/anymore) |
// gamemode aware. That means, sounds from |
// DOOM II will be requested even with DOOM |
// shareware. |
// The sound list is wired into sounds.c, |
// which sets the external variable. |
// I do not do runtime patches to that |
// variable. Instead, we will use a |
// default sound for replacement. |
if ( W_CheckNumForName(name) == -1 ) |
sfxlump = W_GetNumForName("dspistol"); |
else |
sfxlump = W_GetNumForName(name); |
size = W_LumpLength( sfxlump ); |
// Debug. |
// fprintf( stderr, "." ); |
//fprintf( stderr, " -loading %s (lump %d, %d bytes)\n", |
// sfxname, sfxlump, size ); |
//fflush( stderr ); |
sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC ); |
// Pads the sound effect out to the mixing buffer size. |
// The original realloc would interfere with zone memory. |
paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT; |
// Allocate from zone memory. |
paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 ); |
// ddt: (unsigned char *) realloc(sfx, paddedsize+8); |
// This should interfere with zone memory handling, |
// which does not kick in in the soundserver. |
// Now copy and pad. |
memcpy( paddedsfx, sfx, size ); |
for (i=size ; i<paddedsize+8 ; i++) |
paddedsfx[i] = 128; |
// Remove the cached lump. |
Z_Free( sfx ); |
// Preserve padded length. |
*len = paddedsize; |
// Return allocated padded data. |
return (void *) (paddedsfx + 8); |
} |
// |
// This function adds a sound to the |
// list of currently active sounds, |
// which is maintained as a given number |
// (eight, usually) of internal channels. |
// Returns a handle. |
// |
static unsigned short handlenums = 0; |
int addsfx(int sfxid, int volume, int step, int seperation) |
{ |
int i; |
int rc = -1; |
int oldest = gametic; |
int oldestnum = 0; |
int slot; |
int rightvol; |
int leftvol; |
// Chainsaw troubles. |
// Play these sound effects only one at a time. |
if ( sfxid == sfx_sawup |
|| sfxid == sfx_sawidl |
|| sfxid == sfx_sawful |
|| sfxid == sfx_sawhit |
|| sfxid == sfx_stnmov |
|| sfxid == sfx_pistol ) |
{ |
// Loop all channels, check. |
for (i=0 ; i<NUM_CHANNELS ; i++) |
{ |
// Active, and using the same SFX? |
if ( (channels[i]) |
&& (channelids[i] == sfxid) ) |
{ |
// Reset. |
channels[i] = 0; |
// We are sure that iff, |
// there will only be one. |
break; |
} |
} |
} |
// Loop all channels to find oldest SFX. |
for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++) |
{ |
if (channelstart[i] < oldest) |
{ |
oldestnum = i; |
oldest = channelstart[i]; |
} |
} |
// Tales from the cryptic. |
// If we found a channel, fine. |
// If not, we simply overwrite the first one, 0. |
// Probably only happens at startup. |
if (i == NUM_CHANNELS) |
slot = oldestnum; |
else |
slot = i; |
// Okay, in the less recent channel, |
// we will handle the new SFX. |
// Set pointer to raw data. |
channels[slot] = (unsigned char *) S_sfx[sfxid].data; |
// Set pointer to end of raw data. |
channelsend[slot] = channels[slot] + lengths[sfxid]; |
// Reset current handle number, limited to 0..100. |
if (!handlenums) |
handlenums = 100; |
// Assign current handle number. |
// Preserved so sounds could be stopped (unused). |
channelhandles[slot] = rc = handlenums++; |
channelstep[slot] = step; |
channelstepremainder[slot] = 0; |
// Should be gametic, I presume. |
channelstart[slot] = gametic; |
// Separation, that is, orientation/stereo. |
// range is: 1 - 256 |
seperation += 1; |
volume *=7; |
// Per left/right channel. |
// x^2 seperation, |
// adjust volume properly. |
leftvol = |
volume - ((volume*seperation*seperation) >> 16); ///(256*256); |
seperation = seperation - 257; |
rightvol = |
volume - ((volume*seperation*seperation) >> 16); |
// Sanity check, clamp volume. |
if (rightvol < 0 || rightvol > 127) |
I_Error("rightvol out of bounds"); |
if (leftvol < 0 || leftvol > 127) |
I_Error("leftvol out of bounds"); |
// Get the proper lookup table piece |
// for this volume level??? |
channelleftvol_lookup[slot] = &vol_lookup[leftvol*256]; |
channelrightvol_lookup[slot] = &vol_lookup[rightvol*256]; |
// Preserve sound SFX id, |
// e.g. for avoiding duplicates of chainsaw. |
channelids[slot] = sfxid; |
// You tell me. |
return rc; |
} |
// |
// SFX API |
// Note: this was called by S_Init. |
// However, whatever they did in the |
// old DPMS based DOS version, this |
// were simply dummies in the Linux |
// version. |
// See soundserver initdata(). |
// |
void I_SetChannels() |
{ |
// Init internal lookups (raw data, mixing buffer, channels). |
// This function sets up internal lookups used during |
// the mixing process. |
int i; |
int j; |
int* steptablemid = steptable + 128; |
// Okay, reset internal mixing channels to zero. |
for (i=0; i<NUM_CHANNELS; i++) |
{ |
channels[i] = 0; |
} |
for (i=-128 ; i<128 ; i++) |
steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0); |
// Generates volume lookup tables |
// which also turn the unsigned samples |
// into signed samples. |
for (i=0 ; i<128 ; i++) |
for (j=0 ; j<256 ; j++) |
vol_lookup[i*256+j] = (i*(j-128)*256)/127; |
} |
void I_SetSfxVolume(int volume) |
{ |
// Identical to DOS. |
// Basically, this should propagate |
// the menu/config file setting |
// to the state variable used in |
// the mixing. |
snd_SfxVolume = volume; |
} |
// MUSIC API - dummy. Some code from DOS version. |
void I_SetMusicVolume(int volume) |
{ |
// Internal state variable. |
snd_MusicVolume = volume; |
} |
// |
// Retrieve the raw data lump index |
// for a given SFX name. |
// |
int I_GetSfxLumpNum(sfxinfo_t* sfx) |
{ |
char namebuf[9]; |
sprintf(namebuf, "ds%s", sfx->name); |
return W_GetNumForName(namebuf); |
} |
// |
// Starting a sound means adding it |
// to the current list of active sounds |
// in the internal channels. |
// As the SFX info struct contains |
// e.g. a pointer to the raw data, |
// it is ignored. |
// As our sound handling does not handle |
// priority, it is ignored. |
// Pitching (that is, increased speed of playback) |
// |
int I_StartSound(int id, int vol, int sep, |
int pitch, int priority ) |
{ |
// Returns a handle (not used). |
id = addsfx( id, vol, steptable[pitch], sep ); |
return id; |
} |
void I_StopSound (int handle) |
{ |
// You need the handle returned by StartSound. |
// Would be looping all channels, |
// tracking down the handle, |
// an setting the channel to zero. |
// UNUSED. |
handle = 0; |
} |
int I_SoundIsPlaying(int handle) |
{ |
// Ouch. |
return gametic < handle; |
} |
// |
// This function loops all active (internal) sound |
// channels, retrieves a given number of samples |
// from the raw sound data, modifies it according |
// to the current (internal) channel parameters, |
// mixes the per channel samples into the global |
// mixbuffer, clamping it to the allowed range, |
// and sets up everything for transferring the |
// contents of the mixbuffer to the (two) |
// hardware channels (left and right, that is). |
// |
// This function currently supports only 16bit. |
// |
extern DWORD hMixBuff[4]; |
extern int mix_ptr; |
void I_UpdateSound( void ) |
{ |
// Mix current sound data. |
// Data, from raw sound, for right and left. |
register unsigned int sample; |
register int dl; |
register int dr; |
// Pointers in global mixbuffer, left, right, end. |
signed short* leftout; |
signed short* rightout; |
signed short* leftend; |
// Step in mixbuffer, left and right, thus two. |
int step; |
// Mixing channel index. |
int chan; |
int i; |
int flags; |
flags = 0; |
// Left and right channel |
// are in global mixbuffer, alternating. |
leftout = mixbuffer; |
rightout = mixbuffer+1; |
step = 2; |
// Determine end, for left channel only |
// (right channel is implicit). |
leftend = mixbuffer + SAMPLECOUNT*step; |
// Mix sounds into the mixing buffer. |
// Loop over step*SAMPLECOUNT, |
// that is 512 values for two channels. |
for (i=0; i < 8192; i++) |
{ |
// Reset left/right value. |
dl = 0; |
dr = 0; |
// Love thy L2 chache - made this a loop. |
// Now more channels could be set at compile time |
// as well. Thus loop those channels. |
for ( chan = 0; chan < NUM_CHANNELS; chan++ ) |
{ |
// Check channel, if active. |
if (channels[ chan ]) |
{ |
flags=1; |
// Get the raw data from the channel. |
sample = *channels[ chan ]; |
// Add left and right part |
// for this channel (sound) |
// to the current data. |
// Adjust volume accordingly. |
dl += channelleftvol_lookup[ chan ][sample]; |
dr += channelrightvol_lookup[ chan ][sample]; |
channelstepremainder[ chan ] += channelstep[ chan ]; |
channels[ chan ] += channelstepremainder[ chan ] >> 16; |
channelstepremainder[ chan ] &= 65536-1; |
// Check whether we are done. |
if (channels[ chan ] >= channelsend[ chan ]) |
channels[ chan ] = 0; |
} |
} |
// Clamp to range. Left hardware channel. |
// Has been char instead of short. |
// if (dl > 127) *leftout = 127; |
// else if (dl < -128) *leftout = -128; |
// else *leftout = dl; |
if (dl > 0x7fff) |
*leftout = 0x7fff; |
else if (dl < -0x8000) |
*leftout = -0x8000; |
else |
*leftout = dl; |
// Same for right hardware channel. |
if (dr > 0x7fff) |
*rightout = 0x7fff; |
else if (dr < -0x8000) |
*rightout = -0x8000; |
else |
*rightout = dr; |
// Increment current pointers in mixbuffer. |
leftout += step; |
rightout += step; |
} |
if(flags) |
{ WaveOut(hMixBuff[mix_ptr],(char*)&mixbuffer[0],32768); |
mix_ptr= (mix_ptr+1)&3; |
}; |
} |
// |
// This would be used to write out the mixbuffer |
// during each game loop update. |
// Updates sound buffer and audio device at runtime. |
// It is called during Timer interrupt with SNDINTR. |
// Mixing now done synchronous, and |
// only output be done asynchronous? |
// |
//void I_SubmitSound(void) |
//{ |
// Write it to DSP device. |
// write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); |
//} |
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch) |
{ |
// I fail too see that this is used. |
// Would be using the handle to identify |
// on which channel the sound might be active, |
// and resetting the channel parameters. |
// UNUSED. |
handle = vol = sep = pitch = 0; |
} |
void I_ShutdownSound(void) |
{ |
// Wait till all pending sounds are finished. |
int done = 0; |
int i; |
// FIXME (below). |
printf( "I_ShutdownSound: NOT finishing pending sounds\n"); |
while ( !done ) |
{ |
for( i=0 ; i<8 && !channels[i] ; i++); |
// FIXME. No proper channel output. |
//if (i==8) |
done=1; |
} |
return; |
} |
void I_InitSound() |
{ int i; |
printf("I_InitSound: "); |
for (i=1 ; i<NUMSFX ; i++) |
{ |
// Alias? Example is the chaingun sound linked to pistol. |
if (!S_sfx[i].link) |
{ |
// Load data from WAD file. |
S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] ); |
} |
else |
{ |
// Previously loaded already? |
S_sfx[i].data = S_sfx[i].link->data; |
lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; |
} |
} |
printf( " pre-cached all sound data\n"); |
// Now initialize mixbuffer with zero. |
for ( i = 0; i< MIXBUFFERSIZE; i++ ) |
mixbuffer[i] = 0; |
// Finished initialization. |
printf("I_InitSound: sound module ready\n"); |
} |
// |
// MUSIC API. |
// Still no music done. |
// Remains. Dummies. |
// |
void I_InitMusic(void) { } |
void I_ShutdownMusic(void) { } |
static int looping=0; |
static int musicdies=-1; |
void I_PlaySong(int handle, int looping) |
{ |
// UNUSED. |
handle = looping = 0; |
musicdies = gametic + TICRATE*30; |
} |
void I_PauseSong (int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
void I_ResumeSong (int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
void I_StopSong(int handle) |
{ |
// UNUSED. |
handle = 0; |
looping = 0; |
musicdies = 0; |
} |
void I_UnRegisterSong(int handle) |
{ |
// UNUSED. |
handle = 0; |
} |
int I_RegisterSong(void* data) |
{ |
// UNUSED. |
data = NULL; |
return 1; |
} |
// Is the song playing? |
int I_QrySongPlaying(int handle) |
{ |
// UNUSED. |
handle = 0; |
return looping || musicdies > gametic; |
} |
// Interrupt handler. |
void I_HandleSoundTimer( int ignore ) |
{ |
// UNUSED, but required. |
ignore = 0; |
return; |
} |
/programs/games/doom/trunk/i_system.c |
---|
99,7 → 99,7 |
void I_Init (void) |
{ |
I_InitGraphics(); |
// I_InitSound(); |
I_InitSound(); |
} |
// |
/programs/games/doom/trunk/m_fixed.c |
---|
17,7 → 17,7 |
// $Log:$ |
// |
// DESCRIPTION: |
// Fixed point implementation. |
// Fixed point implementation. |
// |
//----------------------------------------------------------------------------- |
42,8 → 42,8 |
fixed_t |
FixedMul |
( fixed_t a, |
fixed_t b ) |
( fixed_t a, |
fixed_t b ) |
{ |
return ((long long) a * (long long) b) >> FRACBITS; |
} |
56,11 → 56,11 |
fixed_t |
FixedDiv |
( fixed_t a, |
fixed_t b ) |
( fixed_t a, |
fixed_t b ) |
{ |
if ( (abs(a)>>14) >= abs(b)) |
return (a^b)<0 ? MININT : MAXINT; |
return (a^b)<0 ? MININT : MAXINT; |
return FixedDiv2 (a,b); |
} |
68,8 → 68,8 |
fixed_t |
FixedDiv2 |
( fixed_t a, |
fixed_t b ) |
( fixed_t a, |
fixed_t b ) |
{ |
#if 0 |
long long c; |
82,6 → 82,6 |
c = ((double)a) / ((double)b) * FRACUNIT; |
if (c >= 2147483648.0 || c < -2147483648.0) |
I_Error("FixedDiv: divide by zero"); |
I_Error("FixedDiv: divide by zero"); |
return (fixed_t) c; |
} |
/programs/games/doom/trunk/p_map.c |
---|
17,8 → 17,8 |
// $Log:$ |
// |
// DESCRIPTION: |
// Movement, collision handling. |
// Shooting and aiming. |
// Movement, collision handling. |
// Shooting and aiming. |
// |
//----------------------------------------------------------------------------- |
27,6 → 27,7 |
#include <stdlib.h> |
#include "doomtype.h" |
#include "m_bbox.h" |
#include "m_random.h" |
#include "i_system.h" |
43,31 → 44,31 |
#include "sounds.h" |
fixed_t tmbbox[4]; |
mobj_t* tmthing; |
int tmflags; |
fixed_t tmx; |
fixed_t tmy; |
fixed_t tmbbox[4]; |
mobj_t* tmthing; |
int tmflags; |
fixed_t tmx; |
fixed_t tmy; |
// If "floatok" true, move would be ok |
// if within "tmfloorz - tmceilingz". |
boolean floatok; |
boolean floatok; |
fixed_t tmfloorz; |
fixed_t tmceilingz; |
fixed_t tmdropoffz; |
fixed_t tmfloorz; |
fixed_t tmceilingz; |
fixed_t tmdropoffz; |
// keep track of the line that lowers the ceiling, |
// so missiles don't explode against sky hack walls |
line_t* ceilingline; |
line_t* ceilingline; |
// keep track of special lines as they are hit, |
// but don't process them until the move is proven valid |
#define MAXSPECIALCROSS 8 |
#define MAXSPECIALCROSS 8 |
line_t* spechit[MAXSPECIALCROSS]; |
int numspechit; |
line_t* spechit[MAXSPECIALCROSS]; |
int numspechit; |
80,30 → 81,30 |
// |
boolean PIT_StompThing (mobj_t* thing) |
{ |
fixed_t blockdist; |
fixed_t blockdist; |
if (!(thing->flags & MF_SHOOTABLE) ) |
return true; |
return true; |
blockdist = thing->radius + tmthing->radius; |
if ( abs(thing->x - tmx) >= blockdist |
|| abs(thing->y - tmy) >= blockdist ) |
|| abs(thing->y - tmy) >= blockdist ) |
{ |
// didn't hit it |
return true; |
// didn't hit it |
return true; |
} |
// don't clip against self |
if (thing == tmthing) |
return true; |
return true; |
// monsters don't stomp things except on boss level |
if ( !tmthing->player && gamemap != 30) |
return false; |
return false; |
P_DamageMobj (thing, tmthing, tmthing, 10000); |
return true; |
} |
113,26 → 114,26 |
// |
boolean |
P_TeleportMove |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
{ |
int xl; |
int xh; |
int yl; |
int yh; |
int bx; |
int by; |
int xl; |
int xh; |
int yl; |
int yh; |
int bx; |
int by; |
subsector_t* newsubsec; |
subsector_t* newsubsec; |
// kill anything occupying the position |
tmthing = thing; |
tmflags = thing->flags; |
tmx = x; |
tmy = y; |
tmbbox[BOXTOP] = y + tmthing->radius; |
tmbbox[BOXBOTTOM] = y - tmthing->radius; |
tmbbox[BOXRIGHT] = x + tmthing->radius; |
147,7 → 148,7 |
// will adjust them. |
tmfloorz = tmdropoffz = newsubsec->sector->floorheight; |
tmceilingz = newsubsec->sector->ceilingheight; |
validcount++; |
numspechit = 0; |
158,9 → 159,9 |
yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; |
for (bx=xl ; bx<=xh ; bx++) |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) |
return false; |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) |
return false; |
// the move is ok, |
// so link the thing into its new position |
167,12 → 168,12 |
P_UnsetThingPosition (thing); |
thing->floorz = tmfloorz; |
thing->ceilingz = tmceilingz; |
thing->ceilingz = tmceilingz; |
thing->x = x; |
thing->y = y; |
P_SetThingPosition (thing); |
return true; |
} |
189,14 → 190,14 |
boolean PIT_CheckLine (line_t* ld) |
{ |
if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] |
|| tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] |
|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] |
|| tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) |
return true; |
|| tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] |
|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] |
|| tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) |
return true; |
if (P_BoxOnLineSide (tmbbox, ld) != -1) |
return true; |
return true; |
// A line has been hit |
// The moving thing's destination position will cross |
209,38 → 210,38 |
// could be crossed in either order. |
if (!ld->backsector) |
return false; // one sided line |
return false; // one sided line |
if (!(tmthing->flags & MF_MISSILE) ) |
{ |
if ( ld->flags & ML_BLOCKING ) |
return false; // explicitly blocking everything |
if ( ld->flags & ML_BLOCKING ) |
return false; // explicitly blocking everything |
if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS ) |
return false; // block monsters only |
if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS ) |
return false; // block monsters only |
} |
// set openrange, opentop, openbottom |
P_LineOpening (ld); |
P_LineOpening (ld); |
// adjust floor / ceiling heights |
if (opentop < tmceilingz) |
{ |
tmceilingz = opentop; |
ceilingline = ld; |
tmceilingz = opentop; |
ceilingline = ld; |
} |
if (openbottom > tmfloorz) |
tmfloorz = openbottom; |
tmfloorz = openbottom; |
if (lowfloor < tmdropoffz) |
tmdropoffz = lowfloor; |
tmdropoffz = lowfloor; |
// if contacted a special line, add it to the list |
if (ld->special) |
{ |
spechit[numspechit] = ld; |
numspechit++; |
spechit[numspechit] = ld; |
numspechit++; |
} |
return true; |
251,39 → 252,39 |
// |
boolean PIT_CheckThing (mobj_t* thing) |
{ |
fixed_t blockdist; |
boolean solid; |
int damage; |
fixed_t blockdist; |
boolean solid; |
int damage; |
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) )) |
return true; |
return true; |
blockdist = thing->radius + tmthing->radius; |
if ( abs(thing->x - tmx) >= blockdist |
|| abs(thing->y - tmy) >= blockdist ) |
|| abs(thing->y - tmy) >= blockdist ) |
{ |
// didn't hit it |
return true; |
// didn't hit it |
return true; |
} |
// don't clip against self |
if (thing == tmthing) |
return true; |
return true; |
// check for skulls slamming into things |
if (tmthing->flags & MF_SKULLFLY) |
{ |
damage = ((P_Random()%8)+1)*tmthing->info->damage; |
P_DamageMobj (thing, tmthing, tmthing, damage); |
tmthing->flags &= ~MF_SKULLFLY; |
tmthing->momx = tmthing->momy = tmthing->momz = 0; |
P_SetMobjState (tmthing, tmthing->info->spawnstate); |
return false; // stop moving |
damage = ((P_Random()%8)+1)*tmthing->info->damage; |
P_DamageMobj (thing, tmthing, tmthing, damage); |
tmthing->flags &= ~MF_SKULLFLY; |
tmthing->momx = tmthing->momy = tmthing->momz = 0; |
P_SetMobjState (tmthing, tmthing->info->spawnstate); |
return false; // stop moving |
} |
290,55 → 291,55 |
// missiles can hit other things |
if (tmthing->flags & MF_MISSILE) |
{ |
// see if it went over / under |
if (tmthing->z > thing->z + thing->height) |
return true; // overhead |
if (tmthing->z+tmthing->height < thing->z) |
return true; // underneath |
if (tmthing->target && ( |
tmthing->target->type == thing->type || |
(tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| |
(tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) ) |
{ |
// Don't hit same species as originator. |
if (thing == tmthing->target) |
return true; |
// see if it went over / under |
if (tmthing->z > thing->z + thing->height) |
return true; // overhead |
if (tmthing->z+tmthing->height < thing->z) |
return true; // underneath |
if (tmthing->target && ( |
tmthing->target->type == thing->type || |
(tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| |
(tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) ) |
{ |
// Don't hit same species as originator. |
if (thing == tmthing->target) |
return true; |
if (thing->type != MT_PLAYER) |
{ |
// Explode, but do no damage. |
// Let players missile other players. |
return false; |
} |
} |
if (! (thing->flags & MF_SHOOTABLE) ) |
{ |
// didn't do any damage |
return !(thing->flags & MF_SOLID); |
} |
// damage / explode |
damage = ((P_Random()%8)+1)*tmthing->info->damage; |
P_DamageMobj (thing, tmthing, tmthing->target, damage); |
if (thing->type != MT_PLAYER) |
{ |
// Explode, but do no damage. |
// Let players missile other players. |
return false; |
} |
} |
if (! (thing->flags & MF_SHOOTABLE) ) |
{ |
// didn't do any damage |
return !(thing->flags & MF_SOLID); |
} |
// damage / explode |
damage = ((P_Random()%8)+1)*tmthing->info->damage; |
P_DamageMobj (thing, tmthing, tmthing->target, damage); |
// don't traverse any more |
return false; |
// don't traverse any more |
return false; |
} |
// check for special pickup |
if (thing->flags & MF_SPECIAL) |
{ |
solid = thing->flags&MF_SOLID; |
if (tmflags&MF_PICKUP) |
{ |
// can remove thing |
P_TouchSpecialThing (thing, tmthing); |
} |
return !solid; |
solid = thing->flags&MF_SOLID; |
if (tmflags&MF_PICKUP) |
{ |
// can remove thing |
P_TouchSpecialThing (thing, tmthing); |
} |
return !solid; |
} |
return !(thing->flags & MF_SOLID); |
} |
373,24 → 374,24 |
// |
boolean |
P_CheckPosition |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
{ |
int xl; |
int xh; |
int yl; |
int yh; |
int bx; |
int by; |
subsector_t* newsubsec; |
int xl; |
int xh; |
int yl; |
int yh; |
int bx; |
int by; |
subsector_t* newsubsec; |
tmthing = thing; |
tmflags = thing->flags; |
tmx = x; |
tmy = y; |
tmbbox[BOXTOP] = y + tmthing->radius; |
tmbbox[BOXBOTTOM] = y - tmthing->radius; |
tmbbox[BOXRIGHT] = x + tmthing->radius; |
405,12 → 406,12 |
// will adjust them. |
tmfloorz = tmdropoffz = newsubsec->sector->floorheight; |
tmceilingz = newsubsec->sector->ceilingheight; |
validcount++; |
numspechit = 0; |
if ( tmflags & MF_NOCLIP ) |
return true; |
return true; |
// Check things first, possibly picking things up. |
// The bounding box is extended by MAXRADIUS |
423,9 → 424,9 |
yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; |
for (bx=xl ; bx<=xh ; bx++) |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) |
return false; |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) |
return false; |
// check lines |
xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; |
434,9 → 435,9 |
yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; |
for (bx=xl ; bx<=xh ; bx++) |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) |
return false; |
for (by=yl ; by<=yh ; by++) |
if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) |
return false; |
return true; |
} |
449,38 → 450,38 |
// |
boolean |
P_TryMove |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
( mobj_t* thing, |
fixed_t x, |
fixed_t y ) |
{ |
fixed_t oldx; |
fixed_t oldy; |
int side; |
int oldside; |
line_t* ld; |
fixed_t oldx; |
fixed_t oldy; |
int side; |
int oldside; |
line_t* ld; |
floatok = false; |
if (!P_CheckPosition (thing, x, y)) |
return false; // solid wall or thing |
return false; // solid wall or thing |
if ( !(thing->flags & MF_NOCLIP) ) |
{ |
if (tmceilingz - tmfloorz < thing->height) |
return false; // doesn't fit |
if (tmceilingz - tmfloorz < thing->height) |
return false; // doesn't fit |
floatok = true; |
if ( !(thing->flags&MF_TELEPORT) |
&&tmceilingz - thing->z < thing->height) |
return false; // mobj must lower itself to fit |
floatok = true; |
if ( !(thing->flags&MF_TELEPORT) |
&&tmceilingz - thing->z < thing->height) |
return false; // mobj must lower itself to fit |
if ( !(thing->flags&MF_TELEPORT) |
&& tmfloorz - thing->z > 24*FRACUNIT ) |
return false; // too big a step up |
if ( !(thing->flags&MF_TELEPORT) |
&& tmfloorz - thing->z > 24*FRACUNIT ) |
return false; // too big a step up |
if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT)) |
&& tmfloorz - tmdropoffz > 24*FRACUNIT ) |
return false; // don't stand over a dropoff |
if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT)) |
&& tmfloorz - tmdropoffz > 24*FRACUNIT ) |
return false; // don't stand over a dropoff |
} |
// the move is ok, |
490,7 → 491,7 |
oldx = thing->x; |
oldy = thing->y; |
thing->floorz = tmfloorz; |
thing->ceilingz = tmceilingz; |
thing->ceilingz = tmceilingz; |
thing->x = x; |
thing->y = y; |
499,18 → 500,18 |
// if any special lines were hit, do the effect |
if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) |
{ |
while (numspechit--) |
{ |
// see if the line was crossed |
ld = spechit[numspechit]; |
side = P_PointOnLineSide (thing->x, thing->y, ld); |
oldside = P_PointOnLineSide (oldx, oldy, ld); |
if (side != oldside) |
{ |
if (ld->special) |
P_CrossSpecialLine (ld-lines, oldside, thing); |
} |
} |
while (numspechit--) |
{ |
// see if the line was crossed |
ld = spechit[numspechit]; |
side = P_PointOnLineSide (thing->x, thing->y, ld); |
oldside = P_PointOnLineSide (oldx, oldy, ld); |
if (side != oldside) |
{ |
if (ld->special) |
P_CrossSpecialLine (ld-lines, oldside, thing); |
} |
} |
} |
return true; |
529,31 → 530,31 |
// |
boolean P_ThingHeightClip (mobj_t* thing) |
{ |
boolean onfloor; |
boolean onfloor; |
onfloor = (thing->z == thing->floorz); |
P_CheckPosition (thing, thing->x, thing->y); |
P_CheckPosition (thing, thing->x, thing->y); |
// what about stranding a monster partially off an edge? |
thing->floorz = tmfloorz; |
thing->ceilingz = tmceilingz; |
if (onfloor) |
{ |
// walking monsters rise and fall with the floor |
thing->z = thing->floorz; |
// walking monsters rise and fall with the floor |
thing->z = thing->floorz; |
} |
else |
{ |
// don't adjust a floating monster unless forced to |
if (thing->z+thing->height > thing->ceilingz) |
thing->z = thing->ceilingz - thing->height; |
// don't adjust a floating monster unless forced to |
if (thing->z+thing->height > thing->ceilingz) |
thing->z = thing->ceilingz - thing->height; |
} |
if (thing->ceilingz - thing->floorz < thing->height) |
return false; |
return false; |
return true; |
} |
563,16 → 564,16 |
// SLIDE MOVE |
// Allows the player to slide along any angled walls. |
// |
fixed_t bestslidefrac; |
fixed_t secondslidefrac; |
fixed_t bestslidefrac; |
fixed_t secondslidefrac; |
line_t* bestslideline; |
line_t* secondslideline; |
line_t* bestslideline; |
line_t* secondslideline; |
mobj_t* slidemo; |
mobj_t* slidemo; |
fixed_t tmxmove; |
fixed_t tmymove; |
fixed_t tmxmove; |
fixed_t tmymove; |
583,50 → 584,50 |
// |
void P_HitSlideLine (line_t* ld) |
{ |
int side; |
int side; |
angle_t lineangle; |
angle_t moveangle; |
angle_t deltaangle; |
angle_t lineangle; |
angle_t moveangle; |
angle_t deltaangle; |
fixed_t movelen; |
fixed_t newlen; |
fixed_t movelen; |
fixed_t newlen; |
if (ld->slopetype == ST_HORIZONTAL) |
{ |
tmymove = 0; |
return; |
tmymove = 0; |
return; |
} |
if (ld->slopetype == ST_VERTICAL) |
{ |
tmxmove = 0; |
return; |
tmxmove = 0; |
return; |
} |
side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); |
lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); |
if (side == 1) |
lineangle += ANG180; |
lineangle += ANG180; |
moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); |
deltaangle = moveangle-lineangle; |
if (deltaangle > ANG180) |
deltaangle += ANG180; |
// I_Error ("SlideLine: ang>ANG180"); |
deltaangle += ANG180; |
// I_Error ("SlideLine: ang>ANG180"); |
lineangle >>= ANGLETOFINESHIFT; |
deltaangle >>= ANGLETOFINESHIFT; |
movelen = P_AproxDistance (tmxmove, tmymove); |
newlen = FixedMul (movelen, finecosine[deltaangle]); |
tmxmove = FixedMul (newlen, finecosine[lineangle]); |
tmymove = FixedMul (newlen, finesine[lineangle]); |
tmxmove = FixedMul (newlen, finecosine[lineangle]); |
tmymove = FixedMul (newlen, finesine[lineangle]); |
} |
635,21 → 636,21 |
// |
boolean PTR_SlideTraverse (intercept_t* in) |
{ |
line_t* li; |
line_t* li; |
if (!in->isaline) |
I_Error ("PTR_SlideTraverse: not a line?"); |
I_Error ("PTR_SlideTraverse: not a line?"); |
li = in->d.line; |
if ( ! (li->flags & ML_TWOSIDED) ) |
{ |
if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) |
{ |
// don't hit the back side |
return true; |
} |
goto isblocking; |
if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) |
{ |
// don't hit the back side |
return true; |
} |
goto isblocking; |
} |
// set openrange, opentop, openbottom |
656,29 → 657,29 |
P_LineOpening (li); |
if (openrange < slidemo->height) |
goto isblocking; // doesn't fit |
goto isblocking; // doesn't fit |
if (opentop - slidemo->z < slidemo->height) |
goto isblocking; // mobj is too high |
goto isblocking; // mobj is too high |
if (openbottom - slidemo->z > 24*FRACUNIT ) |
goto isblocking; // too big a step up |
goto isblocking; // too big a step up |
// this line doesn't block movement |
return true; |
return true; |
// the line does block movement, |
// see if it is closer than best so far |
isblocking: |
isblocking: |
if (in->frac < bestslidefrac) |
{ |
secondslidefrac = bestslidefrac; |
secondslideline = bestslideline; |
bestslidefrac = in->frac; |
bestslideline = li; |
secondslidefrac = bestslidefrac; |
secondslideline = bestslideline; |
bestslidefrac = in->frac; |
bestslideline = li; |
} |
return false; // stop |
return false; // stop |
} |
694,73 → 695,73 |
// |
void P_SlideMove (mobj_t* mo) |
{ |
fixed_t leadx; |
fixed_t leady; |
fixed_t trailx; |
fixed_t traily; |
fixed_t newx; |
fixed_t newy; |
int hitcount; |
fixed_t leadx; |
fixed_t leady; |
fixed_t trailx; |
fixed_t traily; |
fixed_t newx; |
fixed_t newy; |
int hitcount; |
slidemo = mo; |
hitcount = 0; |
retry: |
if (++hitcount == 3) |
goto stairstep; // don't loop forever |
goto stairstep; // don't loop forever |
// trace along the three leading corners |
if (mo->momx > 0) |
{ |
leadx = mo->x + mo->radius; |
trailx = mo->x - mo->radius; |
leadx = mo->x + mo->radius; |
trailx = mo->x - mo->radius; |
} |
else |
{ |
leadx = mo->x - mo->radius; |
trailx = mo->x + mo->radius; |
leadx = mo->x - mo->radius; |
trailx = mo->x + mo->radius; |
} |
if (mo->momy > 0) |
{ |
leady = mo->y + mo->radius; |
traily = mo->y - mo->radius; |
leady = mo->y + mo->radius; |
traily = mo->y - mo->radius; |
} |
else |
{ |
leady = mo->y - mo->radius; |
traily = mo->y + mo->radius; |
leady = mo->y - mo->radius; |
traily = mo->y + mo->radius; |
} |
bestslidefrac = FRACUNIT+1; |
P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy, |
PT_ADDLINES, PTR_SlideTraverse ); |
PT_ADDLINES, PTR_SlideTraverse ); |
P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy, |
PT_ADDLINES, PTR_SlideTraverse ); |
PT_ADDLINES, PTR_SlideTraverse ); |
P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy, |
PT_ADDLINES, PTR_SlideTraverse ); |
PT_ADDLINES, PTR_SlideTraverse ); |
// move up to the wall |
if (bestslidefrac == FRACUNIT+1) |
{ |
// the move most have hit the middle, so stairstep |
// the move most have hit the middle, so stairstep |
stairstep: |
if (!P_TryMove (mo, mo->x, mo->y + mo->momy)) |
P_TryMove (mo, mo->x + mo->momx, mo->y); |
return; |
if (!P_TryMove (mo, mo->x, mo->y + mo->momy)) |
P_TryMove (mo, mo->x + mo->momx, mo->y); |
return; |
} |
// fudge a bit to make sure it doesn't hit |
bestslidefrac -= 0x800; |
bestslidefrac -= 0x800; |
if (bestslidefrac > 0) |
{ |
newx = FixedMul (mo->momx, bestslidefrac); |
newy = FixedMul (mo->momy, bestslidefrac); |
if (!P_TryMove (mo, mo->x+newx, mo->y+newy)) |
goto stairstep; |
newx = FixedMul (mo->momx, bestslidefrac); |
newy = FixedMul (mo->momy, bestslidefrac); |
if (!P_TryMove (mo, mo->x+newx, mo->y+newy)) |
goto stairstep; |
} |
// Now continue along the wall. |
768,22 → 769,22 |
bestslidefrac = FRACUNIT-(bestslidefrac+0x800); |
if (bestslidefrac > FRACUNIT) |
bestslidefrac = FRACUNIT; |
bestslidefrac = FRACUNIT; |
if (bestslidefrac <= 0) |
return; |
return; |
tmxmove = FixedMul (mo->momx, bestslidefrac); |
tmymove = FixedMul (mo->momy, bestslidefrac); |
P_HitSlideLine (bestslideline); // clip the moves |
P_HitSlideLine (bestslideline); // clip the moves |
mo->momx = tmxmove; |
mo->momy = tmymove; |
if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove)) |
{ |
goto retry; |
goto retry; |
} |
} |
791,21 → 792,21 |
// |
// P_LineAttack |
// |
mobj_t* linetarget; // who got hit (or NULL) |
mobj_t* shootthing; |
mobj_t* linetarget; // who got hit (or NULL) |
mobj_t* shootthing; |
// Height if not aiming up or down |
// ???: use slope for monsters? |
fixed_t shootz; |
fixed_t shootz; |
int la_damage; |
fixed_t attackrange; |
int la_damage; |
fixed_t attackrange; |
fixed_t aimslope; |
fixed_t aimslope; |
// slopes to top and bottom of target |
extern fixed_t topslope; |
extern fixed_t bottomslope; |
extern fixed_t topslope; |
extern fixed_t bottomslope; |
// |
815,57 → 816,57 |
boolean |
PTR_AimTraverse (intercept_t* in) |
{ |
line_t* li; |
mobj_t* th; |
fixed_t slope; |
fixed_t thingtopslope; |
fixed_t thingbottomslope; |
fixed_t dist; |
line_t* li; |
mobj_t* th; |
fixed_t slope; |
fixed_t thingtopslope; |
fixed_t thingbottomslope; |
fixed_t dist; |
if (in->isaline) |
{ |
li = in->d.line; |
if ( !(li->flags & ML_TWOSIDED) ) |
return false; // stop |
// Crosses a two sided line. |
// A two sided line will restrict |
// the possible target ranges. |
P_LineOpening (li); |
if (openbottom >= opentop) |
return false; // stop |
dist = FixedMul (attackrange, in->frac); |
li = in->d.line; |
if ( !(li->flags & ML_TWOSIDED) ) |
return false; // stop |
// Crosses a two sided line. |
// A two sided line will restrict |
// the possible target ranges. |
P_LineOpening (li); |
if (openbottom >= opentop) |
return false; // stop |
dist = FixedMul (attackrange, in->frac); |
if (li->frontsector->floorheight != li->backsector->floorheight) |
{ |
slope = FixedDiv (openbottom - shootz , dist); |
if (slope > bottomslope) |
bottomslope = slope; |
} |
if (li->frontsector->ceilingheight != li->backsector->ceilingheight) |
{ |
slope = FixedDiv (opentop - shootz , dist); |
if (slope < topslope) |
topslope = slope; |
} |
if (topslope <= bottomslope) |
return false; // stop |
return true; // shot continues |
if (li->frontsector->floorheight != li->backsector->floorheight) |
{ |
slope = FixedDiv (openbottom - shootz , dist); |
if (slope > bottomslope) |
bottomslope = slope; |
} |
if (li->frontsector->ceilingheight != li->backsector->ceilingheight) |
{ |
slope = FixedDiv (opentop - shootz , dist); |
if (slope < topslope) |
topslope = slope; |
} |
if (topslope <= bottomslope) |
return false; // stop |
return true; // shot continues |
} |
// shoot a thing |
th = in->d.thing; |
if (th == shootthing) |
return true; // can't shoot self |
return true; // can't shoot self |
if (!(th->flags&MF_SHOOTABLE)) |
return true; // corpse or something |
return true; // corpse or something |
// check angles to see if the thing can be aimed at |
dist = FixedMul (attackrange, in->frac); |
872,24 → 873,24 |
thingtopslope = FixedDiv (th->z+th->height - shootz , dist); |
if (thingtopslope < bottomslope) |
return true; // shot over the thing |
return true; // shot over the thing |
thingbottomslope = FixedDiv (th->z - shootz, dist); |
if (thingbottomslope > topslope) |
return true; // shot under the thing |
return true; // shot under the thing |
// this thing can be hit! |
if (thingtopslope > topslope) |
thingtopslope = topslope; |
thingtopslope = topslope; |
if (thingbottomslope < bottomslope) |
thingbottomslope = bottomslope; |
thingbottomslope = bottomslope; |
aimslope = (thingtopslope+thingbottomslope)/2; |
linetarget = th; |
return false; // don't go any farther |
return false; // don't go any farther |
} |
898,98 → 899,98 |
// |
boolean PTR_ShootTraverse (intercept_t* in) |
{ |
fixed_t x; |
fixed_t y; |
fixed_t z; |
fixed_t frac; |
fixed_t x; |
fixed_t y; |
fixed_t z; |
fixed_t frac; |
line_t* li; |
line_t* li; |
mobj_t* th; |
mobj_t* th; |
fixed_t slope; |
fixed_t dist; |
fixed_t thingtopslope; |
fixed_t thingbottomslope; |
fixed_t slope; |
fixed_t dist; |
fixed_t thingtopslope; |
fixed_t thingbottomslope; |
if (in->isaline) |
{ |
li = in->d.line; |
if (li->special) |
P_ShootSpecialLine (shootthing, li); |
li = in->d.line; |
if (li->special) |
P_ShootSpecialLine (shootthing, li); |
if ( !(li->flags & ML_TWOSIDED) ) |
goto hitline; |
// crosses a two sided line |
P_LineOpening (li); |
dist = FixedMul (attackrange, in->frac); |
if ( !(li->flags & ML_TWOSIDED) ) |
goto hitline; |
// crosses a two sided line |
P_LineOpening (li); |
dist = FixedMul (attackrange, in->frac); |
if (li->frontsector->floorheight != li->backsector->floorheight) |
{ |
slope = FixedDiv (openbottom - shootz , dist); |
if (slope > aimslope) |
goto hitline; |
} |
if (li->frontsector->ceilingheight != li->backsector->ceilingheight) |
{ |
slope = FixedDiv (opentop - shootz , dist); |
if (slope < aimslope) |
goto hitline; |
} |
if (li->frontsector->floorheight != li->backsector->floorheight) |
{ |
slope = FixedDiv (openbottom - shootz , dist); |
if (slope > aimslope) |
goto hitline; |
} |
if (li->frontsector->ceilingheight != li->backsector->ceilingheight) |
{ |
slope = FixedDiv (opentop - shootz , dist); |
if (slope < aimslope) |
goto hitline; |
} |
// shot continues |
return true; |
// hit line |
// shot continues |
return true; |
// hit line |
hitline: |
// position a bit closer |
frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); |
x = trace.x + FixedMul (trace.dx, frac); |
y = trace.y + FixedMul (trace.dy, frac); |
z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); |
// position a bit closer |
frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); |
x = trace.x + FixedMul (trace.dx, frac); |
y = trace.y + FixedMul (trace.dy, frac); |
z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); |
if (li->frontsector->ceilingpic == skyflatnum) |
{ |
// don't shoot the sky! |
if (z > li->frontsector->ceilingheight) |
return false; |
// it's a sky hack wall |
if (li->backsector && li->backsector->ceilingpic == skyflatnum) |
return false; |
} |
if (li->frontsector->ceilingpic == skyflatnum) |
{ |
// don't shoot the sky! |
if (z > li->frontsector->ceilingheight) |
return false; |
// it's a sky hack wall |
if (li->backsector && li->backsector->ceilingpic == skyflatnum) |
return false; |
} |
// Spawn bullet puffs. |
P_SpawnPuff (x,y,z); |
// don't go any farther |
return false; |
// Spawn bullet puffs. |
P_SpawnPuff (x,y,z); |
// don't go any farther |
return false; |
} |
// shoot a thing |
th = in->d.thing; |
if (th == shootthing) |
return true; // can't shoot self |
return true; // can't shoot self |
if (!(th->flags&MF_SHOOTABLE)) |
return true; // corpse or something |
return true; // corpse or something |
// check angles to see if the thing can be aimed at |
dist = FixedMul (attackrange, in->frac); |
thingtopslope = FixedDiv (th->z+th->height - shootz , dist); |
if (thingtopslope < aimslope) |
return true; // shot over the thing |
return true; // shot over the thing |
thingbottomslope = FixedDiv (th->z - shootz, dist); |
if (thingbottomslope > aimslope) |
return true; // shot under the thing |
return true; // shot under the thing |
// hit thing |
1003,16 → 1004,16 |
// Spawn bullet puffs or blod spots, |
// depending on target type. |
if (in->d.thing->flags & MF_NOBLOOD) |
P_SpawnPuff (x,y,z); |
P_SpawnPuff (x,y,z); |
else |
P_SpawnBlood (x,y,z, la_damage); |
P_SpawnBlood (x,y,z, la_damage); |
if (la_damage) |
P_DamageMobj (th, shootthing, shootthing, la_damage); |
P_DamageMobj (th, shootthing, shootthing, la_damage); |
// don't go any farther |
return false; |
} |
1021,13 → 1022,13 |
// |
fixed_t |
P_AimLineAttack |
( mobj_t* t1, |
angle_t angle, |
fixed_t distance ) |
( mobj_t* t1, |
angle_t angle, |
fixed_t distance ) |
{ |
fixed_t x2; |
fixed_t y2; |
fixed_t x2; |
fixed_t y2; |
angle >>= ANGLETOFINESHIFT; |
shootthing = t1; |
1036,19 → 1037,19 |
shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; |
// can't shoot outside view angles |
topslope = 100*FRACUNIT/160; |
topslope = 100*FRACUNIT/160; |
bottomslope = -100*FRACUNIT/160; |
attackrange = distance; |
linetarget = NULL; |
P_PathTraverse ( t1->x, t1->y, |
x2, y2, |
PT_ADDLINES|PT_ADDTHINGS, |
PTR_AimTraverse ); |
x2, y2, |
PT_ADDLINES|PT_ADDTHINGS, |
PTR_AimTraverse ); |
if (linetarget) |
return aimslope; |
return aimslope; |
return 0; |
} |
1061,15 → 1062,15 |
// |
void |
P_LineAttack |
( mobj_t* t1, |
angle_t angle, |
fixed_t distance, |
fixed_t slope, |
int damage ) |
( mobj_t* t1, |
angle_t angle, |
fixed_t distance, |
fixed_t slope, |
int damage ) |
{ |
fixed_t x2; |
fixed_t y2; |
fixed_t x2; |
fixed_t y2; |
angle >>= ANGLETOFINESHIFT; |
shootthing = t1; |
la_damage = damage; |
1078,11 → 1079,11 |
shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; |
attackrange = distance; |
aimslope = slope; |
P_PathTraverse ( t1->x, t1->y, |
x2, y2, |
PT_ADDLINES|PT_ADDTHINGS, |
PTR_ShootTraverse ); |
x2, y2, |
PT_ADDLINES|PT_ADDTHINGS, |
PTR_ShootTraverse ); |
} |
1090,32 → 1091,32 |
// |
// USE LINES |
// |
mobj_t* usething; |
mobj_t* usething; |
boolean PTR_UseTraverse (intercept_t* in) |
boolean PTR_UseTraverse (intercept_t* in) |
{ |
int side; |
int side; |
if (!in->d.line->special) |
{ |
P_LineOpening (in->d.line); |
if (openrange <= 0) |
{ |
S_StartSound (usething, sfx_noway); |
// can't use through a wall |
return false; |
} |
// not a special line, but keep checking |
return true ; |
P_LineOpening (in->d.line); |
if (openrange <= 0) |
{ |
S_StartSound (usething, sfx_noway); |
// can't use through a wall |
return false; |
} |
// not a special line, but keep checking |
return true ; |
} |
side = 0; |
if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) |
side = 1; |
side = 1; |
// return false; // don't use back side |
// return false; // don't use back side |
P_UseSpecialLine (usething, in->d.line, side); |
// can't use for than one special line in a row |
1127,16 → 1128,16 |
// P_UseLines |
// Looks for special lines in front of the player to activate. |
// |
void P_UseLines (player_t* player) |
void P_UseLines (player_t* player) |
{ |
int angle; |
fixed_t x1; |
fixed_t y1; |
fixed_t x2; |
fixed_t y2; |
int angle; |
fixed_t x1; |
fixed_t y1; |
fixed_t x2; |
fixed_t y2; |
usething = player->mo; |
angle = player->mo->angle >> ANGLETOFINESHIFT; |
x1 = player->mo->x; |
1143,7 → 1144,7 |
y1 = player->mo->y; |
x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; |
y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; |
P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); |
} |
1151,9 → 1152,9 |
// |
// RADIUS ATTACK |
// |
mobj_t* bombsource; |
mobj_t* bombspot; |
int bombdamage; |
mobj_t* bombsource; |
mobj_t* bombspot; |
int bombdamage; |
// |
1163,19 → 1164,19 |
// |
boolean PIT_RadiusAttack (mobj_t* thing) |
{ |
fixed_t dx; |
fixed_t dy; |
fixed_t dist; |
fixed_t dx; |
fixed_t dy; |
fixed_t dist; |
if (!(thing->flags & MF_SHOOTABLE) ) |
return true; |
return true; |
// Boss spider and cyborg |
// take no damage from concussion. |
if (thing->type == MT_CYBORG |
|| thing->type == MT_SPIDER) |
return true; |
|| thing->type == MT_SPIDER) |
return true; |
dx = abs(thing->x - bombspot->x); |
dy = abs(thing->y - bombspot->y); |
1183,15 → 1184,15 |
dist = (dist - thing->radius) >> FRACBITS; |
if (dist < 0) |
dist = 0; |
dist = 0; |
if (dist >= bombdamage) |
return true; // out of range |
return true; // out of range |
if ( P_CheckSight (thing, bombspot) ) |
{ |
// must be in direct path |
P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); |
// must be in direct path |
P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); |
} |
return true; |
1204,20 → 1205,20 |
// |
void |
P_RadiusAttack |
( mobj_t* spot, |
mobj_t* source, |
int damage ) |
( mobj_t* spot, |
mobj_t* source, |
int damage ) |
{ |
int x; |
int y; |
int x; |
int y; |
int xl; |
int xh; |
int yl; |
int yh; |
int xl; |
int xh; |
int yl; |
int yh; |
fixed_t dist; |
fixed_t dist; |
dist = (damage+MAXRADIUS)<<FRACBITS; |
yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT; |
yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; |
1226,10 → 1227,10 |
bombspot = spot; |
bombsource = source; |
bombdamage = damage; |
for (y=yl ; y<=yh ; y++) |
for (x=xl ; x<=xh ; x++) |
P_BlockThingsIterator (x, y, PIT_RadiusAttack ); |
for (x=xl ; x<=xh ; x++) |
P_BlockThingsIterator (x, y, PIT_RadiusAttack ); |
} |
1247,21 → 1248,21 |
// the way it was and call P_ChangeSector again |
// to undo the changes. |
// |
boolean crushchange; |
boolean nofit; |
boolean crushchange; |
boolean nofit; |
// |
// PIT_ChangeSector |
// |
boolean PIT_ChangeSector (mobj_t* thing) |
boolean PIT_ChangeSector (mobj_t* thing) |
{ |
mobj_t* mo; |
mobj_t* mo; |
if (P_ThingHeightClip (thing)) |
{ |
// keep checking |
return true; |
// keep checking |
return true; |
} |
1268,29 → 1269,29 |
// crunch bodies to giblets |
if (thing->health <= 0) |
{ |
P_SetMobjState (thing, S_GIBS); |
P_SetMobjState (thing, S_GIBS); |
thing->flags &= ~MF_SOLID; |
thing->height = 0; |
thing->radius = 0; |
thing->flags &= ~MF_SOLID; |
thing->height = 0; |
thing->radius = 0; |
// keep checking |
return true; |
// keep checking |
return true; |
} |
// crunch dropped items |
if (thing->flags & MF_DROPPED) |
{ |
P_RemoveMobj (thing); |
// keep checking |
return true; |
P_RemoveMobj (thing); |
// keep checking |
return true; |
} |
if (! (thing->flags & MF_SHOOTABLE) ) |
{ |
// assume it is bloody gibs or something |
return true; |
// assume it is bloody gibs or something |
return true; |
} |
nofit = true; |
1297,19 → 1298,19 |
if (crushchange && !(leveltime&3) ) |
{ |
P_DamageMobj(thing,NULL,NULL,10); |
P_DamageMobj(thing,NULL,NULL,10); |
// spray blood in a random direction |
mo = P_SpawnMobj (thing->x, |
thing->y, |
thing->z + thing->height/2, MT_BLOOD); |
mo->momx = (P_Random() - P_Random ())<<12; |
mo->momy = (P_Random() - P_Random ())<<12; |
// spray blood in a random direction |
mo = P_SpawnMobj (thing->x, |
thing->y, |
thing->z + thing->height/2, MT_BLOOD); |
mo->momx = (P_Random() - P_Random ())<<12; |
mo->momy = (P_Random() - P_Random ())<<12; |
} |
// keep checking (crush other things) |
return true; |
// keep checking (crush other things) |
return true; |
} |
1319,21 → 1320,21 |
// |
boolean |
P_ChangeSector |
( sector_t* sector, |
boolean crunch ) |
( sector_t* sector, |
boolean crunch ) |
{ |
int x; |
int y; |
int x; |
int y; |
nofit = false; |
crushchange = crunch; |
// re-check heights for all things near the moving sector |
for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) |
for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) |
P_BlockThingsIterator (x, y, PIT_ChangeSector); |
for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) |
P_BlockThingsIterator (x, y, PIT_ChangeSector); |
return nofit; |
} |
/programs/games/doom/trunk/p_telept.c |
---|
17,7 → 17,7 |
// $Log:$ |
// |
// DESCRIPTION: |
// Teleportation. |
// Teleportation. |
// |
//----------------------------------------------------------------------------- |
25,7 → 25,7 |
rcsid[] = "$Id: p_telept.c,v 1.3 1997/01/28 22:08:29 b1 Exp $"; |
#include "doomtype.h" |
#include "doomdef.h" |
#include "s_sound.h" |
46,86 → 46,86 |
// |
int |
EV_Teleport |
( line_t* line, |
int side, |
mobj_t* thing ) |
( line_t* line, |
int side, |
mobj_t* thing ) |
{ |
int i; |
int tag; |
mobj_t* m; |
mobj_t* fog; |
unsigned an; |
thinker_t* thinker; |
sector_t* sector; |
fixed_t oldx; |
fixed_t oldy; |
fixed_t oldz; |
int i; |
int tag; |
mobj_t* m; |
mobj_t* fog; |
unsigned an; |
thinker_t* thinker; |
sector_t* sector; |
fixed_t oldx; |
fixed_t oldy; |
fixed_t oldz; |
// don't teleport missiles |
if (thing->flags & MF_MISSILE) |
return 0; |
return 0; |
// Don't teleport if hit back of line, |
// so you can get out of teleporter. |
if (side == 1) |
return 0; |
if (side == 1) |
return 0; |
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) |
{ |
// not a mobj |
if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) |
continue; |
if (sectors[ i ].tag == tag ) |
{ |
thinker = thinkercap.next; |
for (thinker = thinkercap.next; |
thinker != &thinkercap; |
thinker = thinker->next) |
{ |
// not a mobj |
if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) |
continue; |
m = (mobj_t *)thinker; |
// not a teleportman |
if (m->type != MT_TELEPORTMAN ) |
continue; |
m = (mobj_t *)thinker; |
// not a teleportman |
if (m->type != MT_TELEPORTMAN ) |
continue; |
sector = m->subsector->sector; |
// wrong sector |
if (sector-sectors != i ) |
continue; |
sector = m->subsector->sector; |
// wrong sector |
if (sector-sectors != i ) |
continue; |
oldx = thing->x; |
oldy = thing->y; |
oldz = thing->z; |
if (!P_TeleportMove (thing, m->x, m->y)) |
return 0; |
thing->z = thing->floorz; //fixme: not needed? |
if (thing->player) |
thing->player->viewz = thing->z+thing->player->viewheight; |
// spawn teleport fog at source and destination |
fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); |
S_StartSound (fog, sfx_telept); |
an = m->angle >> ANGLETOFINESHIFT; |
fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an] |
, thing->z, MT_TFOG); |
oldx = thing->x; |
oldy = thing->y; |
oldz = thing->z; |
if (!P_TeleportMove (thing, m->x, m->y)) |
return 0; |
thing->z = thing->floorz; //fixme: not needed? |
if (thing->player) |
thing->player->viewz = thing->z+thing->player->viewheight; |
// spawn teleport fog at source and destination |
fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); |
S_StartSound (fog, sfx_telept); |
an = m->angle >> ANGLETOFINESHIFT; |
fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an] |
, thing->z, MT_TFOG); |
// emit sound, where? |
S_StartSound (fog, sfx_telept); |
// don't move for a bit |
if (thing->player) |
thing->reactiontime = 18; |
// emit sound, where? |
S_StartSound (fog, sfx_telept); |
// don't move for a bit |
if (thing->player) |
thing->reactiontime = 18; |
thing->angle = m->angle; |
thing->momx = thing->momy = thing->momz = 0; |
return 1; |
} |
} |
thing->angle = m->angle; |
thing->momx = thing->momy = thing->momz = 0; |
return 1; |
} |
} |
} |
return 0; |
} |
/programs/games/doom/trunk/r_draw.c |
---|
17,9 → 17,9 |
// $Log:$ |
// |
// DESCRIPTION: |
// The actual span/column drawing functions. |
// Here find the main potential for optimization, |
// e.g. inline assembly, different algorithms. |
// The actual span/column drawing functions. |
// Here find the main potential for optimization, |
// e.g. inline assembly, different algorithms. |
// |
//----------------------------------------------------------------------------- |
27,7 → 27,7 |
static const char |
rcsid[] = "$Id: r_draw.c,v 1.4 1997/02/03 16:47:55 b1 Exp $"; |
#include "doomtype.h" |
#include "doomdef.h" |
#include "i_system.h" |
44,11 → 44,11 |
// ? |
#define MAXWIDTH 1120 |
#define MAXHEIGHT 832 |
#define MAXWIDTH 1120 |
#define MAXHEIGHT 832 |
// status bar height at bottom of screen |
#define SBARHEIGHT 32 |
#define SBARHEIGHT 32 |
// |
// All drawing to the view buffer is accomplished in this file. |
60,20 → 60,20 |
// |
byte* viewimage; |
int viewwidth; |
int scaledviewwidth; |
int viewheight; |
int viewwindowx; |
int viewwindowy; |
byte* ylookup[MAXHEIGHT]; |
int columnofs[MAXWIDTH]; |
byte* viewimage; |
int viewwidth; |
int scaledviewwidth; |
int viewheight; |
int viewwindowx; |
int viewwindowy; |
byte* ylookup[MAXHEIGHT]; |
int columnofs[MAXWIDTH]; |
// Color tables for different players, |
// translate a limited part to another |
// (color ramps used for suit colors). |
// |
byte translations[3][256]; |
byte translations[3][256]; |
82,18 → 82,18 |
// 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; |
lighttable_t* dc_colormap; |
int dc_x; |
int dc_yl; |
int dc_yh; |
fixed_t dc_iscale; |
fixed_t dc_texturemid; |
// first pixel in a column (possibly virtual) |
byte* dc_source; |
byte* dc_source; |
// just for profiling |
int dccount; |
int dccount; |
// |
// A column is a vertical slice/span from a wall texture that, |
104,22 → 104,22 |
// |
void R_DrawColumn (void) |
{ |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
count = dc_yh - dc_yl; |
// Zero length, column does not exceed a pixel. |
if (count < 0) |
return; |
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); |
|| dc_yl < 0 |
|| dc_yh >= SCREENHEIGHT) |
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); |
#endif |
// Framebuffer destination address. |
137,13 → 137,13 |
// This is as fast as it gets. |
do |
{ |
// Re-map color indices from wall texture column |
// using a lighting/special effects LUT. |
*dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
// Re-map color indices from wall texture column |
// using a lighting/special effects LUT. |
*dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
} while (count--); |
} |
154,23 → 154,23 |
#if 0 |
void R_DrawColumn (void) |
{ |
int count; |
byte* source; |
byte* dest; |
byte* colormap; |
int count; |
byte* source; |
byte* dest; |
byte* colormap; |
unsigned frac; |
unsigned fracstep; |
unsigned fracstep2; |
unsigned fracstep3; |
unsigned fracstep4; |
unsigned frac; |
unsigned fracstep; |
unsigned fracstep2; |
unsigned fracstep3; |
unsigned fracstep4; |
count = dc_yh - dc_yl + 1; |
source = dc_source; |
colormap = dc_colormap; |
colormap = dc_colormap; |
dest = ylookup[dc_yl] + columnofs[dc_x]; |
fracstep = dc_iscale<<9; |
frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9; |
177,32 → 177,32 |
fracstep2 = fracstep+fracstep; |
fracstep3 = fracstep2+fracstep; |
fracstep4 = fracstep3+fracstep; |
while (count >= 8) |
{ |
dest[0] = colormap[source[frac>>25]]; |
dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]]; |
dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]]; |
dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]]; |
frac += fracstep4; |
dest[0] = colormap[source[frac>>25]]; |
dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]]; |
dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]]; |
dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]]; |
frac += fracstep4; |
dest[SCREENWIDTH*4] = colormap[source[frac>>25]]; |
dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]]; |
dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]]; |
dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]]; |
dest[SCREENWIDTH*4] = colormap[source[frac>>25]]; |
dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]]; |
dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]]; |
dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]]; |
frac += fracstep4; |
dest += SCREENWIDTH*8; |
count -= 8; |
frac += fracstep4; |
dest += SCREENWIDTH*8; |
count -= 8; |
} |
while (count > 0) |
{ |
*dest = colormap[source[frac>>25]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
count--; |
*dest = colormap[source[frac>>25]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
count--; |
} |
} |
#endif |
210,27 → 210,27 |
void R_DrawColumnLow (void) |
{ |
int count; |
byte* dest; |
byte* dest2; |
fixed_t frac; |
fixed_t fracstep; |
int count; |
byte* dest; |
byte* dest2; |
fixed_t frac; |
fixed_t fracstep; |
count = dc_yh - dc_yl; |
// Zero length. |
if (count < 0) |
return; |
return; |
#ifdef RANGECHECK |
if ((unsigned)dc_x >= SCREENWIDTH |
|| dc_yl < 0 |
|| dc_yh >= SCREENHEIGHT) |
|| dc_yl < 0 |
|| dc_yh >= SCREENHEIGHT) |
{ |
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); |
I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); |
} |
// dccount++; |
// dccount++; |
#endif |
// Blocky mode, need to multiply by 2. |
dc_x <<= 1; |
243,11 → 243,11 |
do |
{ |
// Hack. Does not work corretly. |
*dest2 = *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; |
dest += SCREENWIDTH; |
dest2 += SCREENWIDTH; |
frac += fracstep; |
// Hack. Does not work corretly. |
*dest2 = *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; |
dest += SCREENWIDTH; |
dest2 += SCREENWIDTH; |
frac += fracstep; |
} while (count--); |
} |
256,11 → 256,11 |
// |
// Spectre/Invisibility. |
// |
#define FUZZTABLE 50 |
#define FUZZOFF (SCREENWIDTH) |
#define FUZZTABLE 50 |
#define FUZZOFF (SCREENWIDTH) |
int fuzzoffset[FUZZTABLE] = |
int fuzzoffset[FUZZTABLE] = |
{ |
FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, |
FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, |
271,7 → 271,7 |
FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF |
}; |
int fuzzpos = 0; |
int fuzzpos = 0; |
// |
284,32 → 284,32 |
// |
void R_DrawFuzzColumn (void) |
{ |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
// Adjust borders. Low... |
if (!dc_yl) |
dc_yl = 1; |
dc_yl = 1; |
// .. and high. |
if (dc_yh == viewheight-1) |
dc_yh = viewheight - 2; |
dc_yh = viewheight - 2; |
count = dc_yh - dc_yl; |
// Zero length. |
if (count < 0) |
return; |
return; |
#ifdef RANGECHECK |
if ((unsigned)dc_x >= SCREENWIDTH |
|| dc_yl < 0 || dc_yh >= SCREENHEIGHT) |
|| dc_yl < 0 || dc_yh >= SCREENHEIGHT) |
{ |
I_Error ("R_DrawFuzzColumn: %i to %i at %i", |
dc_yl, dc_yh, dc_x); |
I_Error ("R_DrawFuzzColumn: %i to %i at %i", |
dc_yl, dc_yh, dc_x); |
} |
#endif |
319,23 → 319,23 |
/* WATCOM code |
if (detailshift) |
{ |
if (dc_x & 1) |
{ |
outpw (GC_INDEX,GC_READMAP+(2<<8) ); |
outp (SC_INDEX+1,12); |
} |
else |
{ |
outpw (GC_INDEX,GC_READMAP); |
outp (SC_INDEX+1,3); |
} |
dest = destview + dc_yl*80 + (dc_x>>1); |
if (dc_x & 1) |
{ |
outpw (GC_INDEX,GC_READMAP+(2<<8) ); |
outp (SC_INDEX+1,12); |
} |
else |
{ |
outpw (GC_INDEX,GC_READMAP); |
outp (SC_INDEX+1,3); |
} |
dest = destview + dc_yl*80 + (dc_x>>1); |
} |
else |
{ |
outpw (GC_INDEX,GC_READMAP+((dc_x&3)<<8) ); |
outp (SC_INDEX+1,1<<(dc_x&3)); |
dest = destview + dc_yl*80 + (dc_x>>2); |
outpw (GC_INDEX,GC_READMAP+((dc_x&3)<<8) ); |
outp (SC_INDEX+1,1<<(dc_x&3)); |
dest = destview + dc_yl*80 + (dc_x>>2); |
}*/ |
351,19 → 351,19 |
// brighter than average). |
do |
{ |
// Lookup framebuffer, and retrieve |
// a pixel that is either one column |
// left or right of the current one. |
// Add index from colormap to index. |
*dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; |
// Lookup framebuffer, and retrieve |
// a pixel that is either one column |
// left or right of the current one. |
// Add index from colormap to index. |
*dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; |
// Clamp table lookup index. |
if (++fuzzpos == FUZZTABLE) |
fuzzpos = 0; |
dest += SCREENWIDTH; |
// Clamp table lookup index. |
if (++fuzzpos == FUZZTABLE) |
fuzzpos = 0; |
dest += SCREENWIDTH; |
frac += fracstep; |
frac += fracstep; |
} while (count--); |
} |
379,27 → 379,27 |
// of the BaronOfHell, the HellKnight, uses |
// identical sprites, kinda brightened up. |
// |
byte* dc_translation; |
byte* translationtables; |
byte* dc_translation; |
byte* translationtables; |
void R_DrawTranslatedColumn (void) |
{ |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
int count; |
byte* dest; |
fixed_t frac; |
fixed_t fracstep; |
count = dc_yh - dc_yl; |
if (count < 0) |
return; |
return; |
#ifdef RANGECHECK |
if ((unsigned)dc_x >= SCREENWIDTH |
|| dc_yl < 0 |
|| dc_yh >= SCREENHEIGHT) |
|| dc_yl < 0 |
|| dc_yh >= SCREENHEIGHT) |
{ |
I_Error ( "R_DrawColumn: %i to %i at %i", |
dc_yl, dc_yh, dc_x); |
I_Error ( "R_DrawColumn: %i to %i at %i", |
dc_yl, dc_yh, dc_x); |
} |
#endif |
409,18 → 409,18 |
/* Keep for fixing. |
if (detailshift) |
{ |
if (dc_x & 1) |
outp (SC_INDEX+1,12); |
else |
outp (SC_INDEX+1,3); |
dest = destview + dc_yl*80 + (dc_x>>1); |
if (dc_x & 1) |
outp (SC_INDEX+1,12); |
else |
outp (SC_INDEX+1,3); |
dest = destview + dc_yl*80 + (dc_x>>1); |
} |
else |
{ |
outp (SC_INDEX+1,1<<(dc_x&3)); |
outp (SC_INDEX+1,1<<(dc_x&3)); |
dest = destview + dc_yl*80 + (dc_x>>2); |
dest = destview + dc_yl*80 + (dc_x>>2); |
}*/ |
434,15 → 434,15 |
// Here we do an additional index re-mapping. |
do |
{ |
// Translation tables are used |
// to map certain colorramps to other ones, |
// used with PLAY sprites. |
// Thus the "green" ramp of the player 0 sprite |
// is mapped to gray, red, black/indigo. |
*dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
// Translation tables are used |
// to map certain colorramps to other ones, |
// used with PLAY sprites. |
// Thus the "green" ramp of the player 0 sprite |
// is mapped to gray, red, black/indigo. |
*dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; |
dest += SCREENWIDTH; |
frac += fracstep; |
} while (count--); |
} |
458,8 → 458,8 |
// |
void R_InitTranslationTables (void) |
{ |
int i; |
int i; |
translationtables = Z_Malloc (256*3+255, PU_STATIC, 0); |
translationtables = (byte *)(( (int)translationtables + 255 )& ~255); |
466,19 → 466,19 |
// translate just the 16 green colors |
for (i=0 ; i<256 ; i++) |
{ |
if (i >= 0x70 && i<= 0x7f) |
{ |
// map green ramp to gray, brown, red |
translationtables[i] = 0x60 + (i&0xf); |
translationtables [i+256] = 0x40 + (i&0xf); |
translationtables [i+512] = 0x20 + (i&0xf); |
} |
else |
{ |
// Keep all other colors as is. |
translationtables[i] = translationtables[i+256] |
= translationtables[i+512] = i; |
} |
if (i >= 0x70 && i<= 0x7f) |
{ |
// map green ramp to gray, brown, red |
translationtables[i] = 0x60 + (i&0xf); |
translationtables [i+256] = 0x40 + (i&0xf); |
translationtables [i+512] = 0x20 + (i&0xf); |
} |
else |
{ |
// Keep all other colors as is. |
translationtables[i] = translationtables[i+256] |
= translationtables[i+512] = i; |
} |
} |
} |
497,22 → 497,22 |
// In consequence, flats are not stored by column (like walls), |
// and the inner loop has to step in texture space u and v. |
// |
int ds_y; |
int ds_x1; |
int ds_x2; |
int ds_y; |
int ds_x1; |
int ds_x2; |
lighttable_t* ds_colormap; |
lighttable_t* ds_colormap; |
fixed_t ds_xfrac; |
fixed_t ds_yfrac; |
fixed_t ds_xstep; |
fixed_t ds_ystep; |
fixed_t ds_xfrac; |
fixed_t ds_yfrac; |
fixed_t ds_xstep; |
fixed_t ds_ystep; |
// start of a 64*64 tile image |
byte* ds_source; |
byte* ds_source; |
// just for profiling |
int dscount; |
int dscount; |
// |
519,28 → 519,28 |
// Draws the actual span. |
void R_DrawSpan (void) |
{ |
fixed_t xfrac; |
fixed_t yfrac; |
byte* dest; |
int count; |
int spot; |
fixed_t xfrac; |
fixed_t yfrac; |
byte* dest; |
int count; |
int spot; |
#ifdef RANGECHECK |
if (ds_x2 < ds_x1 |
|| ds_x1<0 |
|| ds_x2>=SCREENWIDTH |
|| (unsigned)ds_y>SCREENHEIGHT) |
|| 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); |
I_Error( "R_DrawSpan: %i to %i at %i", |
ds_x1,ds_x2,ds_y); |
} |
// dscount++; |
// dscount++; |
#endif |
xfrac = ds_xfrac; |
yfrac = ds_yfrac; |
dest = ylookup[ds_y] + columnofs[ds_x1]; |
// We do not check for zero spans here? |
548,17 → 548,17 |
do |
{ |
// Current texture index in u,v. |
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); |
// Current texture index in u,v. |
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); |
// Lookup pixel from flat texture tile, |
// re-index using light/colormap. |
*dest++ = ds_colormap[ds_source[spot]]; |
// Lookup pixel from flat texture tile, |
// re-index using light/colormap. |
*dest++ = ds_colormap[ds_source[spot]]; |
// Next step in u,v. |
xfrac += ds_xstep; |
yfrac += ds_ystep; |
// Next step in u,v. |
xfrac += ds_xstep; |
yfrac += ds_ystep; |
} while (count--); |
} |
569,69 → 569,69 |
#if 0 |
void R_DrawSpan (void) |
{ |
unsigned position, step; |
unsigned position, step; |
byte* source; |
byte* colormap; |
byte* dest; |
byte* source; |
byte* colormap; |
byte* dest; |
unsigned count; |
usingned spot; |
unsigned value; |
unsigned temp; |
unsigned xtemp; |
unsigned ytemp; |
unsigned count; |
usingned spot; |
unsigned value; |
unsigned temp; |
unsigned xtemp; |
unsigned ytemp; |
position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff); |
step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff); |
source = ds_source; |
colormap = ds_colormap; |
dest = ylookup[ds_y] + columnofs[ds_x1]; |
dest = ylookup[ds_y] + columnofs[ds_x1]; |
count = ds_x2 - ds_x1 + 1; |
while (count >= 4) |
{ |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[0] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[0] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[1] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[2] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[3] = colormap[source[spot]]; |
count -= 4; |
dest += 4; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[1] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[2] = colormap[source[spot]]; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
dest[3] = colormap[source[spot]]; |
count -= 4; |
dest += 4; |
} |
while (count > 0) |
{ |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
*dest++ = colormap[source[spot]]; |
count--; |
ytemp = position>>4; |
ytemp = ytemp & 4032; |
xtemp = position>>26; |
spot = xtemp | ytemp; |
position += step; |
*dest++ = colormap[source[spot]]; |
count--; |
} |
} |
#endif |
642,24 → 642,24 |
// |
void R_DrawSpanLow (void) |
{ |
fixed_t xfrac; |
fixed_t yfrac; |
byte* dest; |
int count; |
int spot; |
fixed_t xfrac; |
fixed_t yfrac; |
byte* dest; |
int count; |
int spot; |
#ifdef RANGECHECK |
if (ds_x2 < ds_x1 |
|| ds_x1<0 |
|| ds_x2>=SCREENWIDTH |
|| (unsigned)ds_y>SCREENHEIGHT) |
|| 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); |
I_Error( "R_DrawSpan: %i to %i at %i", |
ds_x1,ds_x2,ds_y); |
} |
// dscount++; |
// dscount++; |
#endif |
xfrac = ds_xfrac; |
yfrac = ds_yfrac; |
673,14 → 673,14 |
count = ds_x2 - ds_x1; |
do |
{ |
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); |
// Lowres/blocky mode does it twice, |
// while scale is adjusted appropriately. |
*dest++ = ds_colormap[ds_source[spot]]; |
*dest++ = ds_colormap[ds_source[spot]]; |
xfrac += ds_xstep; |
yfrac += ds_ystep; |
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); |
// Lowres/blocky mode does it twice, |
// while scale is adjusted appropriately. |
*dest++ = ds_colormap[ds_source[spot]]; |
*dest++ = ds_colormap[ds_source[spot]]; |
xfrac += ds_xstep; |
yfrac += ds_ystep; |
} while (count--); |
} |
694,10 → 694,10 |
// |
void |
R_InitBuffer |
( int width, |
int height ) |
( int width, |
int height ) |
{ |
int i; |
int i; |
// Handle resize, |
// e.g. smaller view windows |
706,17 → 706,17 |
// Column offset. For windows. |
for (i=0 ; i<width ; i++) |
columnofs[i] = viewwindowx + i; |
columnofs[i] = viewwindowx + i; |
// Samw with base row offset. |
if (width == SCREENWIDTH) |
viewwindowy = 0; |
viewwindowy = 0; |
else |
viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1; |
viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1; |
// Preclaculate all row offsets. |
for (i=0 ; i<height ; i++) |
ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH; |
ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH; |
} |
730,84 → 730,84 |
// |
void R_FillBackScreen (void) |
{ |
byte* src; |
byte* dest; |
int x; |
int y; |
patch_t* patch; |
byte* src; |
byte* dest; |
int x; |
int y; |
patch_t* patch; |
// DOOM border patch. |
char name1[] = "FLOOR7_2"; |
char name1[] = "FLOOR7_2"; |
// DOOM II border patch. |
char name2[] = "GRNROCK"; |
char name2[] = "GRNROCK"; |
char* name; |
char* name; |
if (scaledviewwidth == 320) |
return; |
return; |
if ( gamemode == commercial) |
name = name2; |
name = name2; |
else |
name = name1; |
name = name1; |
src = W_CacheLumpName (name, PU_CACHE); |
dest = screens[1]; |
for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++) |
{ |
for (x=0 ; x<SCREENWIDTH/64 ; x++) |
{ |
memcpy (dest, src+((y&63)<<6), 64); |
dest += 64; |
} |
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 (SCREENWIDTH&63) |
{ |
memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63); |
dest += (SCREENWIDTH&63); |
} |
} |
patch = W_CacheLumpName ("brdr_t",PU_CACHE); |
for (x=0 ; x<scaledviewwidth ; x+=8) |
V_DrawPatch (viewwindowx+x,viewwindowy-8,1,patch); |
V_DrawPatch (viewwindowx+x,viewwindowy-8,1,patch); |
patch = W_CacheLumpName ("brdr_b",PU_CACHE); |
for (x=0 ; x<scaledviewwidth ; x+=8) |
V_DrawPatch (viewwindowx+x,viewwindowy+viewheight,1,patch); |
V_DrawPatch (viewwindowx+x,viewwindowy+viewheight,1,patch); |
patch = W_CacheLumpName ("brdr_l",PU_CACHE); |
for (y=0 ; y<viewheight ; y+=8) |
V_DrawPatch (viewwindowx-8,viewwindowy+y,1,patch); |
V_DrawPatch (viewwindowx-8,viewwindowy+y,1,patch); |
patch = W_CacheLumpName ("brdr_r",PU_CACHE); |
for (y=0 ; y<viewheight ; y+=8) |
V_DrawPatch (viewwindowx+scaledviewwidth,viewwindowy+y,1,patch); |
V_DrawPatch (viewwindowx+scaledviewwidth,viewwindowy+y,1,patch); |
// Draw beveled edge. |
V_DrawPatch (viewwindowx-8, |
viewwindowy-8, |
1, |
W_CacheLumpName ("brdr_tl",PU_CACHE)); |
viewwindowy-8, |
1, |
W_CacheLumpName ("brdr_tl",PU_CACHE)); |
V_DrawPatch (viewwindowx+scaledviewwidth, |
viewwindowy-8, |
1, |
W_CacheLumpName ("brdr_tr",PU_CACHE)); |
viewwindowy-8, |
1, |
W_CacheLumpName ("brdr_tr",PU_CACHE)); |
V_DrawPatch (viewwindowx-8, |
viewwindowy+viewheight, |
1, |
W_CacheLumpName ("brdr_bl",PU_CACHE)); |
viewwindowy+viewheight, |
1, |
W_CacheLumpName ("brdr_bl",PU_CACHE)); |
V_DrawPatch (viewwindowx+scaledviewwidth, |
viewwindowy+viewheight, |
1, |
W_CacheLumpName ("brdr_br",PU_CACHE)); |
viewwindowy+viewheight, |
1, |
W_CacheLumpName ("brdr_br",PU_CACHE)); |
} |
816,8 → 816,8 |
// |
void |
R_VideoErase |
( unsigned ofs, |
int count ) |
( unsigned ofs, |
int count ) |
{ |
// LFB copy. |
// This might not be a good idea if memcpy |
835,20 → 835,20 |
// |
void |
V_MarkRect |
( int x, |
int y, |
int width, |
int height ); |
( int x, |
int y, |
int width, |
int height ); |
void R_DrawViewBorder (void) |
{ |
int top; |
int side; |
int ofs; |
int i; |
int top; |
int side; |
int ofs; |
int i; |
if (scaledviewwidth == SCREENWIDTH) |
return; |
return; |
top = ((SCREENHEIGHT-SBARHEIGHT)-viewheight)/2; |
side = (SCREENWIDTH-scaledviewwidth)/2; |
866,8 → 866,8 |
for (i=1 ; i<viewheight ; i++) |
{ |
R_VideoErase (ofs, side); |
ofs += SCREENWIDTH; |
R_VideoErase (ofs, side); |
ofs += SCREENWIDTH; |
} |
// ? |
/programs/games/doom/trunk/r_things.c |
---|
1,989 → 1,995 |
// Emacs style mode select -*- C++ -*- |
//----------------------------------------------------------------------------- |
// |
// $Id:$ |
// |
// Copyright (C) 1993-1996 by id Software, Inc. |
// |
// This source is available for distribution and/or modification |
// only under the terms of the DOOM Source Code License as |
// published by id Software. All rights reserved. |
// |
// The source is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
// for more details. |
// |
// $Log:$ |
// |
// DESCRIPTION: |
// Refresh of things, i.e. objects represented by sprites. |
// |
//----------------------------------------------------------------------------- |
static const char |
rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $"; |
#include <stdio.h> |
#include <stdlib.h> |
#include "doomdef.h" |
#include "m_swap.h" |
#include "i_system.h" |
#include "z_zone.h" |
#include "w_wad.h" |
#include "r_local.h" |
#include "doomstat.h" |
#define MINZ (FRACUNIT*4) |
#define BASEYCENTER 100 |
//void R_DrawColumn (void); |
//void R_DrawFuzzColumn (void); |
typedef struct |
{ |
int x1; |
int 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; |
fixed_t 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[29]; |
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 >= 29 || 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; |
// make 0 based |
rotation--; |
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; |
int l; |
int intname; |
int frame; |
int rotation; |
int start; |
int end; |
int patched; |
// 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'; |
if (modifiedgame) |
patched = W_GetNumForName (lumpinfo[l].name); |
else |
patched = l; |
R_InstallSpriteLump (patched, 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) |
{ |
sprites[i].numframes = 0; |
continue; |
} |
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'); |
break; |
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'); |
break; |
} |
} |
// 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_t* 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. |
// Masked means: partly transparent, i.e. stored |
// in posts/runs of opaque pixels. |
// |
short* mfloorclip; |
short* mceilingclip; |
fixed_t spryscale; |
fixed_t sprtopscreen; |
void R_DrawMaskedColumn (column_t* column) |
{ |
int topscreen; |
int 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_yl <= dc_yh) |
{ |
dc_source = (byte *)column + 3; |
dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS); |
// dc_source = (byte *)column + 3 - column->topdelta; |
// Drawn by either R_DrawColumn |
// or (SHADOW) R_DrawFuzzColumn. |
colfunc (); |
} |
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; |
patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE); |
dc_colormap = vis->colormap; |
if (!dc_colormap) |
{ |
// NULL colormap = shadow draw |
colfunc = fuzzcolfunc; |
} |
else if (vis->mobjflags & MF_TRANSLATION) |
{ |
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); |
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); |
} |
colfunc = basecolfunc; |
} |
// |
// R_ProjectSprite |
// Generates a vissprite for a thing |
// if it might be visible. |
// |
void R_ProjectSprite (mobj_t* thing) |
{ |
fixed_t tr_x; |
fixed_t tr_y; |
fixed_t gxt; |
fixed_t gyt; |
fixed_t tx; |
fixed_t tz; |
fixed_t xscale; |
int x1; |
int x2; |
spritedef_t* sprdef; |
spriteframe_t* sprframe; |
int lump; |
unsigned rot; |
boolean flip; |
int index; |
vissprite_t* vis; |
angle_t ang; |
fixed_t iscale; |
// transform the origin point |
tr_x = thing->x - viewx; |
tr_y = thing->y - viewy; |
gxt = FixedMul(tr_x,viewcos); |
gyt = -FixedMul(tr_y,viewsin); |
tz = gxt-gyt; |
// thing is behind view plane? |
if (tz < MINZ) |
return; |
xscale = FixedDiv(projection, tz); |
gxt = -FixedMul(tr_x,viewsin); |
gyt = FixedMul(tr_y,viewcos); |
tx = -(gyt+gxt); |
// too far off the side? |
if (abs(tx)>(tz<<2)) |
return; |
// decide which patch to use for sprite relative 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; |
// off the right side? |
if (x1 > viewwidth) |
return; |
tx += spritewidth[lump]; |
x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; |
// off the left side |
if (x2 < 0) |
return; |
// store information in a vissprite |
vis = R_NewVisSprite (); |
vis->mobjflags = thing->flags; |
vis->scale = xscale<<detailshift; |
vis->gx = thing->x; |
vis->gy = thing->y; |
vis->gz = thing->z; |
vis->gzt = thing->z + spritetopoffset[lump]; |
vis->texturemid = vis->gzt - viewz; |
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) |
{ |
// shadow draw |
vis->colormap = NULL; |
} |
else if (fixedcolormap) |
{ |
// fixed map |
vis->colormap = fixedcolormap; |
} |
else if (thing->frame & FF_FULLBRIGHT) |
{ |
// full bright |
vis->colormap = colormaps; |
} |
else |
{ |
// diminished light |
index = xscale>>(LIGHTSCALESHIFT-detailshift); |
if (index >= MAXLIGHTSCALE) |
index = MAXLIGHTSCALE-1; |
vis->colormap = spritelights[index]; |
} |
} |
// |
// R_AddSprites |
// During BSP traversal, this adds sprites by sector. |
// |
void R_AddSprites (sector_t* sec) |
{ |
mobj_t* thing; |
int lightnum; |
// BSP is traversed by subsector. |
// A sector might have been split into several |
// subsectors during BSP building. |
// Thus we check whether its already added. |
if (sec->validcount == validcount) |
return; |
// Well, now it will be done. |
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]; |
// Handle all things in sector. |
for (thing = sec->thinglist ; thing ; thing = thing->snext) |
R_ProjectSprite (thing); |
} |
// |
// R_DrawPSprite |
// |
void R_DrawPSprite (pspdef_t* psp) |
{ |
fixed_t tx; |
int x1; |
int x2; |
spritedef_t* sprdef; |
spriteframe_t* sprframe; |
int lump; |
boolean flip; |
vissprite_t* vis; |
vissprite_t avis; |
// 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]; |
x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS; |
// off the right side |
if (x1 > viewwidth) |
return; |
tx += spritewidth[lump]; |
x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; |
// off the left side |
if (x2 < 0) |
return; |
// store information in a vissprite |
vis = &avis; |
vis->mobjflags = 0; |
vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]); |
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) |
{ |
// shadow draw |
vis->colormap = NULL; |
} |
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; |
int 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; |
int count; |
vissprite_t* ds; |
vissprite_t* 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]; |
short cliptop[SCREENWIDTH]; |
int x; |
int r1; |
int r2; |
fixed_t scale; |
fixed_t 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) ) |
{ |
// does not cover sprite |
continue; |
} |
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) ) ) |
{ |
// masked mid texture? |
if (ds->maskedtexturecol) |
R_RenderMaskedSegRange (ds, r1, r2); |
// seg is behind sprite |
continue; |
} |
// 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 |
// but does not draw on side views |
if (!viewangleoffset) |
R_DrawPlayerSprites (); |
} |
// Emacs style mode select -*- C++ -*- |
//----------------------------------------------------------------------------- |
// |
// $Id:$ |
// |
// Copyright (C) 1993-1996 by id Software, Inc. |
// |
// This source is available for distribution and/or modification |
// only under the terms of the DOOM Source Code License as |
// published by id Software. All rights reserved. |
// |
// The source is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
// for more details. |
// |
// $Log:$ |
// |
// DESCRIPTION: |
// Refresh of things, i.e. objects represented by sprites. |
// |
//----------------------------------------------------------------------------- |
static const char |
rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $"; |
#include <stdio.h> |
#include <stdlib.h> |
#include "doomtype.h" |
#include "doomdef.h" |
#include "m_swap.h" |
#include "i_system.h" |
#include "z_zone.h" |
#include "w_wad.h" |
#include "r_local.h" |
#include "doomstat.h" |
#define MINZ (FRACUNIT*4) |
#define BASEYCENTER 100 |
//void R_DrawColumn (void); |
//void R_DrawFuzzColumn (void); |
typedef struct |
{ |
int x1; |
int 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; |
fixed_t 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[29]; |
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 >= 29 || 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; |
// make 0 based |
rotation--; |
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; |
int l; |
int intname; |
int frame; |
int rotation; |
int start; |
int end; |
int patched; |
// 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'; |
if (modifiedgame) |
patched = W_GetNumForName (lumpinfo[l].name); |
else |
patched = l; |
R_InstallSpriteLump (patched, 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) |
{ |
sprites[i].numframes = 0; |
continue; |
} |
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'); |
break; |
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'); |
break; |
} |
} |
// 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_t* 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. |
// Masked means: partly transparent, i.e. stored |
// in posts/runs of opaque pixels. |
// |
short* mfloorclip; |
short* mceilingclip; |
fixed_t spryscale; |
fixed_t sprtopscreen; |
void R_DrawMaskedColumn (column_t* column) |
{ |
int topscreen; |
int 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_yl <= dc_yh) |
{ |
dc_source = (byte *)column + 3; |
dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS); |
// dc_source = (byte *)column + 3 - column->topdelta; |
// Drawn by either R_DrawColumn |
// or (SHADOW) R_DrawFuzzColumn. |
colfunc (); |
} |
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; |
patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE); |
dc_colormap = vis->colormap; |
if (!dc_colormap) |
{ |
// NULL colormap = shadow draw |
colfunc = fuzzcolfunc; |
} |
else if (vis->mobjflags & MF_TRANSLATION) |
{ |
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); |
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"); |
printf( "texturecolumn= %d, width= %d\n\r", |
texturecolumn,patch->width); |
texturecolumn=patch->width-1; |
} |
#endif |
column = (column_t *) ((byte *)patch + |
LONG(patch->columnofs[texturecolumn])); |
R_DrawMaskedColumn (column); |
} |
colfunc = basecolfunc; |
} |
// |
// R_ProjectSprite |
// Generates a vissprite for a thing |
// if it might be visible. |
// |
void R_ProjectSprite (mobj_t* thing) |
{ |
fixed_t tr_x; |
fixed_t tr_y; |
fixed_t gxt; |
fixed_t gyt; |
fixed_t tx; |
fixed_t tz; |
fixed_t xscale; |
int x1; |
int x2; |
spritedef_t* sprdef; |
spriteframe_t* sprframe; |
int lump; |
unsigned rot; |
boolean flip; |
int index; |
vissprite_t* vis; |
angle_t ang; |
fixed_t iscale; |
// transform the origin point |
tr_x = thing->x - viewx; |
tr_y = thing->y - viewy; |
gxt = FixedMul(tr_x,viewcos); |
gyt = -FixedMul(tr_y,viewsin); |
tz = gxt-gyt; |
// thing is behind view plane? |
if (tz < MINZ) |
return; |
xscale = FixedDiv(projection, tz); |
gxt = -FixedMul(tr_x,viewsin); |
gyt = FixedMul(tr_y,viewcos); |
tx = -(gyt+gxt); |
// too far off the side? |
if (abs(tx)>(tz<<2)) |
return; |
// decide which patch to use for sprite relative 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; |
// off the right side? |
if (x1 > viewwidth) |
return; |
tx += spritewidth[lump]; |
x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; |
// off the left side |
if (x2 < 0) |
return; |
// store information in a vissprite |
vis = R_NewVisSprite (); |
vis->mobjflags = thing->flags; |
vis->scale = xscale<<detailshift; |
vis->gx = thing->x; |
vis->gy = thing->y; |
vis->gz = thing->z; |
vis->gzt = thing->z + spritetopoffset[lump]; |
vis->texturemid = vis->gzt - viewz; |
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) |
{ |
// shadow draw |
vis->colormap = NULL; |
} |
else if (fixedcolormap) |
{ |
// fixed map |
vis->colormap = fixedcolormap; |
} |
else if (thing->frame & FF_FULLBRIGHT) |
{ |
// full bright |
vis->colormap = colormaps; |
} |
else |
{ |
// diminished light |
index = xscale>>(LIGHTSCALESHIFT-detailshift); |
if (index >= MAXLIGHTSCALE) |
index = MAXLIGHTSCALE-1; |
vis->colormap = spritelights[index]; |
} |
} |
// |
// R_AddSprites |
// During BSP traversal, this adds sprites by sector. |
// |
void R_AddSprites (sector_t* sec) |
{ |
mobj_t* thing; |
int lightnum; |
// BSP is traversed by subsector. |
// A sector might have been split into several |
// subsectors during BSP building. |
// Thus we check whether its already added. |
if (sec->validcount == validcount) |
return; |
// Well, now it will be done. |
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]; |
// Handle all things in sector. |
for (thing = sec->thinglist ; thing ; thing = thing->snext) |
R_ProjectSprite (thing); |
} |
// |
// R_DrawPSprite |
// |
void R_DrawPSprite (pspdef_t* psp) |
{ |
fixed_t tx; |
int x1; |
int x2; |
spritedef_t* sprdef; |
spriteframe_t* sprframe; |
int lump; |
boolean flip; |
vissprite_t* vis; |
vissprite_t avis; |
// 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]; |
x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS; |
// off the right side |
if (x1 > viewwidth) |
return; |
tx += spritewidth[lump]; |
x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; |
// off the left side |
if (x2 < 0) |
return; |
// store information in a vissprite |
vis = &avis; |
vis->mobjflags = 0; |
vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]); |
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) |
{ |
// shadow draw |
vis->colormap = NULL; |
} |
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; |
int 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; |
int count; |
vissprite_t* ds; |
vissprite_t* 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]; |
short cliptop[SCREENWIDTH]; |
int x; |
int r1; |
int r2; |
fixed_t scale; |
fixed_t 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) ) |
{ |
// does not cover sprite |
continue; |
} |
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) ) ) |
{ |
// masked mid texture? |
if (ds->maskedtexturecol) |
R_RenderMaskedSegRange (ds, r1, r2); |
// seg is behind sprite |
continue; |
} |
// 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 |
// but does not draw on side views |
if (!viewangleoffset) |
R_DrawPlayerSprites (); |
} |
/programs/games/doom/trunk/s_sound.c |
---|
45,6 → 45,9 |
//#include "qmus2mid.h" |
#include "kolibri.h" |
void WriteDebug(char *); |
// Purpose? |
112,10 → 115,10 |
// These are not used, but should be (menu). |
// Maximum volume of a sound effect. |
// Internal default is max out of 0-15. |
int snd_SfxVolume = 80; |
int snd_SfxVolume = 15; |
// Maximum volume of music. Useless so far. |
int snd_MusicVolume = 80; |
int snd_MusicVolume = 15; |
161,6 → 164,10 |
// Sets channels, SFX and music volume, |
// allocates channel buffer, sets S_sfx lookup. |
// |
DWORD hMixBuff[4]; |
int mix_ptr; |
void S_Init |
( int sfxVolume, |
int musicVolume ) |
169,7 → 176,13 |
printf("S_Init: default sfx volume %d\n", sfxVolume); |
//I_CreateSound(); |
InitSound(); |
hMixBuff[0]= CreateBuffer(15); |
hMixBuff[1]= CreateBuffer(15); |
hMixBuff[2]= CreateBuffer(15); |
hMixBuff[3]= CreateBuffer(15); |
numChannels = NUM_CHANNELS; |
// Whatever these did with DMX, these are rather dummies now. |
/programs/games/doom/trunk/w_wad.c |
---|
151,6 → 151,8 |
reloadname = filename; |
reloadlump = numlumps; |
} |
printf("open file %s\n\r",filename); |
if ( (handle = fopen (filename,"rb")) == NULL) |
{ |