From 7c47cdf16112ed6b15e8a918377156035a166f1e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 26 Jan 2010 19:18:18 +0000 Subject: Fix glass hack windows where a linedef is flagged as two sided but has only one side. Fixes WADs such as OTTAWAU.WAD (thanks Never_Again). Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1826 --- src/p_map.c | 21 +++++++++++++++++++-- src/p_setup.c | 27 +++++++++++++++++++++++---- src/p_sight.c | 10 +++++++++- 3 files changed, 51 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/p_map.c b/src/p_map.c index 89f8f3f8..b50fff2c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -885,7 +885,17 @@ PTR_AimTraverse (intercept_t* in) dist = FixedMul (attackrange, in->frac); - if (li->frontsector->floorheight != li->backsector->floorheight) + // Return false if there is no back sector. This should never + // be the case if the line is two-sided; however, some WADs + // (eg. ottawau.wad) use this as an "impassible glass" trick + // and rely on Vanilla Doom's (unintentional) support for this. + + if (li->backsector == NULL) + { + return false; + } + + if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > bottomslope) @@ -973,7 +983,14 @@ boolean PTR_ShootTraverse (intercept_t* in) dist = FixedMul (attackrange, in->frac); - if (li->frontsector->floorheight != li->backsector->floorheight) + // Check if backsector is NULL. See comment in PTR_AimTraverse. + + if (li->backsector == NULL) + { + goto hitline; + } + + if (li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > aimslope) diff --git a/src/p_setup.c b/src/p_setup.c index 5cf7a628..2a3a8f85 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -167,6 +167,7 @@ void P_LoadSegs (int lump) line_t* ldef; int linedef; int side; + int sidenum; numsegs = W_LumpLength (lump) / sizeof(mapseg_t); segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0); @@ -179,7 +180,7 @@ void P_LoadSegs (int lump) { li->v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; - + li->angle = (SHORT(ml->angle))<<16; li->offset = (SHORT(ml->offset))<<16; linedef = SHORT(ml->linedef); @@ -188,10 +189,28 @@ void P_LoadSegs (int lump) side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; - if (ldef-> flags & ML_TWOSIDED) - li->backsector = sides[ldef->sidenum[side^1]].sector; - else + + if (ldef-> flags & ML_TWOSIDED) + { + sidenum = ldef->sidenum[side ^ 1]; + + // If the sidenum is out of range, this may be a "glass hack" + // impassible window. Point at side #0 (this may not be + // the correct Vanilla behavior; however, it seems to work for + // OTTAWAU.WAD, which is the one place I've seen this trick + // used). + + if (sidenum < 0 || sidenum >= numsides) + { + sidenum = 0; + } + + li->backsector = sides[sidenum].sector; + } + else + { li->backsector = 0; + } } W_ReleaseLumpNum(lump); diff --git a/src/p_sight.c b/src/p_sight.c index e192567b..79c1bb1d 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -173,7 +173,7 @@ boolean P_CrossSubsector (int num) continue; line->validcount = validcount; - + v1 = line->v1; v2 = line->v2; s1 = P_DivlineSide (v1->x,v1->y, &strace); @@ -194,6 +194,14 @@ boolean P_CrossSubsector (int num) if (s1 == s2) continue; + // Backsector may be NULL if this is an "impassible + // glass" hack line. + + if (line->backsector == NULL) + { + return false; + } + // stop because it is not two sided anyway // might do this after updating validcount? if ( !(line->flags & ML_TWOSIDED) ) -- cgit v1.2.3 From a9e2d244a5a37fed344405e40698de2a2969c12a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 27 Jan 2010 19:16:26 +0000 Subject: Add tags files to svn:ignore properties. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1828 --- src/.gitignore | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/.gitignore b/src/.gitignore index d7e732ad..973a0073 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -5,3 +5,5 @@ Makefile.in chocolate-doom chocolate-server *.exe +tags +TAGS -- cgit v1.2.3 From 6fbd6eafb3dec01401a033eae2e2ec7a2d00ec1c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 29 Jan 2010 03:55:20 +0000 Subject: Fix indentation/style etc. in mus2mid.c. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1830 --- src/mus2mid.c | 951 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 479 insertions(+), 472 deletions(-) (limited to 'src') diff --git a/src/mus2mid.c b/src/mus2mid.c index 66051bae..f84be548 100644 --- a/src/mus2mid.c +++ b/src/mus2mid.c @@ -1,4 +1,4 @@ -// Emacs style mode select -*- C++ -*- +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. @@ -33,593 +33,600 @@ #include "mus2mid.h" // MUS event codes -typedef enum +typedef enum { - mus_releasekey = 0x00, - mus_presskey = 0x10, - mus_pitchwheel = 0x20, - mus_systemevent = 0x30, - mus_changecontroller = 0x40, - mus_scoreend = 0x60 + mus_releasekey = 0x00, + mus_presskey = 0x10, + mus_pitchwheel = 0x20, + mus_systemevent = 0x30, + mus_changecontroller = 0x40, + mus_scoreend = 0x60 } musevent; // MIDI event codes -typedef enum +typedef enum { - midi_releasekey = 0x80, - midi_presskey = 0x90, - midi_aftertouchkey = 0xA0, - midi_changecontroller = 0xB0, - midi_changepatch = 0xC0, - midi_aftertouchchannel = 0xD0, - midi_pitchwheel = 0xE0 + midi_releasekey = 0x80, + midi_presskey = 0x90, + midi_aftertouchkey = 0xA0, + midi_changecontroller = 0xB0, + midi_changepatch = 0xC0, + midi_aftertouchchannel = 0xD0, + midi_pitchwheel = 0xE0 } midievent; // Structure to hold MUS file header -typedef struct +typedef struct { - byte id[4]; - unsigned short scorelength; - unsigned short scorestart; - unsigned short primarychannels; - unsigned short secondarychannels; - unsigned short instrumentcount; + byte id[4]; + unsigned short scorelength; + unsigned short scorestart; + unsigned short primarychannels; + unsigned short secondarychannels; + unsigned short instrumentcount; } PACKEDATTR musheader; // Standard MIDI type 0 header + track header -static byte midiheader[] = +static byte midiheader[] = { - 'M', 'T', 'h', 'd', // Main header - 0x00, 0x00, 0x00, 0x06, // Header size - 0x00, 0x00, // MIDI type (0) - 0x00, 0x01, // Number of tracks - 0x00, 0x46, // Resolution - 'M', 'T', 'r', 'k', // Start of track - 0x00, 0x00, 0x00, 0x00 // Placeholder for track length + 'M', 'T', 'h', 'd', // Main header + 0x00, 0x00, 0x00, 0x06, // Header size + 0x00, 0x00, // MIDI type (0) + 0x00, 0x01, // Number of tracks + 0x00, 0x46, // Resolution + 'M', 'T', 'r', 'k', // Start of track + 0x00, 0x00, 0x00, 0x00 // Placeholder for track length }; // Cached channel velocities -static byte channelvelocities[] = -{ - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127 +static byte channelvelocities[] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127 }; // Timestamps between sequences of MUS events -static unsigned int queuedtime = 0; +static unsigned int queuedtime = 0; // Counter for the length of the track static unsigned int tracksize; -static byte mus2midi_translation[] = -{ - 0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D, - 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79 +static byte mus2midi_translation[] = +{ + 0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D, + 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79 }; // Write timestamp to a MIDI file. -static boolean midi_writetime(unsigned int time, MEMFILE *midioutput) +static boolean midi_writetime(unsigned int time, MEMFILE *midioutput) { - unsigned int buffer = time & 0x7F; - byte writeval; - - while ((time >>= 7) != 0) - { - buffer <<= 8; - buffer |= ((time & 0x7F) | 0x80); - } - - for (;;) - { - writeval = (byte)(buffer & 0xFF); - - if (mem_fwrite(&writeval, 1, 1, midioutput) != 1) - { - return true; - } - - ++tracksize; - - if ((buffer & 0x80) != 0) - { - buffer >>= 8; - } - else - { - queuedtime = 0; - return false; - } - } + unsigned int buffer = time & 0x7F; + byte writeval; + + while ((time >>= 7) != 0) + { + buffer <<= 8; + buffer |= ((time & 0x7F) | 0x80); + } + + for (;;) + { + writeval = (byte)(buffer & 0xFF); + + if (mem_fwrite(&writeval, 1, 1, midioutput) != 1) + { + return true; + } + + ++tracksize; + + if ((buffer & 0x80) != 0) + { + buffer >>= 8; + } + else + { + queuedtime = 0; + return false; + } + } } // Write the end of track marker -static boolean midi_writeendtrack(MEMFILE *midioutput) +static boolean midi_writeendtrack(MEMFILE *midioutput) { - byte endtrack[] = {0xFF, 0x2F, 0x00}; + byte endtrack[] = {0xFF, 0x2F, 0x00}; - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } - if (mem_fwrite(endtrack, 1, 3, midioutput) != 3) - { - return true; - } + if (mem_fwrite(endtrack, 1, 3, midioutput) != 3) + { + return true; + } - tracksize += 3; - return false; + tracksize += 3; + return false; } // Write a key press event -static boolean midi_writepresskey(byte channel, byte key, - byte velocity, MEMFILE *midioutput) +static boolean midi_writepresskey(byte channel, byte key, + byte velocity, MEMFILE *midioutput) { - byte working = midi_presskey | channel; - - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } - - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } - - working = key & 0x7F; - - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } - - working = velocity & 0x7F; - - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } - - tracksize += 3; - - return false; + byte working = midi_presskey | channel; + + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } + + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } + + working = key & 0x7F; + + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } + + working = velocity & 0x7F; + + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } + + tracksize += 3; + + return false; } // Write a key release event -static boolean midi_writereleasekey(byte channel, byte key, - MEMFILE *midioutput) +static boolean midi_writereleasekey(byte channel, byte key, + MEMFILE *midioutput) { - byte working = midi_releasekey | channel; + byte working = midi_releasekey | channel; - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = key & 0x7F; + working = key & 0x7F; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = 0; + working = 0; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - tracksize += 3; + tracksize += 3; - return false; + return false; } // Write a pitch wheel/bend event -static boolean midi_writepitchwheel(byte channel, short wheel, - MEMFILE *midioutput) +static boolean midi_writepitchwheel(byte channel, short wheel, + MEMFILE *midioutput) { - byte working = midi_pitchwheel | channel; + byte working = midi_pitchwheel | channel; - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = wheel & 0x7F; + working = wheel & 0x7F; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = (wheel >> 7) & 0x7F; + working = (wheel >> 7) & 0x7F; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - tracksize += 3; - return false; + tracksize += 3; + return false; } // Write a patch change event static boolean midi_writechangepatch(byte channel, byte patch, - MEMFILE *midioutput) + MEMFILE *midioutput) { - byte working = midi_changepatch | channel; - - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } + byte working = midi_changepatch | channel; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } - working = patch & 0x7F; + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + working = patch & 0x7F; - tracksize += 2; - - return false; -} + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } + tracksize += 2; + return false; +} // Write a valued controller change event -static boolean midi_writechangecontroller_valued(byte channel, - byte control, - byte value, - MEMFILE *midioutput) + +static boolean midi_writechangecontroller_valued(byte channel, + byte control, + byte value, + MEMFILE *midioutput) { - byte working = midi_changecontroller | channel; + byte working = midi_changecontroller | channel; - if (midi_writetime(queuedtime, midioutput)) - { - return true; - } + if (midi_writetime(queuedtime, midioutput)) + { + return true; + } - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = control & 0x7F; + working = control & 0x7F; - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } - // Quirk in vanilla DOOM? MUS controller values should be - // 7-bit, not 8-bit. + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - working = value;// & 0x7F; + // Quirk in vanilla DOOM? MUS controller values should be + // 7-bit, not 8-bit. - // Fix on said quirk to stop MIDI players from complaining that - // the value is out of range: + working = value;// & 0x7F; - if (working & 0x80) - { - working = 0x7F; - } + // Fix on said quirk to stop MIDI players from complaining that + // the value is out of range: - if (mem_fwrite(&working, 1, 1, midioutput) != 1) - { - return true; - } + if (working & 0x80) + { + working = 0x7F; + } - tracksize += 3; + if (mem_fwrite(&working, 1, 1, midioutput) != 1) + { + return true; + } - return false; + tracksize += 3; + + return false; } // Write a valueless controller change event -static boolean midi_writechangecontroller_valueless(byte channel, - byte control, - MEMFILE *midioutput) +static boolean midi_writechangecontroller_valueless(byte channel, + byte control, + MEMFILE *midioutput) { - return midi_writechangecontroller_valued(channel, control, 0, - midioutput); + return midi_writechangecontroller_valued(channel, control, 0, + midioutput); } static boolean read_musheader(MEMFILE *file, musheader *header) { - boolean result; - - result = (mem_fread(&header->id, sizeof(byte), 4, file) == 4) - && (mem_fread(&header->scorelength, sizeof(short), 1, file) == 1) - && (mem_fread(&header->scorestart, sizeof(short), 1, file) == 1) - && (mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1) - && (mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1) - && (mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1); - - if (result) - { - header->scorelength = SHORT(header->scorelength); - header->scorestart = SHORT(header->scorestart); - header->primarychannels = SHORT(header->primarychannels); - header->secondarychannels = SHORT(header->secondarychannels); - header->instrumentcount = SHORT(header->instrumentcount); - } - - return result; + boolean result; + + result = mem_fread(&header->id, sizeof(byte), 4, file) == 4 + && mem_fread(&header->scorelength, sizeof(short), 1, file) == 1 + && mem_fread(&header->scorestart, sizeof(short), 1, file) == 1 + && mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1 + && mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1 + && mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1; + + if (result) + { + header->scorelength = SHORT(header->scorelength); + header->scorestart = SHORT(header->scorestart); + header->primarychannels = SHORT(header->primarychannels); + header->secondarychannels = SHORT(header->secondarychannels); + header->instrumentcount = SHORT(header->instrumentcount); + } + + return result; } -// Read a MUS file from a stream (musinput) and output a MIDI file to +// Read a MUS file from a stream (musinput) and output a MIDI file to // a stream (midioutput). // // Returns 0 on success or 1 on failure. -boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput) +boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput) { - // Header for the MUS file - musheader musfileheader; + // Header for the MUS file + musheader musfileheader; + + // Descriptor for the current MUS event + byte eventdescriptor; + int channel; // Channel number + musevent event; - // Descriptor for the current MUS event - byte eventdescriptor; - int channel; // Channel number - musevent event; - - // Bunch of vars read from MUS lump - byte key; - byte controllernumber; - byte controllervalue; + // Bunch of vars read from MUS lump + byte key; + byte controllernumber; + byte controllervalue; - // Buffer used for MIDI track size record - byte tracksizebuffer[4]; + // Buffer used for MIDI track size record + byte tracksizebuffer[4]; - // Flag for when the score end marker is hit. - int hitscoreend = 0; + // Flag for when the score end marker is hit. + int hitscoreend = 0; - // Temp working byte - byte working; - // Used in building up time delays - unsigned int timedelay; + // Temp working byte + byte working; + // Used in building up time delays + unsigned int timedelay; - // Grab the header + // Grab the header - if (!read_musheader(musinput, &musfileheader)) - { - return true; - } + if (!read_musheader(musinput, &musfileheader)) + { + return true; + } #ifdef CHECK_MUS_HEADER - // Check MUS header - if (musfileheader.id[0] != 'M' - || musfileheader.id[1] != 'U' - || musfileheader.id[2] != 'S' - || musfileheader.id[3] != 0x1A) - { - return true; - } + // Check MUS header + if (musfileheader.id[0] != 'M' + || musfileheader.id[1] != 'U' + || musfileheader.id[2] != 'S' + || musfileheader.id[3] != 0x1A) + { + return true; + } #endif - // Seek to where the data is held - if (mem_fseek(musinput, (long)musfileheader.scorestart, - MEM_SEEK_SET) != 0) - { - return true; - } - - // So, we can assume the MUS file is faintly legit. Let's start - // writing MIDI data... - - mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput); - tracksize = 0; - - // Now, process the MUS file: - while (!hitscoreend) - { - // Handle a block of events: - - while (!hitscoreend) - { - // Fetch channel number and event code: - - if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1) - { - return true; - } - - channel = eventdescriptor & 0x0F; - event = eventdescriptor & 0x70; - - // Swap channels 15 and 9. - // MIDI channel 9 = percussion. - // MUS channel 15 = percussion. - - if (channel == 15) - { - channel = 9; - } - else if (channel == 9) - { - channel = 15; - } - - switch (event) - { - case mus_releasekey: - if (mem_fread(&key, 1, 1, musinput) != 1) - { - return true; - } - - if (midi_writereleasekey(channel, key, midioutput)) - { - return true; - } - - break; - - case mus_presskey: - if (mem_fread(&key, 1, 1, musinput) != 1) - { - return true; - } - - if (key & 0x80) - { - if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1) - { - return true; - } - - channelvelocities[channel] &= 0x7F; - } - - if (midi_writepresskey(channel, key, channelvelocities[channel], midioutput)) - { - return true; - } - - break; - - case mus_pitchwheel: - if (mem_fread(&key, 1, 1, musinput) != 1) - { - break; - } - if (midi_writepitchwheel(channel, (short)(key * 64), midioutput)) - { - return true; - } - - break; - - case mus_systemevent: - if (mem_fread(&controllernumber, 1, 1, musinput) != 1) - { - return true; - } - if (controllernumber < 10 || controllernumber > 14) - { - return true; - } - - if (midi_writechangecontroller_valueless(channel, mus2midi_translation[controllernumber], midioutput)) - { - return true; - } - - break; - - case mus_changecontroller: - if (mem_fread(&controllernumber, 1, 1, musinput) != 1) - { - return true; - } - - if (mem_fread(&controllervalue, 1, 1, musinput) != 1) - { - return true; - } - - if (controllernumber == 0) - { - if (midi_writechangepatch(channel, controllervalue, midioutput)) - { - return true; - } - } - else - { - if (controllernumber < 1 || controllernumber > 9) - { - return true; - } - - if (midi_writechangecontroller_valued(channel, mus2midi_translation[controllernumber], controllervalue, midioutput)) - { - return true; - } - } - - break; - - case mus_scoreend: - hitscoreend = 1; - break; - - default: - return true; - break; - } - - if (eventdescriptor & 0x80) - { - break; - } - } - // Now we need to read the time code: - if (!hitscoreend) - { - timedelay = 0; - for (;;) - { - if (mem_fread(&working, 1, 1, musinput) != 1) - { - return true; - } - - timedelay = timedelay * 128 + (working & 0x7F); - if ((working & 0x80) == 0) - { - break; - } - } - queuedtime += timedelay; - } - } - - // End of track - if (midi_writeendtrack(midioutput)) - { - return true; - } - - // Write the track size into the stream - if (mem_fseek(midioutput, 18, MEM_SEEK_SET)) - { - return true; - } - - tracksizebuffer[0] = (tracksize >> 24) & 0xff; - tracksizebuffer[1] = (tracksize >> 16) & 0xff; - tracksizebuffer[2] = (tracksize >> 8) & 0xff; - tracksizebuffer[3] = tracksize & 0xff; - - if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4) - { - return true; - } - - return false; + // Seek to where the data is held + if (mem_fseek(musinput, (long)musfileheader.scorestart, + MEM_SEEK_SET) != 0) + { + return true; + } + + // So, we can assume the MUS file is faintly legit. Let's start + // writing MIDI data... + + mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput); + tracksize = 0; + + // Now, process the MUS file: + while (!hitscoreend) + { + // Handle a block of events: + + while (!hitscoreend) + { + // Fetch channel number and event code: + + if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1) + { + return true; + } + + channel = eventdescriptor & 0x0F; + event = eventdescriptor & 0x70; + + // Swap channels 15 and 9. + // MIDI channel 9 = percussion. + // MUS channel 15 = percussion. + + if (channel == 15) + { + channel = 9; + } + else if (channel == 9) + { + channel = 15; + } + + switch (event) + { + case mus_releasekey: + if (mem_fread(&key, 1, 1, musinput) != 1) + { + return true; + } + + if (midi_writereleasekey(channel, key, midioutput)) + { + return true; + } + + break; + + case mus_presskey: + if (mem_fread(&key, 1, 1, musinput) != 1) + { + return true; + } + + if (key & 0x80) + { + if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1) + { + return true; + } + + channelvelocities[channel] &= 0x7F; + } + + if (midi_writepresskey(channel, key, + channelvelocities[channel], midioutput)) + { + return true; + } + + break; + + case mus_pitchwheel: + if (mem_fread(&key, 1, 1, musinput) != 1) + { + break; + } + if (midi_writepitchwheel(channel, (short)(key * 64), midioutput)) + { + return true; + } + + break; + + case mus_systemevent: + if (mem_fread(&controllernumber, 1, 1, musinput) != 1) + { + return true; + } + if (controllernumber < 10 || controllernumber > 14) + { + return true; + } + + if (midi_writechangecontroller_valueless(channel, + mus2midi_translation[controllernumber], + midioutput)) + { + return true; + } + + break; + + case mus_changecontroller: + if (mem_fread(&controllernumber, 1, 1, musinput) != 1) + { + return true; + } + + if (mem_fread(&controllervalue, 1, 1, musinput) != 1) + { + return true; + } + + if (controllernumber == 0) + { + if (midi_writechangepatch(channel, controllervalue, + midioutput)) + { + return true; + } + } + else + { + if (controllernumber < 1 || controllernumber > 9) + { + return true; + } + + if (midi_writechangecontroller_valued(channel, + mus2midi_translation[controllernumber], + controllervalue, + midioutput)) + { + return true; + } + } + + break; + + case mus_scoreend: + hitscoreend = 1; + break; + + default: + return true; + break; + } + + if (eventdescriptor & 0x80) + { + break; + } + } + // Now we need to read the time code: + if (!hitscoreend) + { + timedelay = 0; + for (;;) + { + if (mem_fread(&working, 1, 1, musinput) != 1) + { + return true; + } + + timedelay = timedelay * 128 + (working & 0x7F); + if ((working & 0x80) == 0) + { + break; + } + } + queuedtime += timedelay; + } + } + + // End of track + if (midi_writeendtrack(midioutput)) + { + return true; + } + + // Write the track size into the stream + if (mem_fseek(midioutput, 18, MEM_SEEK_SET)) + { + return true; + } + + tracksizebuffer[0] = (tracksize >> 24) & 0xff; + tracksizebuffer[1] = (tracksize >> 16) & 0xff; + tracksizebuffer[2] = (tracksize >> 8) & 0xff; + tracksizebuffer[3] = tracksize & 0xff; + + if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4) + { + return true; + } + + return false; } -- cgit v1.2.3 From 8e62a8d877b3c17035aa8fe0e353c5429812a318 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 29 Jan 2010 19:17:56 +0000 Subject: When doing a MUS to MID conversion, allocate MIDI channels so that the lowest-numbered MIDI channels are used before higher-numbered ones. Fixes ear-piercing whistle sound in the MAP05 music when playing with timidity and EAWPATS (thanks entryway / HackNeyed). Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1831 --- src/mus2mid.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/mus2mid.c b/src/mus2mid.c index f84be548..3fea1462 100644 --- a/src/mus2mid.c +++ b/src/mus2mid.c @@ -32,6 +32,11 @@ #include "memio.h" #include "mus2mid.h" +#define NUM_CHANNELS 16 + +#define MIDI_PERCUSSION_CHAN 9 +#define MUS_PERCUSSION_CHAN 15 + // MUS event codes typedef enum { @@ -100,6 +105,8 @@ static byte mus2midi_translation[] = 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79 }; +static int channel_map[NUM_CHANNELS]; + // Write timestamp to a MIDI file. static boolean midi_writetime(unsigned int time, MEMFILE *midioutput) @@ -346,6 +353,68 @@ static boolean midi_writechangecontroller_valueless(byte channel, midioutput); } +// Allocate a free MIDI channel. + +static int midi_allocate_channel(void) +{ + int result; + int max; + int i; + + // Find the current highest-allocated channel. + + max = -1; + + for (i=0; i max) + { + max = channel_map[i]; + } + } + + // max is now equal to the highest-allocated MIDI channel. We can + // now allocate the next available channel. This also works if + // no channels are currently allocated (max=-1) + + result = max + 1; + + // Don't allocate the MIDI percussion channel! + + if (result == MIDI_PERCUSSION_CHAN) + { + ++result; + } + + return result; +} + +// Given a MUS channel number, get the MIDI channel number to use +// in the outputted file. + +static int midi_get_channel(int mus_channel) +{ + // Find the MIDI channel to use for this MUS channel. + // MUS channel 15 is the percusssion channel. + + if (mus_channel == MUS_PERCUSSION_CHAN) + { + return MIDI_PERCUSSION_CHAN; + } + else + { + // If a MIDI channel hasn't been allocated for this MUS channel + // yet, allocate the next free MIDI channel. + + if (channel_map[mus_channel] == -1) + { + channel_map[mus_channel] = midi_allocate_channel(); + } + + return channel_map[mus_channel]; + } +} + static boolean read_musheader(MEMFILE *file, musheader *header) { boolean result; @@ -402,6 +471,13 @@ boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput) // Used in building up time delays unsigned int timedelay; + // Initialise channel map to mark all channels as unused. + + for (channel=0; channel +#include +#include +#include + +#include "i_system.h" +#include "z_zone.h" + +#include "deh_defs.h" +#include "deh_io.h" + +struct deh_context_s +{ + FILE *stream; + char *filename; + int linenum; + boolean last_was_newline; + char *readbuffer; + int readbuffer_size; +}; + +// Open a dehacked file for reading +// Returns NULL if open failed + +deh_context_t *DEH_OpenFile(char *filename) +{ + FILE *fstream; + deh_context_t *context; + + fstream = fopen(filename, "r"); + + if (fstream == NULL) + return NULL; + + context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); + context->stream = fstream; + + // Initial read buffer size of 128 bytes + + context->readbuffer_size = 128; + context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); + context->filename = filename; + context->linenum = 0; + context->last_was_newline = true; + + return context; +} + +// Close dehacked file + +void DEH_CloseFile(deh_context_t *context) +{ + fclose(context->stream); + Z_Free(context->readbuffer); + Z_Free(context); +} + +// Reads a single character from a dehacked file + +int DEH_GetChar(deh_context_t *context) +{ + int result; + + // Read characters, but ignore carriage returns + // Essentially this is a DOS->Unix conversion + + do + { + if (feof(context->stream)) + { + // end of file + + result = -1; + } + else + { + result = fgetc(context->stream); + } + + } while (result == '\r'); + + // Track the current line number + + if (context->last_was_newline) + { + ++context->linenum; + } + + context->last_was_newline = result == '\n'; + + return result; +} + +// Increase the read buffer size + +static void IncreaseReadBuffer(deh_context_t *context) +{ + char *newbuffer; + int newbuffer_size; + + newbuffer_size = context->readbuffer_size * 2; + newbuffer = Z_Malloc(newbuffer_size, PU_STATIC, NULL); + + memcpy(newbuffer, context->readbuffer, context->readbuffer_size); + + Z_Free(context->readbuffer); + + context->readbuffer = newbuffer; + context->readbuffer_size = newbuffer_size; +} + +// Read a whole line + +char *DEH_ReadLine(deh_context_t *context) +{ + int c; + int pos; + + for (pos = 0;;) + { + c = DEH_GetChar(context); + + if (c < 0) + { + // end of file + + return NULL; + } + + // cope with lines of any length: increase the buffer size + + if (pos >= context->readbuffer_size) + { + IncreaseReadBuffer(context); + } + + if (c == '\n') + { + // end of line: a full line has been read + + context->readbuffer[pos] = '\0'; + break; + } + else if (c != '\0') + { + // normal character; don't allow NUL characters to be + // added. + + context->readbuffer[pos] = (char) c; + ++pos; + } + } + + return context->readbuffer; +} + +void DEH_Warning(deh_context_t *context, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + + fprintf(stderr, "%s:%i: warning: ", context->filename, context->linenum); + vfprintf(stderr, msg, args); + fprintf(stderr, "\n"); + + va_end(args); +} + +void DEH_Error(deh_context_t *context, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + + fprintf(stderr, "%s:%i: ", context->filename, context->linenum); + vfprintf(stderr, msg, args); + fprintf(stderr, "\n"); + + va_end(args); + + I_Error("Error parsing dehacked file"); +} + + diff --git a/src/deh_io.h b/src/deh_io.h new file mode 100644 index 00000000..061a5a0e --- /dev/null +++ b/src/deh_io.h @@ -0,0 +1,40 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Dehacked I/O code (does all reads from dehacked files) +// +//----------------------------------------------------------------------------- + +#ifndef DEH_IO_H +#define DEH_IO_H + +#include "deh_defs.h" + +deh_context_t *DEH_OpenFile(char *filename); +void DEH_CloseFile(deh_context_t *context); +int DEH_GetChar(deh_context_t *context); +char *DEH_ReadLine(deh_context_t *context); +void DEH_Error(deh_context_t *context, char *msg, ...); +void DEH_Warning(deh_context_t *context, char *msg, ...); + +#endif /* #ifndef DEH_IO_H */ + diff --git a/src/deh_main.c b/src/deh_main.c new file mode 100644 index 00000000..3f0a6f29 --- /dev/null +++ b/src/deh_main.c @@ -0,0 +1,384 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Main dehacked code +// +//----------------------------------------------------------------------------- + +#include +#include +#include +#include + +#include "doomtype.h" +#include "d_iwad.h" +#include "m_argv.h" + +#include "deh_defs.h" +#include "deh_io.h" + +extern deh_section_t *deh_section_types[]; +extern char *deh_signatures[]; + +// If true, we can do long string replacements. + +boolean deh_allow_long_strings = false; + +// If true, we can do cheat replacements longer than the originals. + +boolean deh_allow_long_cheats = false; + +// If false, dehacked cheat replacements are ignored. + +boolean deh_apply_cheats = true; + +void DEH_Checksum(md5_digest_t digest) +{ + md5_context_t md5_context; + unsigned int i; + + MD5_Init(&md5_context); + + for (i=0; deh_section_types[i] != NULL; ++i) + { + if (deh_section_types[i]->md5_hash != NULL) + { + deh_section_types[i]->md5_hash(&md5_context); + } + } + + MD5_Final(digest, &md5_context); +} + +// Called on startup to call the Init functions + +static void InitializeSections(void) +{ + unsigned int i; + + for (i=0; deh_section_types[i] != NULL; ++i) + { + if (deh_section_types[i]->init != NULL) + { + deh_section_types[i]->init(); + } + } +} + +// Given a section name, get the section structure which corresponds + +static deh_section_t *GetSectionByName(char *name) +{ + unsigned int i; + + for (i=0; deh_section_types[i] != NULL; ++i) + { + if (!strcasecmp(deh_section_types[i]->name, name)) + { + return deh_section_types[i]; + } + } + + return NULL; +} + +// Is the string passed just whitespace? + +static boolean IsWhitespace(char *s) +{ + for (; *s; ++s) + { + if (!isspace(*s)) + return false; + } + + return true; +} + +// Strip whitespace from the start and end of a string + +static char *CleanString(char *s) +{ + char *strending; + + // Leading whitespace + + while (*s && isspace(*s)) + ++s; + + // Trailing whitespace + + strending = s + strlen(s) - 1; + + while (strlen(s) > 0 && isspace(*strending)) + { + *strending = '\0'; + --strending; + } + + return s; +} + +// This pattern is used a lot of times in different sections, +// an assignment is essentially just a statement of the form: +// +// Variable Name = Value +// +// The variable name can include spaces or any other characters. +// The string is split on the '=', essentially. +// +// Returns true if read correctly + +boolean DEH_ParseAssignment(char *line, char **variable_name, char **value) +{ + char *p; + + // find the equals + + p = strchr(line, '='); + + if (p == NULL && p-line > 2) + { + return false; + } + + // variable name at the start + // turn the '=' into a \0 to terminate the string here + + *p = '\0'; + *variable_name = CleanString(line); + + // value immediately follows the '=' + + *value = CleanString(p+1); + + return true; +} + +static boolean CheckSignatures(deh_context_t *context) +{ + size_t i; + char *line; + + // Read the first line + + line = DEH_ReadLine(context); + + if (line == NULL) + { + return false; + } + + // Check all signatures to see if one matches + + for (i=0; deh_signatures[i] != NULL; ++i) + { + if (!strcmp(deh_signatures[i], line)) + { + return true; + } + } + + return false; +} + +// Parses a comment string in a dehacked file. + +static void DEH_ParseComment(char *comment) +{ + // Allow comments containing this special value to allow string + // replacements longer than those permitted by DOS dehacked. + // This allows us to use a dehacked patch for doing string + // replacements for emulating Chex Quest. + // + // If you use this, your dehacked patch may not work in Vanilla + // Doom. + + if (strstr(comment, "*allow-long-strings*") != NULL) + { + deh_allow_long_strings = true; + } + + // Allow magic comments to allow longer cheat replacements than + // those permitted by DOS dehacked. This is also for Chex + // Quest. + + if (strstr(comment, "*allow-long-cheats*") != NULL) + { + deh_allow_long_cheats = true; + } +} + +// Parses a dehacked file by reading from the context + +static void DEH_ParseContext(deh_context_t *context) +{ + deh_section_t *current_section = NULL; + char section_name[20]; + void *tag = NULL; + char *line; + + // Read the header and check it matches the signature + + if (!CheckSignatures(context)) + { + DEH_Error(context, "This is not a valid dehacked patch file!"); + } + + deh_allow_long_strings = false; + deh_allow_long_cheats = false; + + // Read the file + + for (;;) + { + // read a new line + + line = DEH_ReadLine(context); + + // end of file? + + if (line == NULL) + return; + + while (line[0] != '\0' && isspace(line[0])) + ++line; + + if (line[0] == '#') + { + // comment + + DEH_ParseComment(line); + continue; + } + + if (IsWhitespace(line)) + { + if (current_section != NULL) + { + // end of section + + if (current_section->end != NULL) + { + current_section->end(context, tag); + } + + //printf("end %s tag\n", current_section->name); + current_section = NULL; + } + } + else + { + if (current_section != NULL) + { + // parse this line + + current_section->line_parser(context, line, tag); + } + else + { + // possibly the start of a new section + + sscanf(line, "%19s", section_name); + + current_section = GetSectionByName(section_name); + + if (current_section != NULL) + { + tag = current_section->start(context, line); + //printf("started %s tag\n", section_name); + } + else + { + //printf("unknown section name %s\n", section_name); + } + } + } + } +} + +// Parses a dehacked file + +int DEH_LoadFile(char *filename) +{ + deh_context_t *context; + + printf(" loading %s\n", filename); + + context = DEH_OpenFile(filename); + + if (context == NULL) + { + fprintf(stderr, "DEH_LoadFile: Unable to open %s\n", filename); + return 0; + } + + DEH_ParseContext(context); + + DEH_CloseFile(context); + + return 1; +} + +// Checks the command line for -deh argument + +void DEH_Init(void) +{ + char *filename; + int p; + + InitializeSections(); + + //! + // @category mod + // + // Ignore cheats in dehacked files. + // + + if (M_CheckParm("-nocheats") > 0) + { + deh_apply_cheats = false; + } + + //! + // @arg + // @category mod + // + // Load the given dehacked patch(es) + // + + p = M_CheckParm("-deh"); + + if (p > 0) + { + ++p; + + while (p < myargc && myargv[p][0] != '-') + { + filename = D_TryFindWADByName(myargv[p]); + DEH_LoadFile(filename); + ++p; + } + } +} + + diff --git a/src/deh_main.h b/src/deh_main.h new file mode 100644 index 00000000..f9cb44ca --- /dev/null +++ b/src/deh_main.h @@ -0,0 +1,54 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Dehacked entrypoint and common code +// +//----------------------------------------------------------------------------- + +#ifndef DEH_MAIN_H +#define DEH_MAIN_H + +#include "doomtype.h" +#include "doomfeatures.h" +#include "md5.h" +#include "deh_str.h" + +// These are the limits that dehacked uses (from dheinit.h in the dehacked +// source). If these limits are exceeded, it does not generate an error, but +// a warning is displayed. + +#define DEH_VANILLA_NUMSTATES 966 +#define DEH_VANILLA_NUMSFX 107 + +void DEH_Init(void); +int DEH_LoadFile(char *filename); + +boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); + +void DEH_Checksum(md5_digest_t digest); + +extern boolean deh_allow_long_strings; +extern boolean deh_allow_long_cheats; +extern boolean deh_apply_cheats; + +#endif /* #ifndef DEH_MAIN_H */ + diff --git a/src/deh_mapping.c b/src/deh_mapping.c new file mode 100644 index 00000000..b215b128 --- /dev/null +++ b/src/deh_mapping.c @@ -0,0 +1,133 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Dehacked "mapping" code +// Allows the fields in structures to be mapped out and accessed by +// name +// +//----------------------------------------------------------------------------- + +#include +#include +#include + +#include "doomtype.h" +#include "i_system.h" +#include "deh_mapping.h" + +// +// Set the value of a particular field in a structure by name +// + +boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, + void *structptr, char *name, int value) +{ + int i; + + for (i=0; mapping->entries[i].name != NULL; ++i) + { + deh_mapping_entry_t *entry = &mapping->entries[i]; + + if (!strcasecmp(entry->name, name)) + { + void *location; + + if (entry->location == NULL) + { + DEH_Warning(context, "Field '%s' is unsupported", name); + return false; + } + + location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); + + // printf("Setting %p::%s to %i (%i bytes)\n", + // structptr, name, value, entry->size); + + switch (entry->size) + { + case 1: + * ((uint8_t *) location) = value; + break; + case 2: + * ((uint16_t *) location) = value; + break; + case 4: + * ((uint32_t *) location) = value; + break; + default: + DEH_Error(context, "Unknown field type for '%s' (BUG)", name); + return false; + } + + return true; + } + } + + // field with this name not found + + DEH_Warning(context, "Field named '%s' not found", name); + + return false; +} + +void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, + void *structptr) +{ + int i; + + // Go through each mapping + + for (i=0; mapping->entries[i].name != NULL; ++i) + { + deh_mapping_entry_t *entry = &mapping->entries[i]; + void *location; + + if (entry->location == NULL) + { + // Unsupported field + + continue; + } + + // Add in data for this field + + location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); + + switch (entry->size) + { + case 1: + MD5_UpdateInt32(context, *((uint8_t *) location)); + break; + case 2: + MD5_UpdateInt32(context, *((uint16_t *) location)); + break; + case 4: + MD5_UpdateInt32(context, *((uint32_t *) location)); + break; + default: + I_Error("Unknown dehacked mapping field type for '%s' (BUG)", + entry->name); + break; + } + } +} + diff --git a/src/deh_mapping.h b/src/deh_mapping.h new file mode 100644 index 00000000..4862dec9 --- /dev/null +++ b/src/deh_mapping.h @@ -0,0 +1,90 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Dehacked "mapping" code +// Allows the fields in structures to be mapped out and accessed by +// name +// +//----------------------------------------------------------------------------- + +#ifndef DEH_MAPPING_H +#define DEH_MAPPING_H + +#include "doomtype.h" +#include "deh_io.h" +#include "md5.h" + +#define DEH_BEGIN_MAPPING(mapping_name, structname) \ + static structname deh_mapping_base; \ + static deh_mapping_t mapping_name = \ + { \ + &deh_mapping_base, \ + { + +#define DEH_MAPPING(deh_name, fieldname) \ + {deh_name, &deh_mapping_base.fieldname, \ + sizeof(deh_mapping_base.fieldname)}, + +#define DEH_UNSUPPORTED_MAPPING(deh_name) \ + {deh_name, NULL, -1}, + +#define DEH_END_MAPPING \ + {NULL, NULL, -1} \ + } \ + }; + + + +#define MAX_MAPPING_ENTRIES 32 + +typedef struct deh_mapping_s deh_mapping_t; +typedef struct deh_mapping_entry_s deh_mapping_entry_t; + +struct deh_mapping_entry_s +{ + // field name + + char *name; + + // location relative to the base in the deh_mapping_t struct + // If this is NULL, it is an unsupported mapping + + void *location; + + // field size + + int size; +}; + +struct deh_mapping_s +{ + void *base; + deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES]; +}; + +boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, + void *structptr, char *name, int value); +void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, + void *structptr); + +#endif /* #ifndef DEH_MAPPING_H */ + diff --git a/src/deh_text.c b/src/deh_text.c new file mode 100644 index 00000000..31e23db2 --- /dev/null +++ b/src/deh_text.c @@ -0,0 +1,127 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Parses Text substitution sections in dehacked files +// +//----------------------------------------------------------------------------- + +#include +#include + +#include "doomtype.h" + +#include "z_zone.h" + +#include "deh_defs.h" +#include "deh_io.h" +#include "deh_main.h" + +// Given a string length, find the maximum length of a +// string that can replace it. + +static int TXT_MaxStringLength(int len) +{ + // Enough bytes for the string and the NUL terminator + + len += 1; + + // All strings in doom.exe are on 4-byte boundaries, so we may be able + // to support a slightly longer string. + // Extend up to the next 4-byte boundary + + len += (4 - (len % 4)) % 4; + + // Less one for the NUL terminator. + + return len - 1; +} + +static void *DEH_TextStart(deh_context_t *context, char *line) +{ + char *from_text, *to_text; + int fromlen, tolen; + int i; + + if (sscanf(line, "Text %i %i", &fromlen, &tolen) != 2) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + // Only allow string replacements that are possible in Vanilla Doom. + // Chocolate Doom is unforgiving! + + if (!deh_allow_long_strings && tolen > TXT_MaxStringLength(fromlen)) + { + DEH_Error(context, "Replacement string is longer than the maximum " + "possible in doom.exe"); + return NULL; + } + + from_text = Z_Malloc(fromlen + 1, PU_STATIC, NULL); + to_text = Z_Malloc(tolen + 1, PU_STATIC, NULL); + + // read in the "from" text + + for (i=0; i +#include "deh_defs.h" +#include "deh_main.h" + +char *deh_signatures[] = +{ + "Patch File for DeHackEd v2.3", + "Patch File for DeHackEd v3.0", + NULL +}; + +// deh_ammo.c: +extern deh_section_t deh_section_ammo; +// deh_cheat.c: +extern deh_section_t deh_section_cheat; +// deh_frame.c: +extern deh_section_t deh_section_frame; +// deh_misc.c: +extern deh_section_t deh_section_misc; +// deh_ptr.c: +extern deh_section_t deh_section_pointer; +// deh_sound.c +extern deh_section_t deh_section_sound; +// deh_text.c: +extern deh_section_t deh_section_text; +// deh_thing.c: +extern deh_section_t deh_section_thing; +// deh_weapon.c: +extern deh_section_t deh_section_weapon; + +// +// List of section types: +// + +deh_section_t *deh_section_types[] = +{ + &deh_section_ammo, + &deh_section_cheat, + &deh_section_frame, + &deh_section_misc, + &deh_section_pointer, + &deh_section_sound, + &deh_section_text, + &deh_section_thing, + &deh_section_weapon, + NULL +}; + diff --git a/src/doom/deh_io.c b/src/doom/deh_io.c deleted file mode 100644 index 3386a6fa..00000000 --- a/src/doom/deh_io.c +++ /dev/null @@ -1,211 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked I/O code (does all reads from dehacked files) -// -//----------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "i_system.h" -#include "z_zone.h" - -#include "deh_defs.h" -#include "deh_io.h" - -struct deh_context_s -{ - FILE *stream; - char *filename; - int linenum; - boolean last_was_newline; - char *readbuffer; - int readbuffer_size; -}; - -// Open a dehacked file for reading -// Returns NULL if open failed - -deh_context_t *DEH_OpenFile(char *filename) -{ - FILE *fstream; - deh_context_t *context; - - fstream = fopen(filename, "r"); - - if (fstream == NULL) - return NULL; - - context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); - context->stream = fstream; - - // Initial read buffer size of 128 bytes - - context->readbuffer_size = 128; - context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); - context->filename = filename; - context->linenum = 0; - context->last_was_newline = true; - - return context; -} - -// Close dehacked file - -void DEH_CloseFile(deh_context_t *context) -{ - fclose(context->stream); - Z_Free(context->readbuffer); - Z_Free(context); -} - -// Reads a single character from a dehacked file - -int DEH_GetChar(deh_context_t *context) -{ - int result; - - // Read characters, but ignore carriage returns - // Essentially this is a DOS->Unix conversion - - do - { - if (feof(context->stream)) - { - // end of file - - result = -1; - } - else - { - result = fgetc(context->stream); - } - - } while (result == '\r'); - - // Track the current line number - - if (context->last_was_newline) - { - ++context->linenum; - } - - context->last_was_newline = result == '\n'; - - return result; -} - -// Increase the read buffer size - -static void IncreaseReadBuffer(deh_context_t *context) -{ - char *newbuffer; - int newbuffer_size; - - newbuffer_size = context->readbuffer_size * 2; - newbuffer = Z_Malloc(newbuffer_size, PU_STATIC, NULL); - - memcpy(newbuffer, context->readbuffer, context->readbuffer_size); - - Z_Free(context->readbuffer); - - context->readbuffer = newbuffer; - context->readbuffer_size = newbuffer_size; -} - -// Read a whole line - -char *DEH_ReadLine(deh_context_t *context) -{ - int c; - int pos; - - for (pos = 0;;) - { - c = DEH_GetChar(context); - - if (c < 0) - { - // end of file - - return NULL; - } - - // cope with lines of any length: increase the buffer size - - if (pos >= context->readbuffer_size) - { - IncreaseReadBuffer(context); - } - - if (c == '\n') - { - // end of line: a full line has been read - - context->readbuffer[pos] = '\0'; - break; - } - else if (c != '\0') - { - // normal character; don't allow NUL characters to be - // added. - - context->readbuffer[pos] = (char) c; - ++pos; - } - } - - return context->readbuffer; -} - -void DEH_Warning(deh_context_t *context, char *msg, ...) -{ - va_list args; - - va_start(args, msg); - - fprintf(stderr, "%s:%i: warning: ", context->filename, context->linenum); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n"); - - va_end(args); -} - -void DEH_Error(deh_context_t *context, char *msg, ...) -{ - va_list args; - - va_start(args, msg); - - fprintf(stderr, "%s:%i: ", context->filename, context->linenum); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n"); - - va_end(args); - - I_Error("Error parsing dehacked file"); -} - - diff --git a/src/doom/deh_io.h b/src/doom/deh_io.h deleted file mode 100644 index 061a5a0e..00000000 --- a/src/doom/deh_io.h +++ /dev/null @@ -1,40 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked I/O code (does all reads from dehacked files) -// -//----------------------------------------------------------------------------- - -#ifndef DEH_IO_H -#define DEH_IO_H - -#include "deh_defs.h" - -deh_context_t *DEH_OpenFile(char *filename); -void DEH_CloseFile(deh_context_t *context); -int DEH_GetChar(deh_context_t *context); -char *DEH_ReadLine(deh_context_t *context); -void DEH_Error(deh_context_t *context, char *msg, ...); -void DEH_Warning(deh_context_t *context, char *msg, ...); - -#endif /* #ifndef DEH_IO_H */ - diff --git a/src/doom/deh_main.c b/src/doom/deh_main.c deleted file mode 100644 index 63cae460..00000000 --- a/src/doom/deh_main.c +++ /dev/null @@ -1,423 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Main dehacked code -// -//----------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "doomtype.h" -#include "d_iwad.h" -#include "m_argv.h" - -#include "deh_defs.h" -#include "deh_io.h" - -static char *deh_signatures[] = -{ - "Patch File for DeHackEd v2.3", - "Patch File for DeHackEd v3.0", -}; - -// deh_ammo.c: -extern deh_section_t deh_section_ammo; -// deh_cheat.c: -extern deh_section_t deh_section_cheat; -// deh_frame.c: -extern deh_section_t deh_section_frame; -// deh_misc.c: -extern deh_section_t deh_section_misc; -// deh_ptr.c: -extern deh_section_t deh_section_pointer; -// deh_sound.c -extern deh_section_t deh_section_sound; -// deh_text.c: -extern deh_section_t deh_section_text; -// deh_thing.c: -extern deh_section_t deh_section_thing; -// deh_weapon.c: -extern deh_section_t deh_section_weapon; - -// If true, we can do long string replacements. - -boolean deh_allow_long_strings = false; - -// If true, we can do cheat replacements longer than the originals. - -boolean deh_allow_long_cheats = false; - -// If false, dehacked cheat replacements are ignored. - -boolean deh_apply_cheats = true; - -// -// List of section types: -// - -static deh_section_t *section_types[] = -{ - &deh_section_ammo, - &deh_section_cheat, - &deh_section_frame, - &deh_section_misc, - &deh_section_pointer, - &deh_section_sound, - &deh_section_text, - &deh_section_thing, - &deh_section_weapon, -}; - -void DEH_Checksum(md5_digest_t digest) -{ - md5_context_t md5_context; - unsigned int i; - - MD5_Init(&md5_context); - - for (i=0; imd5_hash != NULL) - { - section_types[i]->md5_hash(&md5_context); - } - } - - MD5_Final(digest, &md5_context); -} - -// Called on startup to call the Init functions - -static void InitializeSections(void) -{ - unsigned int i; - - for (i=0; iinit != NULL) - { - section_types[i]->init(); - } - } -} - -// Given a section name, get the section structure which corresponds - -static deh_section_t *GetSectionByName(char *name) -{ - unsigned int i; - - for (i=0; iname, name)) - { - return section_types[i]; - } - } - - return NULL; -} - -// Is the string passed just whitespace? - -static boolean IsWhitespace(char *s) -{ - for (; *s; ++s) - { - if (!isspace(*s)) - return false; - } - - return true; -} - -// Strip whitespace from the start and end of a string - -static char *CleanString(char *s) -{ - char *strending; - - // Leading whitespace - - while (*s && isspace(*s)) - ++s; - - // Trailing whitespace - - strending = s + strlen(s) - 1; - - while (strlen(s) > 0 && isspace(*strending)) - { - *strending = '\0'; - --strending; - } - - return s; -} - -// This pattern is used a lot of times in different sections, -// an assignment is essentially just a statement of the form: -// -// Variable Name = Value -// -// The variable name can include spaces or any other characters. -// The string is split on the '=', essentially. -// -// Returns true if read correctly - -boolean DEH_ParseAssignment(char *line, char **variable_name, char **value) -{ - char *p; - - // find the equals - - p = strchr(line, '='); - - if (p == NULL && p-line > 2) - { - return false; - } - - // variable name at the start - // turn the '=' into a \0 to terminate the string here - - *p = '\0'; - *variable_name = CleanString(line); - - // value immediately follows the '=' - - *value = CleanString(p+1); - - return true; -} - -static boolean CheckSignatures(deh_context_t *context) -{ - size_t i; - char *line; - - // Read the first line - - line = DEH_ReadLine(context); - - if (line == NULL) - { - return false; - } - - // Check all signatures to see if one matches - - for (i=0; iend != NULL) - { - current_section->end(context, tag); - } - - //printf("end %s tag\n", current_section->name); - current_section = NULL; - } - } - else - { - if (current_section != NULL) - { - // parse this line - - current_section->line_parser(context, line, tag); - } - else - { - // possibly the start of a new section - - sscanf(line, "%19s", section_name); - - current_section = GetSectionByName(section_name); - - if (current_section != NULL) - { - tag = current_section->start(context, line); - //printf("started %s tag\n", section_name); - } - else - { - //printf("unknown section name %s\n", section_name); - } - } - } - } -} - -// Parses a dehacked file - -int DEH_LoadFile(char *filename) -{ - deh_context_t *context; - - printf(" loading %s\n", filename); - - context = DEH_OpenFile(filename); - - if (context == NULL) - { - fprintf(stderr, "DEH_LoadFile: Unable to open %s\n", filename); - return 0; - } - - DEH_ParseContext(context); - - DEH_CloseFile(context); - - return 1; -} - -// Checks the command line for -deh argument - -void DEH_Init(void) -{ - char *filename; - int p; - - InitializeSections(); - - //! - // @category mod - // - // Ignore cheats in dehacked files. - // - - if (M_CheckParm("-nocheats") > 0) - { - deh_apply_cheats = false; - } - - //! - // @arg - // @category mod - // - // Load the given dehacked patch(es) - // - - p = M_CheckParm("-deh"); - - if (p > 0) - { - ++p; - - while (p < myargc && myargv[p][0] != '-') - { - filename = D_TryFindWADByName(myargv[p]); - DEH_LoadFile(filename); - ++p; - } - } -} - - diff --git a/src/doom/deh_main.h b/src/doom/deh_main.h deleted file mode 100644 index f9cb44ca..00000000 --- a/src/doom/deh_main.h +++ /dev/null @@ -1,54 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked entrypoint and common code -// -//----------------------------------------------------------------------------- - -#ifndef DEH_MAIN_H -#define DEH_MAIN_H - -#include "doomtype.h" -#include "doomfeatures.h" -#include "md5.h" -#include "deh_str.h" - -// These are the limits that dehacked uses (from dheinit.h in the dehacked -// source). If these limits are exceeded, it does not generate an error, but -// a warning is displayed. - -#define DEH_VANILLA_NUMSTATES 966 -#define DEH_VANILLA_NUMSFX 107 - -void DEH_Init(void); -int DEH_LoadFile(char *filename); - -boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); - -void DEH_Checksum(md5_digest_t digest); - -extern boolean deh_allow_long_strings; -extern boolean deh_allow_long_cheats; -extern boolean deh_apply_cheats; - -#endif /* #ifndef DEH_MAIN_H */ - diff --git a/src/doom/deh_mapping.c b/src/doom/deh_mapping.c deleted file mode 100644 index b215b128..00000000 --- a/src/doom/deh_mapping.c +++ /dev/null @@ -1,133 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked "mapping" code -// Allows the fields in structures to be mapped out and accessed by -// name -// -//----------------------------------------------------------------------------- - -#include -#include -#include - -#include "doomtype.h" -#include "i_system.h" -#include "deh_mapping.h" - -// -// Set the value of a particular field in a structure by name -// - -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, - void *structptr, char *name, int value) -{ - int i; - - for (i=0; mapping->entries[i].name != NULL; ++i) - { - deh_mapping_entry_t *entry = &mapping->entries[i]; - - if (!strcasecmp(entry->name, name)) - { - void *location; - - if (entry->location == NULL) - { - DEH_Warning(context, "Field '%s' is unsupported", name); - return false; - } - - location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); - - // printf("Setting %p::%s to %i (%i bytes)\n", - // structptr, name, value, entry->size); - - switch (entry->size) - { - case 1: - * ((uint8_t *) location) = value; - break; - case 2: - * ((uint16_t *) location) = value; - break; - case 4: - * ((uint32_t *) location) = value; - break; - default: - DEH_Error(context, "Unknown field type for '%s' (BUG)", name); - return false; - } - - return true; - } - } - - // field with this name not found - - DEH_Warning(context, "Field named '%s' not found", name); - - return false; -} - -void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, - void *structptr) -{ - int i; - - // Go through each mapping - - for (i=0; mapping->entries[i].name != NULL; ++i) - { - deh_mapping_entry_t *entry = &mapping->entries[i]; - void *location; - - if (entry->location == NULL) - { - // Unsupported field - - continue; - } - - // Add in data for this field - - location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); - - switch (entry->size) - { - case 1: - MD5_UpdateInt32(context, *((uint8_t *) location)); - break; - case 2: - MD5_UpdateInt32(context, *((uint16_t *) location)); - break; - case 4: - MD5_UpdateInt32(context, *((uint32_t *) location)); - break; - default: - I_Error("Unknown dehacked mapping field type for '%s' (BUG)", - entry->name); - break; - } - } -} - diff --git a/src/doom/deh_mapping.h b/src/doom/deh_mapping.h deleted file mode 100644 index 4862dec9..00000000 --- a/src/doom/deh_mapping.h +++ /dev/null @@ -1,90 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked "mapping" code -// Allows the fields in structures to be mapped out and accessed by -// name -// -//----------------------------------------------------------------------------- - -#ifndef DEH_MAPPING_H -#define DEH_MAPPING_H - -#include "doomtype.h" -#include "deh_io.h" -#include "md5.h" - -#define DEH_BEGIN_MAPPING(mapping_name, structname) \ - static structname deh_mapping_base; \ - static deh_mapping_t mapping_name = \ - { \ - &deh_mapping_base, \ - { - -#define DEH_MAPPING(deh_name, fieldname) \ - {deh_name, &deh_mapping_base.fieldname, \ - sizeof(deh_mapping_base.fieldname)}, - -#define DEH_UNSUPPORTED_MAPPING(deh_name) \ - {deh_name, NULL, -1}, - -#define DEH_END_MAPPING \ - {NULL, NULL, -1} \ - } \ - }; - - - -#define MAX_MAPPING_ENTRIES 32 - -typedef struct deh_mapping_s deh_mapping_t; -typedef struct deh_mapping_entry_s deh_mapping_entry_t; - -struct deh_mapping_entry_s -{ - // field name - - char *name; - - // location relative to the base in the deh_mapping_t struct - // If this is NULL, it is an unsupported mapping - - void *location; - - // field size - - int size; -}; - -struct deh_mapping_s -{ - void *base; - deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES]; -}; - -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, - void *structptr, char *name, int value); -void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, - void *structptr); - -#endif /* #ifndef DEH_MAPPING_H */ - diff --git a/src/doom/deh_text.c b/src/doom/deh_text.c deleted file mode 100644 index 31e23db2..00000000 --- a/src/doom/deh_text.c +++ /dev/null @@ -1,127 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Parses Text substitution sections in dehacked files -// -//----------------------------------------------------------------------------- - -#include -#include - -#include "doomtype.h" - -#include "z_zone.h" - -#include "deh_defs.h" -#include "deh_io.h" -#include "deh_main.h" - -// Given a string length, find the maximum length of a -// string that can replace it. - -static int TXT_MaxStringLength(int len) -{ - // Enough bytes for the string and the NUL terminator - - len += 1; - - // All strings in doom.exe are on 4-byte boundaries, so we may be able - // to support a slightly longer string. - // Extend up to the next 4-byte boundary - - len += (4 - (len % 4)) % 4; - - // Less one for the NUL terminator. - - return len - 1; -} - -static void *DEH_TextStart(deh_context_t *context, char *line) -{ - char *from_text, *to_text; - int fromlen, tolen; - int i; - - if (sscanf(line, "Text %i %i", &fromlen, &tolen) != 2) - { - DEH_Warning(context, "Parse error on section start"); - return NULL; - } - - // Only allow string replacements that are possible in Vanilla Doom. - // Chocolate Doom is unforgiving! - - if (!deh_allow_long_strings && tolen > TXT_MaxStringLength(fromlen)) - { - DEH_Error(context, "Replacement string is longer than the maximum " - "possible in doom.exe"); - return NULL; - } - - from_text = Z_Malloc(fromlen + 1, PU_STATIC, NULL); - to_text = Z_Malloc(tolen + 1, PU_STATIC, NULL); - - // read in the "from" text - - for (i=0; i