From b3c7b9679a8bf1eadba047ac15e59916b4edd674 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 18 Apr 2015 22:51:28 -0500 Subject: [PATCH 01/23] Fixed: writeopl broke when the OPL3 cores were added - When the OPL3 cores were added, DiskWriterIO was never updated to take into account things like more than two OPL2 chips can be configured. - DiskWriterIO no longer does any file writing directly. That function has been split off into an OPLDump class, which has two specializations: one for RDOS Play, and the other for DOSBox. If one chip is configured, it dumps for a single OPL2, otherwise it dumps for an OPL3 (effectively dual OPL2). - TODO: Figure out why playback of raw OPL files doesn't sound nearly as good as playing MIDI with the OPL emulation. It's probably something simple I overlooked. --- src/oplsynth/music_opldumper_mididevice.cpp | 408 ++++++++++---------- src/oplsynth/muslib.h | 16 +- 2 files changed, 212 insertions(+), 212 deletions(-) diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 74bef0677..33e026c07 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -45,6 +45,35 @@ // TYPES ------------------------------------------------------------------- +class OPLDump : public OPLEmul +{ +public: + OPLDump(FILE *file) : File(file), TimePerTick(0), CurTime(0), + CurIntTime(0), TickMul(1), CurChip(0) {} + + // If we're doing things right, these should never be reset. + virtual void Reset() { assert(0); } + + // Update() is only used for getting waveform data, which dumps don't do. + virtual void Update(float *buffer, int length) { assert(0); } + + // OPL dumps don't pan beyond what OPL3 is capable of (which is + // already written using registers from the original data). + virtual void SetPanning(int c, float left, float right) {} + + // Only for the OPL dumpers, not the emulators + virtual void SetClockRate(double samples_per_tick) {} + virtual void WriteDelay(int ticks) = 0; + +protected: + FILE *File; + double TimePerTick; // in milliseconds + double CurTime; + int CurIntTime; + int TickMul; + BYTE CurChip; +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -59,6 +88,173 @@ // CODE -------------------------------------------------------------------- +class OPL_RDOSdump : public OPLDump +{ +public: + OPL_RDOSdump(FILE *file) : OPLDump(file) + { + assert(File != NULL); + fwrite("RAWADATA\0", 1, 10, File); + NeedClockRate = true; + } + virtual ~OPL_RDOSdump() + { + if (File != NULL) + { + WORD endmark = 0xFFFF; + fwrite(&endmark, 2, 1, File); + fclose(File); + } + } + + virtual void WriteReg(int reg, int v) + { + assert(File != NULL); + BYTE chipnum = reg >> 8; + if (chipnum != CurChip) + { + BYTE switcher[2] = { chipnum + 1, 2 }; + fwrite(switcher, 1, 2, File); + } + reg &= 255; + if (reg != 0 && reg != 2 && (reg != 255 || v != 255)) + { + BYTE cmd[2] = { BYTE(v), BYTE(reg) }; + fwrite(cmd, 1, 2, File); + } + } + + virtual void SetClockRate(double samples_per_tick) + { + TimePerTick = samples_per_tick / OPL_SAMPLE_RATE * 1000.0; + + double clock_rate; + int clock_mul; + WORD clock_word; + + clock_rate = samples_per_tick * ADLIB_CLOCK_MUL; + clock_mul = 1; + + // The RDos raw format's clock rate is stored in a word. Therefore, + // the longest tick that can be stored is only ~55 ms. + while (clock_rate / clock_mul + 0.5 > 65535.0) + { + clock_mul++; + } + clock_word = WORD(clock_rate / clock_mul + 0.5); + + if (NeedClockRate) + { // Set the initial clock rate. + clock_word = LittleShort(clock_word); + fseek(File, 8, SEEK_SET); + fwrite(&clock_word, 2, 1, File); + fseek(File, 0, SEEK_END); + NeedClockRate = false; + } + else + { // Change the clock rate in the middle of the song. + BYTE clock_change[4] = { 0, 2, BYTE(clock_word & 255), BYTE(clock_word >> 8) }; + fwrite(clock_change, 1, 4, File); + } + } + virtual void WriteDelay(int ticks) + { + if (ticks > 0) + { // RDos raw has very precise delays but isn't very efficient at + // storing long delays. + BYTE delay[2]; + + ticks *= TickMul; + delay[1] = 0; + while (ticks > 255) + { + ticks -= 255; + delay[0] = 255; + fwrite(delay, 1, 2, File); + } + delay[0] = BYTE(ticks); + fwrite(delay, 1, 2, File); + } + } +protected: + bool NeedClockRate; +}; + +class OPL_DOSBOXdump : public OPLDump +{ +public: + OPL_DOSBOXdump(FILE *file, bool dual) : OPLDump(file), Dual(dual) + { + assert(File != NULL); + fwrite("DBRAWOPL" + "\0\0" // Minor version number + "\1\0" // Major version number + "\0\0\0\0" // Total milliseconds + "\0\0\0", // Total data + 1, 20, File); + char type[4] = { Dual * 2, 0, 0, 0 }; // Single or dual OPL-2 + fwrite(type, 1, 4, File); + } + virtual ~OPL_DOSBOXdump() + { + if (File != NULL) + { + long where_am_i = ftell(File); + DWORD len[2]; + + fseek(File, 12, SEEK_SET); + len[0] = LittleLong(CurIntTime); + len[1] = LittleLong(DWORD(where_am_i - 24)); + fwrite(len, 4, 2, File); + fclose(File); + } + } + virtual void WriteReg(int reg, int v) + { + assert(File != NULL); + BYTE chipnum = reg >> 8; + if (chipnum != CurChip) + { + CurChip = chipnum; + fputc(chipnum + 2, File); + } + reg &= 255; + BYTE cmd[3] = { 4, BYTE(reg), BYTE(v) }; + fwrite (cmd + (reg > 4), 1, 3 - (reg > 4), File); + } + virtual void WriteDelay(int ticks) + { + if (ticks > 0) + { // DosBox only has millisecond-precise delays. + int delay; + + CurTime += TimePerTick * ticks; + delay = int(CurTime + 0.5) - CurIntTime; + CurIntTime += delay; + while (delay > 65536) + { + BYTE cmd[3] = { 1, 255, 255 }; + fwrite(cmd, 1, 2, File); + delay -= 65536; + } + delay--; + if (delay <= 255) + { + BYTE cmd[2] = { 0, BYTE(delay) }; + fwrite(cmd, 1, 2, File); + } + else + { + assert(delay <= 65535); + BYTE cmd[3] = { 1, BYTE(delay & 255), BYTE(delay >> 8) }; + fwrite(cmd, 1, 3, File); + } + } + } +protected: + bool Dual; +}; + //========================================================================== // // OPLDumperMIDIDevice Constructor @@ -139,139 +335,34 @@ DiskWriterIO::~DiskWriterIO() // //========================================================================== -int DiskWriterIO::OPLinit(uint numchips, bool, bool) +int DiskWriterIO::OPLinit(uint numchips, bool, bool initopl3) { - // If the file extension is unknown or not present, the default format - // is RAW. Otherwise, you can use DRO. - if (Filename.Len() < 5 || stricmp(&Filename[Filename.Len() - 4], ".dro") != 0) - { - Format = FMT_RDOS; - } - else - { - Format = FMT_DOSBOX; - } - File = fopen(Filename, "wb"); - if (File == NULL) + FILE *file = fopen(Filename, "wb"); + if (file == NULL) { Printf("Could not open %s for writing.\n", Filename.GetChars()); return 0; } - if (Format == FMT_RDOS) + numchips = clamp(numchips, 1u, 2u); + memset(chips, 0, sizeof(chips)); + // If the file extension is unknown or not present, the default format + // is RAW. Otherwise, you can use DRO. + if (Filename.Len() < 5 || stricmp(&Filename[Filename.Len() - 4], ".dro") != 0) { - fwrite("RAWADATA\0", 1, 10, File); - NeedClockRate = true; + chips[0] = new OPL_RDOSdump(file); } else { - fwrite("DBRAWOPL" - "\0\0" // Minor version number - "\1\0" // Major version number - "\0\0\0\0" // Total milliseconds - "\0\0\0", // Total data - 1, 20, File); - if (numchips == 1) - { - fwrite("\0\0\0", 1, 4, File); // Single OPL-2 - } - else - { - fwrite("\2\0\0", 1, 4, File); // Dual OPL-2 - } - NeedClockRate = false; + chips[0] = new OPL_DOSBOXdump(file, numchips > 1); } - - TimePerTick = 0; - TickMul = 1; - CurTime = 0; - CurIntTime = 0; - CurChip = 0; OPLchannels = OPL2CHANNELS * numchips; - OPLwriteInitState(false); + NumChips = numchips; + IsOPL3 = numchips > 1; + OPLwriteInitState(initopl3); return numchips; } -//========================================================================== -// -// DiskWriterIO :: OPLdeinit -// -//========================================================================== - -void DiskWriterIO::OPLdeinit() -{ - if (File != NULL) - { - if (Format == FMT_RDOS) - { - WORD endmark = 65535; - fwrite(&endmark, 2, 1, File); - } - else - { - long where_am_i = ftell(File); - DWORD len[2]; - - fseek(File, 12, SEEK_SET); - len[0] = LittleLong(CurIntTime); - len[1] = LittleLong(DWORD(where_am_i - 24)); - fwrite(len, 4, 2, File); - } - fclose(File); - File = NULL; - } -} - -//========================================================================== -// -// DiskWriterIO :: OPLwriteReg -// -//========================================================================== - -void DiskWriterIO::OPLwriteReg(int which, uint reg, uchar data) -{ - SetChip(which); - if (Format == FMT_RDOS) - { - if (reg != 0 && reg != 2 && (reg != 255 || data != 255)) - { - BYTE cmd[2] = { data, BYTE(reg) }; - fwrite(cmd, 1, 2, File); - } - } - else - { - BYTE cmd[3] = { 4, BYTE(reg), data }; - fwrite (cmd + (reg > 4), 1, 3 - (reg > 4), File); - } -} - -//========================================================================== -// -// DiskWriterIO :: SetChip -// -//========================================================================== - -void DiskWriterIO :: SetChip(int chipnum) -{ - assert(chipnum == 0 || chipnum == 1); - - if (chipnum != CurChip) - { - CurChip = chipnum; - if (Format == FMT_RDOS) - { - BYTE switcher[2] = { BYTE(chipnum + 1), 2 }; - fwrite(switcher, 1, 2, File); - } - else - { - BYTE switcher = chipnum + 2; - fwrite(&switcher, 1, 1, File); - } - } -} - //========================================================================== // // DiskWriterIO :: SetClockRate @@ -280,39 +371,7 @@ void DiskWriterIO :: SetChip(int chipnum) void DiskWriterIO::SetClockRate(double samples_per_tick) { - TimePerTick = samples_per_tick / OPL_SAMPLE_RATE * 1000.0; - - if (Format == FMT_RDOS) - { - double clock_rate; - int clock_mul; - WORD clock_word; - - clock_rate = samples_per_tick * ADLIB_CLOCK_MUL; - clock_mul = 1; - - // The RDos raw format's clock rate is stored in a word. Therefore, - // the longest tick that can be stored is only ~55 ms. - while (clock_rate / clock_mul + 0.5 > 65535.0) - { - clock_mul++; - } - clock_word = WORD(clock_rate / clock_mul + 0.5); - - if (NeedClockRate) - { // Set the initial clock rate. - clock_word = LittleShort(clock_word); - fseek(File, 8, SEEK_SET); - fwrite(&clock_word, 2, 1, File); - fseek(File, 0, SEEK_END); - NeedClockRate = false; - } - else - { // Change the clock rate in the middle of the song. - BYTE clock_change[4] = { 0, 2, BYTE(clock_word & 255), BYTE(clock_word >> 8) }; - fwrite(clock_change, 1, 4, File); - } - } + static_cast(chips[0])->SetClockRate(samples_per_tick); } //========================================================================== @@ -323,50 +382,5 @@ void DiskWriterIO::SetClockRate(double samples_per_tick) void DiskWriterIO :: WriteDelay(int ticks) { - if (ticks <= 0) - { - return; - } - if (Format == FMT_RDOS) - { // RDos raw has very precise delays but isn't very efficient at - // storing long delays. - BYTE delay[2]; - - ticks *= TickMul; - delay[1] = 0; - while (ticks > 255) - { - ticks -= 255; - delay[0] = 255; - fwrite(delay, 1, 2, File); - } - delay[0] = BYTE(ticks); - fwrite(delay, 1, 2, File); - } - else - { // DosBox only has millisecond-precise delays. - int delay; - - CurTime += TimePerTick * ticks; - delay = int(CurTime + 0.5) - CurIntTime; - CurIntTime += delay; - while (delay > 65536) - { - BYTE cmd[3] = { 1, 255, 255 }; - fwrite(cmd, 1, 2, File); - delay -= 65536; - } - delay--; - if (delay <= 255) - { - BYTE cmd[2] = { 0, BYTE(delay) }; - fwrite(cmd, 1, 2, File); - } - else - { - assert(delay <= 65535); - BYTE cmd[3] = { 1, BYTE(delay & 255), BYTE(delay >> 8) }; - fwrite(cmd, 1, 3, File); - } - } + static_cast(chips[0])->WriteDelay(ticks); } diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 6cfb5bd55..8499a6bed 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -195,25 +195,11 @@ struct DiskWriterIO : public OPLio DiskWriterIO(const char *filename); ~DiskWriterIO(); - int OPLinit(uint numchips, bool notused=false, bool notused2=false); - void OPLdeinit(); - void OPLwriteReg(int which, uint reg, uchar data); + int OPLinit(uint numchips, bool notused, bool initopl3); void SetClockRate(double samples_per_tick); void WriteDelay(int ticks); - void SetChip(int chipnum); - - FILE *File; FString Filename; - int Format; - bool NeedClockRate; - double TimePerTick; // In milliseconds - double CurTime; - int CurIntTime; - int TickMul; - int CurChip; - - enum { FMT_RDOS, FMT_DOSBOX }; }; struct musicBlock { From f65a07c952d6ed3da49abb06ca8cd7375bd467e7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Apr 2015 08:48:20 +0200 Subject: [PATCH 02/23] - minor bit of cleanup of tags code. --- src/p_sectors.cpp | 10 +++++----- src/p_udmf.cpp | 6 ++++-- src/p_xlat.cpp | 2 +- src/r_defs.h | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 7061af788..49d8db9f1 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -830,6 +830,11 @@ bool sector_t::HasTag(int checktag) const return tag == checktag; } +bool sector_t::HasTags() const +{ + return tag != 0; +} + void sector_t::SetMainTag(int tagnum) { tag = tagnum; @@ -864,11 +869,6 @@ void line_t::SetMainId(int newid) id = newid; } -int line_t::GetMainId() const -{ - return id; -} - void line_t::ClearIds() { id = -1; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 09cee8441..657281a11 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -778,6 +778,7 @@ public: bool strifetrans = false; bool strifetrans2 = false; FString arg0str, arg1str; + int lineid; // forZDoomTranslated namespace memset(ld, 0, sizeof(*ld)); ld->Alpha = FRACUNIT; @@ -814,7 +815,8 @@ public: continue; case NAME_Id: - ld->SetMainId(CheckInt(key)); + lineid = CheckInt(key); + ld->SetMainId(lineid); continue; case NAME_Sidefront: @@ -1067,7 +1069,7 @@ public: maplinedef_t mld; memset(&mld, 0, sizeof(mld)); mld.special = ld->special; - mld.tag = ld->GetMainId(); + mld.tag = lineid; P_TranslateLineDef(ld, &mld, false); ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY)); } diff --git a/src/p_xlat.cpp b/src/p_xlat.cpp index 4b1373817..76d0cb811 100644 --- a/src/p_xlat.cpp +++ b/src/p_xlat.cpp @@ -307,7 +307,7 @@ void P_TranslateTeleportThings () while ( (dest = iterator.Next()) ) { - if (dest->Sector->GetMainTag() == 0) + if (!dest->Sector->HasTags()) { dest->tid = 1; dest->AddToHash (); diff --git a/src/r_defs.h b/src/r_defs.h index 1865777d3..3cf25573c 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -634,6 +634,7 @@ struct sector_t } bool HasTag(int checktag) const; + bool HasTags() const; void SetMainTag(int tagnum); int GetMainTag() const; void ClearTags(); @@ -908,7 +909,6 @@ struct line_t void SetMainId(int newid); - int GetMainId() const; void ClearIds(); bool HasId(int id) const; static void HashIds(); From 6326cd74b444ec668f6db4ab72b841b78ebada8a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Apr 2015 09:07:05 +0200 Subject: [PATCH 03/23] - moved tag iterators to their own file. --- src/CMakeLists.txt | 1 + src/p_spec.cpp | 51 --------------------------- src/p_spec.h | 60 +------------------------------- src/p_tags.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++ src/p_tags.h | 68 ++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 110 deletions(-) create mode 100644 src/p_tags.cpp create mode 100644 src/p_tags.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e43c0d46..dd80d305f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -895,6 +895,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE p_spec.cpp p_states.cpp p_switch.cpp + p_tags.cpp p_teleport.cpp p_terrain.cpp p_things.cpp diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 8dbb73f37..934d93c4d 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -186,57 +186,6 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info) // UTILITIES // - - -// -// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO -// - -// Find the next sector with a specified tag. -// Rewritten by Lee Killough to use chained hashing to improve speed - -int FSectorTagIterator::Next() -{ - int ret; - if (searchtag == INT_MIN) - { - ret = start; - start = -1; - } - else - { - while (start != -1 && sectors[start].tag != searchtag) start = sectors[start].nexttag; - if (start == -1) return -1; - ret = start; - start = sectors[start].nexttag; - } - return ret; -} - -int FSectorTagIterator::NextCompat(bool compat, int start) -{ - if (!compat) return Next(); - - for (int i = start + 1; i < numsectors; i++) - { - if (sectors[i].HasTag(searchtag)) return i; - } - return -1; -} - - -// killough 4/16/98: Same thing, only for linedefs - -int FLineIdIterator::Next() -{ - while (start != -1 && lines[start].id != searchtag) start = lines[start].nextid; - if (start == -1) return -1; - int ret = start; - start = lines[start].nextid; - return ret; -} - - //============================================================================ // // P_ActivateLine diff --git a/src/p_spec.h b/src/p_spec.h index 45eaf7e41..0c3ee8745 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -242,66 +242,8 @@ inline sector_t *getNextSector (line_t *line, const sector_t *sec) line->frontsector; } -class FSectorTagIterator -{ -protected: - int searchtag; - int start; -public: - FSectorTagIterator(int tag) - { - searchtag = tag; - start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; - } - - // Special constructor for actions that treat tag 0 as 'back of activation line' - FSectorTagIterator(int tag, line_t *line) - { - if (tag == 0) - { - searchtag = INT_MIN; - start = (line == NULL || line->backsector == NULL)? -1 : (int)(line->backsector - sectors); - } - else - { - searchtag = tag; - start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; - } - } - - int Next(); - int NextCompat(bool compat, int secnum); -}; - -class FLineIdIterator -{ -protected: - int searchtag; - int start; - -public: - FLineIdIterator(int id) - { - searchtag = id; - start = lines[(unsigned) id % (unsigned) numlines].firstid; - } - - int Next(); -}; - - -inline int P_FindFirstSectorFromTag(int tag) -{ - FSectorTagIterator it(tag); - return it.Next(); -} - -inline int P_FindFirstLineFromID(int tag) -{ - FLineIdIterator it(tag); - return it.Next(); -} +#include "p_tags.h" // // P_LIGHTS diff --git a/src/p_tags.cpp b/src/p_tags.cpp new file mode 100644 index 000000000..febedb85b --- /dev/null +++ b/src/p_tags.cpp @@ -0,0 +1,87 @@ +/* +** p_tags.cpp +** everything to do with tags and their management +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include "p_tags.h" + +// +// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO +// + +// Find the next sector with a specified tag. +// Rewritten by Lee Killough to use chained hashing to improve speed + +int FSectorTagIterator::Next() +{ + int ret; + if (searchtag == INT_MIN) + { + ret = start; + start = -1; + } + else + { + while (start != -1 && sectors[start].tag != searchtag) start = sectors[start].nexttag; + if (start == -1) return -1; + ret = start; + start = sectors[start].nexttag; + } + return ret; +} + +int FSectorTagIterator::NextCompat(bool compat, int start) +{ + if (!compat) return Next(); + + for (int i = start + 1; i < numsectors; i++) + { + if (sectors[i].HasTag(searchtag)) return i; + } + return -1; +} + + +// killough 4/16/98: Same thing, only for linedefs + +int FLineIdIterator::Next() +{ + while (start != -1 && lines[start].id != searchtag) start = lines[start].nextid; + if (start == -1) return -1; + int ret = start; + start = lines[start].nextid; + return ret; +} + + diff --git a/src/p_tags.h b/src/p_tags.h new file mode 100644 index 000000000..e719c380e --- /dev/null +++ b/src/p_tags.h @@ -0,0 +1,68 @@ +#ifndef P_TAGS_H +#define P_TAGS_H 1 + +#include "r_defs.h" +#include "r_state.h" + +class FSectorTagIterator +{ +protected: + int searchtag; + int start; + +public: + FSectorTagIterator(int tag) + { + searchtag = tag; + start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; + } + + // Special constructor for actions that treat tag 0 as 'back of activation line' + FSectorTagIterator(int tag, line_t *line) + { + if (tag == 0) + { + searchtag = INT_MIN; + start = (line == NULL || line->backsector == NULL)? -1 : (int)(line->backsector - sectors); + } + else + { + searchtag = tag; + start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; + } + } + + int Next(); + int NextCompat(bool compat, int secnum); +}; + +class FLineIdIterator +{ +protected: + int searchtag; + int start; + +public: + FLineIdIterator(int id) + { + searchtag = id; + start = lines[(unsigned) id % (unsigned) numlines].firstid; + } + + int Next(); +}; + + +inline int P_FindFirstSectorFromTag(int tag) +{ + FSectorTagIterator it(tag); + return it.Next(); +} + +inline int P_FindFirstLineFromID(int tag) +{ + FLineIdIterator it(tag); + return it.Next(); +} + +#endif From b921157f57783003a82842d689c099029320bcc1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Apr 2015 12:33:27 +0200 Subject: [PATCH 04/23] - uncouple sector tag storage from the sector data to allow multiple tags per sector. Tags are now handled by a tag manager class which stores sector/tag pairs. This way multiple entries can be added per sector. Since UDMF does not have any arrays the additional tags are stored as a space separated string as 'MoreIDs'. --- src/compatibility.cpp | 5 +- src/fragglescript/t_func.cpp | 4 +- src/g_strife/a_strifestuff.cpp | 2 +- src/namedef.h | 1 + src/p_acs.cpp | 4 +- src/p_lights.cpp | 2 +- src/p_linkedsectors.cpp | 2 +- src/p_lnspec.cpp | 6 +- src/p_mobj.cpp | 2 +- src/p_saveg.cpp | 10 +- src/p_sectors.cpp | 39 -------- src/p_setup.cpp | 11 ++- src/p_spec.cpp | 4 +- src/p_tags.cpp | 168 ++++++++++++++++++++++++++++++++- src/p_tags.h | 57 ++++++++++- src/p_teleport.cpp | 4 +- src/p_udmf.cpp | 34 ++++--- src/p_writemap.cpp | 2 +- src/p_xlat.cpp | 2 +- src/r_defs.h | 9 -- src/version.h | 2 +- 21 files changed, 274 insertions(+), 96 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 096811def..d60677f64 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -49,6 +49,7 @@ #include "gi.h" #include "g_level.h" #include "p_lnspec.h" +#include "p_tags.h" #include "r_state.h" #include "w_wad.h" @@ -551,8 +552,8 @@ void SetCompatibilityParams() { if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors) { - sectors[CompatParams[i + 1]].ClearTags(); - sectors[CompatParams[i + 1]].SetMainTag(CompatParams[i + 2]); + // this assumes that the sector does not have any tags yet! + tagManager.AddSectorTag(CompatParams[i + 1], CompatParams[i + 2]); } i += 3; break; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index a0609377e..95d4f4e30 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -1165,7 +1165,7 @@ void FParser::SF_ObjSector(void) } t_return.type = svt_int; - t_return.value.i = mo ? mo->Sector->GetMainTag() : 0; // nullptr check + t_return.value.i = mo ? tagManager.GetFirstSectorTag(mo->Sector) : 0; // nullptr check } //========================================================================== @@ -4312,7 +4312,7 @@ void FParser::SF_KillInSector() while ((mo=it.Next())) { - if (mo->flags3&MF3_ISMONSTER && mo->Sector->HasTag(tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre); + if (mo->flags3&MF3_ISMONSTER && tagManager.SectorHasTag(mo->Sector, tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre); } } } diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index aa9f629db..1edea19fa 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -636,7 +636,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) } else if ((sec->special & 0xFF) == Scroll_StrifeCurrent) { - int anglespeed = sec->GetMainTag() - 100; + int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; fixed_t speed = (anglespeed % 10) << (FRACBITS - 4); angle_t finean = (anglespeed / 10) << (32-3); finean >>= ANGLETOFINESHIFT; diff --git a/src/namedef.h b/src/namedef.h index e0b7e8ba6..78551badf 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -326,6 +326,7 @@ xx(Arg4) xx(Arg0Str) xx(Arg1Str) xx(Id) +xx(MoreIds) xx(V1) xx(V2) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9ea8624f6..111fb99ba 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3211,7 +3211,7 @@ do_count: if (actor->health > 0 && (kind == NULL || actor->IsA (kind))) { - if (actor->Sector->HasTag(tag) || tag == -1) + if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag)) { // Don't count items in somebody's inventory if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) || @@ -3231,7 +3231,7 @@ do_count: if (actor->health > 0 && (kind == NULL || actor->IsA (kind))) { - if (actor->Sector->HasTag(tag) || tag == -1) + if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag)) { // Don't count items in somebody's inventory if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) || diff --git a/src/p_lights.cpp b/src/p_lights.cpp index b4bfa1669..49ef130e8 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -838,7 +838,7 @@ void EV_StopLightEffect (int tag) while ((effect = iterator.Next()) != NULL) { - if (effect->GetSector()->HasTag(tag)) + if (tagManager.SectorHasTag(effect->GetSector(), tag)) { effect->Destroy(); } diff --git a/src/p_linkedsectors.cpp b/src/p_linkedsectors.cpp index 8f78aadda..b9ef8b100 100644 --- a/src/p_linkedsectors.cpp +++ b/src/p_linkedsectors.cpp @@ -278,7 +278,7 @@ static void RemoveTaggedSectors(extsector_t::linked::plane &scrollplane, int tag { for(int i = scrollplane.Sectors.Size()-1; i>=0; i--) { - if (scrollplane.Sectors[i].Sector->HasTag(tag)) + if (tagManager.SectorHasTag(scrollplane.Sectors[i].Sector, tag)) { scrollplane.Sectors.Delete(i); } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 16372b206..a24c93a3b 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1266,7 +1266,7 @@ FUNC(LS_Thing_Destroy) while (actor) { AActor *temp = iterator.Next (); - if (actor->flags & MF_SHOOTABLE && actor->Sector->HasTag(arg2)) + if (actor->flags & MF_SHOOTABLE && tagManager.SectorHasTag(actor->Sector, arg2)) P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None); actor = temp; } @@ -1279,7 +1279,7 @@ FUNC(LS_Thing_Destroy) while (actor) { AActor *temp = iterator.Next (); - if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || actor->Sector->HasTag(arg2))) + if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || tagManager.SectorHasTag(actor->Sector, arg2))) P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None); actor = temp; } @@ -2169,7 +2169,7 @@ static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed { if (scroller->IsType (type)) { - if (sectors[scroller->GetAffectee ()].HasTag(tag)) + if (tagManager.SectorHasTag(scroller->GetAffectee (), tag)) { i++; scroller->SetRate (dx, dy); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 14837a1e2..5921f97e7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3437,7 +3437,7 @@ void AActor::Tick () } else if (scrolltype == Scroll_StrifeCurrent) { // Strife scroll special - int anglespeed = sec->GetMainTag() - 100; + int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; fixed_t carryspeed = DivScale32 (anglespeed % 10, 16*CARRYFACTOR); angle_t fineangle = (anglespeed / 10) << (32-3); fineangle >>= ANGLETOFINESHIFT; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 119d92a9c..53cf79456 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -348,9 +348,13 @@ void P_SerializeWorld (FArchive &arc) { arc << sec->lightlevel; } - arc << sec->special - << sec->tag - << sec->soundtraversed + arc << sec->special; + if (SaveVersion < 4523) + { + short tag; + arc << tag; + } + arc << sec->soundtraversed << sec->seqType << sec->friction << sec->movefactor diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 49d8db9f1..c38834950 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -825,45 +825,6 @@ sector_t *sector_t::GetHeightSec() const } -bool sector_t::HasTag(int checktag) const -{ - return tag == checktag; -} - -bool sector_t::HasTags() const -{ - return tag != 0; -} - -void sector_t::SetMainTag(int tagnum) -{ - tag = tagnum; -} - -int sector_t::GetMainTag() const -{ - return tag; -} - -void sector_t::ClearTags() -{ - tag = 0; -} - -void sector_t::HashTags() -{ - int i; - - for (i=numsectors; --i>=0; ) // Initially make all slots empty. - sectors[i].firsttag = -1; - for (i=numsectors; --i>=0; ) // Proceed from last to first sector - { // so that lower sectors appear first - int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func - sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain - sectors[j].firsttag = i; - } -} - void line_t::SetMainId(int newid) { id = newid; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 4a1527514..7fa3fbcc4 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1513,7 +1513,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) else // [RH] Translate to new sector special ss->special = P_TranslateSectorSpecial (LittleShort(ms->special)); ss->secretsector = !!(ss->special&SECRET_MASK); - ss->SetMainTag(LittleShort(ms->tag)); + tagManager.AddSectorTag(i, LittleShort(ms->tag)); ss->thinglist = NULL; ss->touching_thinglist = NULL; // phares 3/14/98 ss->seqType = defSeqType; @@ -2493,7 +2493,7 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmaps for (s = 0; s < numsectors; s++) { - if (sectors[s].HasTag(tag)) + if (tagManager.SectorHasTag(s, tag)) { if (!colorgood) color = sectors[s].ColorMap->Color; if (!foggood) fog = sectors[s].ColorMap->Fade; @@ -3129,9 +3129,9 @@ static void P_GroupLines (bool buildmap) { if (sector->linecount == 0) { - Printf ("Sector %i (tag %i) has no lines\n", i, sector->GetMainTag()); + Printf ("Sector %i (tag %i) has no lines\n", i, tagManager.GetFirstSectorTag(sector)); // 0 the sector's tag so that no specials can use it - sector->ClearTags(); + tagManager.RemoveSectorTags(i); } else { @@ -3208,7 +3208,7 @@ static void P_GroupLines (bool buildmap) // [RH] Moved this here times[4].Clock(); // killough 1/30/98: Create xref tables for tags - sector_t::HashTags(); + tagManager.HashTags(); line_t::HashIds(); times[4].Unclock(); @@ -3340,6 +3340,7 @@ void P_FreeLevelData () FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. SN_StopAllSequences (); DThinker::DestroyAllThinkers (); + tagManager.Clear(); level.total_monsters = level.total_items = level.total_secrets = level.killed_monsters = level.found_items = level.found_secrets = wminfo.maxfrags = 0; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 934d93c4d..4b3c1093d 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1741,7 +1741,7 @@ static void P_SpawnScrollers(void) if (lines[i].special == Sector_CopyScroller) { // don't allow copying the scroller if the sector has the same tag as it would just duplicate it. - if (lines[i].frontsector->HasTag(lines[i].args[0])) + if (tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0])) { copyscrollers.Push(i); } @@ -2149,7 +2149,7 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, int DPusher::CheckForSectorMatch (EPusher type, int tag) { - if (m_Type == type && sectors[m_Affectee].HasTag(tag)) + if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag)) return m_Affectee; else return -1; diff --git a/src/p_tags.cpp b/src/p_tags.cpp index febedb85b..409d48291 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -35,13 +35,163 @@ #include "p_tags.h" +#include "c_dispatch.h" +FTagManager tagManager; + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +static inline int sectindex(const sector_t *sector) +{ + return (int)(intptr_t)(sector - sectors); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FTagManager::AddSectorTag(int sector, int tag) +{ + // This function assumes that all tags for a single sector get added sequentially. + // Should there ever be some need for compatibility.txt to add tags to sectors which already have a tag this function needs to be changed to adjust the startForSector indices. + while (startForSector.Size() <= (unsigned int)sector) + { + startForSector.Push(-1); + } + if (startForSector[sector] == -1) + { + startForSector[sector] = allTags.Size(); + } + else + { + // check if the key was already defined + for (unsigned i = startForSector[sector]; i < allTags.Size(); i++) + { + if (allTags[i].tag == tag) + { + return; + } + } + } + FTagItem it = { sector, tag, -1 }; + allTags.Push(it); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FTagManager::RemoveSectorTags(int sect) +{ + int start = startForSector[sect]; + if (start >= 0) + { + while (allTags[start].target == sect) + { + allTags[start].tag = allTags[start].target = -1; + start++; + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FTagManager::HashTags() +{ + // add an end marker so we do not need to check for the array's size in the other functions. + static FTagItem it = { -1, -1, -1 }; + allTags.Push(it); + + // Initially make all slots empty. + memset(TagHashFirst, -1, sizeof(TagHashFirst)); + + // Proceed from last to first so that lower targets appear first + for (int i = allTags.Size() - 1; i >= 0; i--) + { + if (allTags[i].target > 0) // only link valid entries + { + int hash = ((unsigned int)allTags[i].tag) % FTagManager::TAG_HASH_SIZE; + allTags[i].nexttag = TagHashFirst[hash]; + TagHashFirst[hash] = i; + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +bool FTagManager::SectorHasTags(const sector_t *sector) const +{ + int i = sectindex(sector); + return SectorHasTags(i); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +int FTagManager::GetFirstSectorTag(const sector_t *sect) const +{ + int i = sectindex(sect); + return SectorHasTags(i) ? allTags[startForSector[i]].tag : 0; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +bool FTagManager::SectorHasTag(int i, int tag) const +{ + if (SectorHasTags(i)) + { + int ndx = startForSector[i]; + while (allTags[ndx].target == i) + { + if (allTags[ndx].tag == tag) return true; + ndx++; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const +{ + return SectorHasTag(sectindex(sector), tag); +} + +//----------------------------------------------------------------------------- // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO // - // Find the next sector with a specified tag. // Rewritten by Lee Killough to use chained hashing to improve speed +// +//----------------------------------------------------------------------------- int FSectorTagIterator::Next() { @@ -53,27 +203,37 @@ int FSectorTagIterator::Next() } else { - while (start != -1 && sectors[start].tag != searchtag) start = sectors[start].nexttag; + while (start >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag; if (start == -1) return -1; ret = start; - start = sectors[start].nexttag; + start = start = tagManager.allTags[start].nexttag; } return ret; } +//----------------------------------------------------------------------------- +// +// linear search for compatible stair building +// +//----------------------------------------------------------------------------- + int FSectorTagIterator::NextCompat(bool compat, int start) { if (!compat) return Next(); for (int i = start + 1; i < numsectors; i++) { - if (sectors[i].HasTag(searchtag)) return i; + if (tagManager.SectorHasTag(i, searchtag)) return i; } return -1; } +//----------------------------------------------------------------------------- +// // killough 4/16/98: Same thing, only for linedefs +// +//----------------------------------------------------------------------------- int FLineIdIterator::Next() { diff --git a/src/p_tags.h b/src/p_tags.h index e719c380e..9b380e012 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -4,6 +4,59 @@ #include "r_defs.h" #include "r_state.h" +struct FTagItem +{ + int target; // either sector or line + int tag; + int nexttag; // for hashing +}; + +class FSectorTagIterator; + +class FTagManager +{ + enum + { + TAG_HASH_SIZE = 256 + }; + + friend class FSectorTagIterator; + + TArray allTags; + TArray allIDs; + TArray startForSector; + TArray startForLine; + int TagHashFirst[TAG_HASH_SIZE]; + + bool SectorHasTags(int sect) const + { + return sect >= 0 && sect < (int)startForSector.Size() && startForSector[sect] >= 0; + } + + +public: + void Clear() + { + allTags.Clear(); + allIDs.Clear(); + startForSector.Clear(); + startForLine.Clear(); + memset(TagHashFirst, -1, sizeof(TagHashFirst)); + } + + bool SectorHasTags(const sector_t *sector) const; + int GetFirstSectorTag(const sector_t *sect) const; + bool SectorHasTag(int sector, int tag) const; + bool SectorHasTag(const sector_t *sector, int tag) const; + + bool LineHasID(int line, int id); + void HashTags(); + void AddSectorTag(int sector, int tag); + void RemoveSectorTags(int sect); +}; + +extern FTagManager tagManager; + class FSectorTagIterator { protected: @@ -14,7 +67,7 @@ public: FSectorTagIterator(int tag) { searchtag = tag; - start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; + start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE]; } // Special constructor for actions that treat tag 0 as 'back of activation line' @@ -28,7 +81,7 @@ public: else { searchtag = tag; - start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag; + start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE]; } } diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index de16a57fa..82359f4e0 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -250,7 +250,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom) int count = 0; while ( (searcher = iterator.Next ()) ) { - if (tag == 0 || searcher->Sector->HasTag(tag)) + if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag)) { count++; } @@ -289,7 +289,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom) while (count > 0) { searcher = iterator.Next (); - if (tag == 0 || searcher->Sector->HasTag(tag)) + if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag)) { count--; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 657281a11..3e8f6ad60 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -46,6 +46,7 @@ #include "r_state.h" #include "r_data/colormaps.h" #include "w_wad.h" +#include "p_tags.h" //=========================================================================== // @@ -1269,6 +1270,7 @@ public: int desaturation = -1; int fplaneflags = 0, cplaneflags = 0; double fp[4] = { 0 }, cp[4] = { 0 }; + FString tagstring; memset(sec, 0, sizeof(*sec)); sec->lightlevel = 160; @@ -1332,7 +1334,7 @@ public: continue; case NAME_Id: - sec->SetMainTag((short)CheckInt(key)); + tagManager.AddSectorTag(index, CheckInt(key)); continue; default: @@ -1510,28 +1512,32 @@ public: cp[3] = CheckFloat(key); break; + case NAME_MoreIds: + // delay parsing of the tag string until parsing of the sector is complete + // This ensures that the ID is always the first tag in the list. + tagstring = CheckString(key); + break; + default: break; } -#if 0 // for later - if (namespace_bits & (Zd)) && !strnicmp(key.GetChars(), "Id", 2)) - { - char *endp; - int num = strtol(key.GetChars(), &endp, 10); - if (num > 0 && *endp == NULL) - { - // only allow ID## with ## as a proper number - sec->SetTag((short)CheckInt(key), false); - } - } -#endif - if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5)) { AddUserKey(key, UDMF_Sector, index); } } + if (tagstring.IsNotEmpty()) + { + FScanner sc; + sc.OpenMem("tagstring", tagstring.GetChars(), tagstring.Len()); + // scan the string as long as valid numbers can be found + while (sc.CheckNumber()) + { + if (sc.Number != 0) tagManager.AddSectorTag(index, sc.Number); + } + } + sec->secretsector = !!(sec->special&SECRET_MASK); // Reset the planes to their defaults if not all of the plane equation's parameters were found. diff --git a/src/p_writemap.cpp b/src/p_writemap.cpp index 2f11ee5c1..e31d2c4c3 100644 --- a/src/p_writemap.cpp +++ b/src/p_writemap.cpp @@ -262,7 +262,7 @@ static int WriteSECTORS (FILE *file) uppercopy (ms.ceilingpic, GetTextureName (sectors[i].GetTexture(sector_t::ceiling))); ms.lightlevel = LittleShort((short)sectors[i].lightlevel); ms.special = LittleShort(sectors[i].special); - ms.tag = LittleShort(sectors[i].GetMainTag()); + ms.tag = LittleShort(tagManager.GetFirstSectorTag(§ors[i])); fwrite (&ms, sizeof(ms), 1, file); } return numsectors * sizeof(ms); diff --git a/src/p_xlat.cpp b/src/p_xlat.cpp index 76d0cb811..040ce47db 100644 --- a/src/p_xlat.cpp +++ b/src/p_xlat.cpp @@ -307,7 +307,7 @@ void P_TranslateTeleportThings () while ( (dest = iterator.Next()) ) { - if (!dest->Sector->HasTags()) + if (!tagManager.SectorHasTags(dest->Sector)) { dest->tid = 1; dest->AddToHash (); diff --git a/src/r_defs.h b/src/r_defs.h index 3cf25573c..076f7736d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -633,12 +633,6 @@ struct sector_t return pos == floor? floorplane:ceilingplane; } - bool HasTag(int checktag) const; - bool HasTags() const; - void SetMainTag(int tagnum); - int GetMainTag() const; - void ClearTags(); - static void HashTags(); bool PlaneMoving(int pos); @@ -657,12 +651,9 @@ struct sector_t TObjPtr SoundTarget; short special; - short tag; short lightlevel; short seqType; // this sector's sound sequence - int nexttag,firsttag; // killough 1/30/98: improves searches for tags. - int sky; FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. diff --git a/src/version.h b/src/version.h index f45f58b2f..3d28dd2ac 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4522 +#define SAVEVER 4523 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From db61c1cb57581876d31bc9dcf01c882767480237 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Apr 2015 17:51:34 +0200 Subject: [PATCH 05/23] - allow multiple line IDs as well using the same method as for sector tags. --- specs/udmf_zdoom.txt | 5 ++ src/fragglescript/t_func.cpp | 4 +- src/p_3dfloors.cpp | 2 +- src/p_3dmidtex.cpp | 2 +- src/p_lnspec.cpp | 4 +- src/p_saveg.cpp | 9 +++- src/p_sectors.cpp | 32 ----------- src/p_setup.cpp | 33 ++++++------ src/p_setup.h | 2 +- src/p_spec.cpp | 2 +- src/p_tags.cpp | 89 ++++++++++++++++++++++++++++++- src/p_tags.h | 10 +++- src/p_udmf.cpp | 38 +++++++------ src/p_xlat.cpp | 6 +-- src/r_defs.h | 9 ---- src/thingdef/thingdef_codeptr.cpp | 2 +- 16 files changed, 159 insertions(+), 90 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index cbb5b902c..6541e9a02 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -119,6 +119,7 @@ Note: All fields default to false unless mentioned otherwise. blockhitscan = ; // Line blocks hitscan attacks locknumber = ; // Line special is locked arg0str = ; // Alternate string-based version of arg0 + moreids = ; // Additional line IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") transparent = ; // true = line is a Strife transparent line (alpha 0.25) @@ -201,6 +202,7 @@ Note: All fields default to false unless mentioned otherwise. // sound sequence thing in the sector will override this property. hidden = ; // if true this sector will not be drawn on the textured automap. waterzone = ; // Sector is under water and swimmable + moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") * Note about dropactors @@ -370,6 +372,9 @@ Added transparent line property (to be folded back to core UDMF standard), and h Added plane equations for sector slopes. (Please read carefully to ensure proper use!) Changed language describing the DIALOGUE lump to mention USDF as an option. +1.25 19.04.2015 +Added 'moreids' for linedefs and sectors. + =============================================================================== EOF =============================================================================== diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 95d4f4e30..6583d1510 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2235,7 +2235,7 @@ void FParser::SF_LineTrigger() maplinedef_t mld; mld.special=intvalue(t_argv[0]); mld.tag=t_argc > 1 ? intvalue(t_argv[1]) : 0; - P_TranslateLineDef(&line, &mld, false); + P_TranslateLineDef(&line, &mld); P_ExecuteSpecial(line.special, NULL, Script->trigger, false, line.args[0],line.args[1],line.args[2],line.args[3],line.args[4]); } @@ -4385,7 +4385,7 @@ void FParser::SF_SetLineTrigger() mld.tag = tag; mld.flags = 0; int f = lines[i].flags; - P_TranslateLineDef(&lines[i], &mld, false); + P_TranslateLineDef(&lines[i], &mld); lines[i].flags = (lines[i].flags & (ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)) | (f & ~(ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)); diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 42d79dcc0..cc76beaa3 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -844,7 +844,7 @@ void P_Spawn3DFloors (void) { if (line->args[1]&8) { - line->SetMainId(line->args[4]); + tagManager.AddLineID(i, line->args[4]); } else { diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index ff0d3a181..9a9492e08 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -167,7 +167,7 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c { line_t *ln = sectors[sec].lines[line]; - if (lineid != 0 && !ln->HasId(lineid)) continue; + if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue; if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX)) { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index a24c93a3b..37d6d6058 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2063,7 +2063,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int { int wallnum = scroller->GetWallNum (); - if (wallnum >= 0 && sides[wallnum].linedef->HasId(id) && + if (wallnum >= 0 && tagManager.LineHasID(sides[wallnum].linedef, id) && int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum && Where == scroller->GetScrollParts()) { @@ -2082,7 +2082,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int while ( (collect.Obj = iterator.Next ()) ) { if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 && - sides[collect.RefNum].linedef->HasId(id) && + tagManager.LineHasID(sides[collect.RefNum].linedef, id) && int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum && Where == ((DScroller *)collect.Obj)->GetScrollParts()) { diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 53cf79456..480494320 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -409,8 +409,13 @@ void P_SerializeWorld (FArchive &arc) arc << li->flags << li->activation << li->special - << li->Alpha - << li->id; + << li->Alpha; + + if (SaveVersion < 4523) + { + int id; + arc << id; + } if (P_IsACSSpecial(li->special)) { P_SerializeACSScriptNumber(arc, li->args[0], false); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index c38834950..904c76c1b 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -825,38 +825,6 @@ sector_t *sector_t::GetHeightSec() const } -void line_t::SetMainId(int newid) -{ - id = newid; -} - -void line_t::ClearIds() -{ - id = -1; -} - -bool line_t::HasId(int checkid) const -{ - return id == checkid; -} - - -void line_t::HashIds() -{ - // killough 4/17/98: same thing, only for linedefs - int i; - - for (i=numlines; --i>=0; ) // Initially make all slots empty. - lines[i].firstid = -1; - for (i=numlines; --i>=0; ) // Proceed from last to first linedef - { // so that lower linedefs appear first - int j = (unsigned) lines[i].id % (unsigned) numlines; // Hash func - lines[i].nextid = lines[j].firstid; // Prepend linedef to chain - lines[j].firstid = i; - } -} - - bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const { bool copy = false; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 7fa3fbcc4..166230e3d 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1907,54 +1907,59 @@ void P_AdjustLine (line_t *ld) } } -void P_SetLineID (line_t *ld) +void P_SetLineID (int i, line_t *ld) { // [RH] Set line id (as appropriate) here // for Doom format maps this must be done in P_TranslateLineDef because // the tag doesn't always go into the first arg. if (level.maptype == MAPTYPE_HEXEN) { + int setid = -1; switch (ld->special) { case Line_SetIdentification: if (!(level.flags2 & LEVEL2_HEXENHACK)) { - ld->SetMainId(ld->args[0] + 256 * ld->args[4]); + setid = ld->args[0] + 256 * ld->args[4]; ld->flags |= ld->args[1]<<16; } else { - ld->SetMainId(ld->args[0]); + setid = ld->args[0]; } ld->special = 0; break; case TranslucentLine: - ld->SetMainId(ld->args[0]); + setid = ld->args[0]; ld->flags |= ld->args[3]<<16; break; case Teleport_Line: case Scroll_Texture_Model: - ld->SetMainId(ld->args[0]); + setid = ld->args[0]; break; case Polyobj_StartLine: - ld->SetMainId(ld->args[3]); + setid = ld->args[3]; break; case Polyobj_ExplicitLine: - ld->SetMainId(ld->args[4]); + setid = ld->args[4]; break; case Plane_Align: - ld->SetMainId(ld->args[2]); + setid = ld->args[2]; break; case Static_Init: - if (ld->args[1] == Init_SectorLink) ld->SetMainId(ld->args[0]); + if (ld->args[1] == Init_SectorLink) setid = ld->args[0]; break; } + if (setid != -1) + { + tagManager.AddLineID(i, setid); + } } } @@ -2037,7 +2042,7 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha) { for (j = 0; j < numlines; j++) { - if (lines[j].HasId(ld->args[0])) + if (tagManager.LineHasID(j, ld->args[0])) { lines[j].Alpha = alpha; if (additive) @@ -2139,13 +2144,13 @@ void P_LoadLineDefs (MapData * map) mld = (maplinedef_t *)mldf; ld = lines; - for (i = numlines; i > 0; i--, mld++, ld++) + for (i = 0; i < numlines; i++, mld++, ld++) { ld->Alpha = FRACUNIT; // [RH] Opaque by default // [RH] Translate old linedef special and flags to be // compatible with the new format. - P_TranslateLineDef (ld, mld, true); + P_TranslateLineDef (ld, mld, i); ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v2 = &vertexes[LittleShort(mld->v2)]; @@ -2231,13 +2236,12 @@ void P_LoadLineDefs2 (MapData * map) ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v2 = &vertexes[LittleShort(mld->v2)]; ld->Alpha = FRACUNIT; // [RH] Opaque by default - ld->ClearIds(); P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0])); P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1])); P_AdjustLine (ld); - P_SetLineID(ld); + P_SetLineID(i, ld); P_SaveLineSpecial (ld); if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; @@ -3209,7 +3213,6 @@ static void P_GroupLines (bool buildmap) times[4].Clock(); // killough 1/30/98: Create xref tables for tags tagManager.HashTags(); - line_t::HashIds(); times[4].Unclock(); times[5].Clock(); diff --git a/src/p_setup.h b/src/p_setup.h index 20caa5d76..cbd423a10 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -115,7 +115,7 @@ struct line_t; struct maplinedef_t; void P_LoadTranslator(const char *lumpname); -void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setlineid); +void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1); int P_TranslateSectorSpecial (int); int GetUDMFInt(int type, int index, const char *key); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 4b3c1093d..81f4a27e4 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -232,7 +232,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType) !repeat && // only non-repeatable triggers (specialGeneric_Crusher) && // not for Boom's generalized linedefs special && // not for lines without a special - line->HasId(line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0] + tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0] line->args[0] && // only if there's a tag (which is stored in the first arg) P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef { diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 409d48291..f4164184f 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -50,6 +50,11 @@ static inline int sectindex(const sector_t *sector) return (int)(intptr_t)(sector - sectors); } +static inline int lineindex(const line_t *line) +{ + return (int)(intptr_t)(line - lines); +} + //----------------------------------------------------------------------------- // // @@ -58,6 +63,8 @@ static inline int sectindex(const sector_t *sector) void FTagManager::AddSectorTag(int sector, int tag) { + if (tag == 0) return; + // This function assumes that all tags for a single sector get added sequentially. // Should there ever be some need for compatibility.txt to add tags to sectors which already have a tag this function needs to be changed to adjust the startForSector indices. while (startForSector.Size() <= (unsigned int)sector) @@ -108,14 +115,50 @@ void FTagManager::RemoveSectorTags(int sect) // //----------------------------------------------------------------------------- +void FTagManager::AddLineID(int line, int tag) +{ + if (tag == -1) return; // For line IDs -1 means 'not set', unlike sectors. + + // This function assumes that all ids for a single line get added sequentially. + while (startForLine.Size() <= (unsigned int)line) + { + startForLine.Push(-1); + } + if (startForLine[line] == -1) + { + startForLine[line] = allIDs.Size(); + } + else + { + // check if the key was already defined + for (unsigned i = startForLine[line]; i < allIDs.Size(); i++) + { + if (allIDs[i].tag == tag) + { + return; + } + } + } + FTagItem it = { line, tag, -1 }; + allIDs.Push(it); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void FTagManager::HashTags() { // add an end marker so we do not need to check for the array's size in the other functions. static FTagItem it = { -1, -1, -1 }; allTags.Push(it); + allIDs.Push(it); // Initially make all slots empty. memset(TagHashFirst, -1, sizeof(TagHashFirst)); + memset(IDHashFirst, -1, sizeof(IDHashFirst)); // Proceed from last to first so that lower targets appear first for (int i = allTags.Size() - 1; i >= 0; i--) @@ -127,6 +170,17 @@ void FTagManager::HashTags() TagHashFirst[hash] = i; } } + + for (int i = allIDs.Size() - 1; i >= 0; i--) + { + if (allIDs[i].target > 0) // only link valid entries + { + int hash = ((unsigned int)allIDs[i].tag) % FTagManager::TAG_HASH_SIZE; + allIDs[i].nexttag = IDHashFirst[hash]; + IDHashFirst[hash] = i; + } + } + } //----------------------------------------------------------------------------- @@ -184,6 +238,37 @@ bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const return SectorHasTag(sectindex(sector), tag); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +bool FTagManager::LineHasID(int i, int tag) const +{ + if (LineHasIDs(i)) + { + int ndx = startForLine[i]; + while (allIDs[ndx].target == i) + { + if (allIDs[ndx].tag == tag) return true; + ndx++; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +bool FTagManager::LineHasID(const line_t *line, int tag) const +{ + return LineHasID(lineindex(line), tag); +} + //----------------------------------------------------------------------------- // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO @@ -237,10 +322,10 @@ int FSectorTagIterator::NextCompat(bool compat, int start) int FLineIdIterator::Next() { - while (start != -1 && lines[start].id != searchtag) start = lines[start].nextid; + while (start >= 0 && tagManager.allIDs[start].tag != searchtag) start = tagManager.allIDs[start].nexttag; if (start == -1) return -1; int ret = start; - start = lines[start].nextid; + start = start = tagManager.allIDs[start].nexttag; return ret; } diff --git a/src/p_tags.h b/src/p_tags.h index 9b380e012..7a63ca74b 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -12,6 +12,7 @@ struct FTagItem }; class FSectorTagIterator; +class FLineIdIterator; class FTagManager { @@ -21,12 +22,14 @@ class FTagManager }; friend class FSectorTagIterator; + friend class FLineIdIterator; TArray allTags; TArray allIDs; TArray startForSector; TArray startForLine; int TagHashFirst[TAG_HASH_SIZE]; + int IDHashFirst[TAG_HASH_SIZE]; bool SectorHasTags(int sect) const { @@ -49,9 +52,12 @@ public: bool SectorHasTag(int sector, int tag) const; bool SectorHasTag(const sector_t *sector, int tag) const; - bool LineHasID(int line, int id); + bool LineHasID(int line, int id) const; + bool LineHasID(const line_t *line, int id) const; + void HashTags(); void AddSectorTag(int sector, int tag); + void AddLineID(int line, int tag); void RemoveSectorTags(int sect); }; @@ -99,7 +105,7 @@ public: FLineIdIterator(int id) { searchtag = id; - start = lines[(unsigned) id % (unsigned) numlines].firstid; + start = tagManager.IDHashFirst[((unsigned int)id) % FTagManager::TAG_HASH_SIZE]; } int Next(); diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 3e8f6ad60..8992c3984 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -755,7 +755,7 @@ public: mld.flags = 0; mld.special = th->special; mld.tag = th->args[0]; - P_TranslateLineDef(&ld, &mld, true); + P_TranslateLineDef(&ld, &mld); th->special = ld.special; memcpy(th->args, ld.args, sizeof (ld.args)); } @@ -780,10 +780,10 @@ public: bool strifetrans2 = false; FString arg0str, arg1str; int lineid; // forZDoomTranslated namespace + FString tagstring; memset(ld, 0, sizeof(*ld)); ld->Alpha = FRACUNIT; - ld->ClearIds(); ld->sidedef[0] = ld->sidedef[1] = NULL; if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; @@ -817,7 +817,7 @@ public: case NAME_Id: lineid = CheckInt(key); - ld->SetMainId(lineid); + tagManager.AddLineID(index, lineid); continue; case NAME_Sidefront: @@ -1040,22 +1040,17 @@ public: Flag(ld->flags, ML_3DMIDTEX_IMPASS, key); continue; + case NAME_MoreIds: + // delay parsing of the tag string until parsing of the sector is complete + // This ensures that the ID is always the first tag in the list. + tagstring = CheckString(key); + break; + + default: break; } -#if 0 // for later - if (namespace_bits & (Zd)) && !strnicmp(key.GetChars(), "Id", 2)) - { - char *endp; - int num = strtol(key.GetChars(), &endp, 10); - if (num > 0 && *endp == NULL) - { - // only allow ID## with ## as a proper number - ld->SetId((short)CheckInt(key), false); - } - } -#endif if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5)) { @@ -1063,6 +1058,17 @@ public: } } + if (tagstring.IsNotEmpty()) + { + FScanner sc; + sc.OpenMem("tagstring", tagstring.GetChars(), tagstring.Len()); + // scan the string as long as valid numbers can be found + while (sc.CheckNumber()) + { + if (sc.Number != 0) tagManager.AddLineID(index, sc.Number); + } + } + if (isTranslated) { int saved = ld->flags; @@ -1071,7 +1077,7 @@ public: memset(&mld, 0, sizeof(mld)); mld.special = ld->special; mld.tag = lineid; - P_TranslateLineDef(ld, &mld, false); + P_TranslateLineDef(ld, &mld); ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY)); } if (passuse && (ld->activation & SPAC_Use)) diff --git a/src/p_xlat.cpp b/src/p_xlat.cpp index 040ce47db..6e1718273 100644 --- a/src/p_xlat.cpp +++ b/src/p_xlat.cpp @@ -60,7 +60,7 @@ typedef enum PushMany, } triggertype_e; -void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setid) +void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid) { unsigned short special = (unsigned short) LittleShort(mld->special); short tag = LittleShort(mld->tag); @@ -100,13 +100,13 @@ void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, bool setid) } flags = newflags; - if (setid) + if (lineindexforid >= 0) { // For purposes of maintaining BOOM compatibility, each // line also needs to have its ID set to the same as its tag. // An external conversion program would need to do this more // intelligently. - ld->SetMainId(tag); + tagManager.AddLineID(lineindexforid, tag); } // 0 specials are never translated. diff --git a/src/r_defs.h b/src/r_defs.h index 076f7736d..afda92089 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -888,21 +888,12 @@ struct line_t DWORD activation; // activation type int special; fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) - int id; // <--- same as tag or set with Line_SetIdentification int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) - int firstid, nextid; side_t *sidedef[2]; - //DWORD sidenum[2]; // sidenum[1] will be NO_SIDE if one sided fixed_t bbox[4]; // bounding box, for the extent of the LineDef. sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special - - - void SetMainId(int newid); - void ClearIds(); - bool HasId(int id) const; - static void HashIds(); }; // phares 3/14/98 diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index b63ba567f..a006d04a1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4520,7 +4520,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) if ((oldjunk.special = special)) // Linedef type { oldjunk.tag = tag; // Sector tag for linedef - P_TranslateLineDef(&junk, &oldjunk, false); // Turn into native type + P_TranslateLineDef(&junk, &oldjunk); // Turn into native type res = !!P_ExecuteSpecial(junk.special, NULL, self, false, junk.args[0], junk.args[1], junk.args[2], junk.args[3], junk.args[4]); if (res && !(junk.flags & ML_REPEAT_SPECIAL)) // If only once, From cad282142d60dcb1ed53c9545ad4616a4e92542b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Apr 2015 18:22:39 +0200 Subject: [PATCH 06/23] - fixed some last issues with the tag manager. --- src/p_setup.cpp | 2 +- src/p_tags.cpp | 29 +++++++++++++++++++++++++---- src/p_tags.h | 6 ++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 166230e3d..f22979eac 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2223,7 +2223,7 @@ void P_LoadLineDefs2 (MapData * map) mld = (maplinedef2_t *)mldf; ld = lines; - for (i = numlines; i > 0; i--, mld++, ld++) + for (i = 0; i < numlines; i++, mld++, ld++) { int j; diff --git a/src/p_tags.cpp b/src/p_tags.cpp index f4164184f..7e958dcca 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -269,6 +269,29 @@ bool FTagManager::LineHasID(const line_t *line, int tag) const return LineHasID(lineindex(line), tag); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FTagManager::DumpTags() +{ + for (unsigned i = 0; i < allTags.Size(); i++) + { + Printf("Sector %d, tag %d\n", allTags[i].target, allTags[i].tag); + } + for (unsigned i = 0; i < allIDs.Size(); i++) + { + Printf("Line %d, ID %d\n", allIDs[i].target, allIDs[i].tag); + } +} + +CCMD(dumptags) +{ + tagManager.DumpTags(); +} + //----------------------------------------------------------------------------- // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO @@ -290,7 +313,7 @@ int FSectorTagIterator::Next() { while (start >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag; if (start == -1) return -1; - ret = start; + ret = tagManager.allTags[start].target; start = start = tagManager.allTags[start].nexttag; } return ret; @@ -324,9 +347,7 @@ int FLineIdIterator::Next() { while (start >= 0 && tagManager.allIDs[start].tag != searchtag) start = tagManager.allIDs[start].nexttag; if (start == -1) return -1; - int ret = start; + int ret = tagManager.allIDs[start].target; start = start = tagManager.allIDs[start].nexttag; return ret; } - - diff --git a/src/p_tags.h b/src/p_tags.h index 7a63ca74b..2195821c1 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -36,6 +36,10 @@ class FTagManager return sect >= 0 && sect < (int)startForSector.Size() && startForSector[sect] >= 0; } + bool LineHasIDs(int sect) const + { + return sect >= 0 && sect < (int)startForLine.Size() && startForLine[sect] >= 0; + } public: void Clear() @@ -59,6 +63,8 @@ public: void AddSectorTag(int sector, int tag); void AddLineID(int line, int tag); void RemoveSectorTags(int sect); + + void DumpTags(); }; extern FTagManager tagManager; From 3300817d65cb57b2428bc962deda305ae45c1d95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 20 Apr 2015 23:20:56 +0200 Subject: [PATCH 07/23] - removed some leftover code from initial development in the DoomEdNum parser. --- src/g_doomedmap.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index c9deb7256..45224329d 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -213,13 +213,12 @@ void FMapInfoParser::ParseDoomEdNums() DoomEdFromMapinfo.Insert(ednum, editem); continue; } - sc.MustGetStringName(","); sc.MustGetNumber(); } int i = 0; while (i < 5) { - editem.args[i++] = sc.Number; + editem.args[i] = sc.Number; i++; if (!sc.CheckString(",")) break; sc.MustGetNumber(); From 3061bcf60403cd5ce598fca8194394f24e987c95 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 17:22:57 -0500 Subject: [PATCH 08/23] Add p_tags.(cpp|h) to solution --- zdoom.vcproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zdoom.vcproj b/zdoom.vcproj index ef356b44a..d171b18eb 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -890,6 +890,10 @@ RelativePath=".\src\p_switch.cpp" > + + @@ -1451,6 +1455,10 @@ RelativePath=".\src\p_spec.h" > + + From f7bd3acec4bde2223771f60ef7b07a48ee9264b7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 17:34:36 -0500 Subject: [PATCH 09/23] Add OpenString to FScanner class --- src/p_udmf.cpp | 4 ++-- src/sc_man.cpp | 15 ++++++++++++++- src/sc_man.h | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 8992c3984..0434d8bce 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1061,7 +1061,7 @@ public: if (tagstring.IsNotEmpty()) { FScanner sc; - sc.OpenMem("tagstring", tagstring.GetChars(), tagstring.Len()); + sc.OpenString("tagstring", tagstring); // scan the string as long as valid numbers can be found while (sc.CheckNumber()) { @@ -1536,7 +1536,7 @@ public: if (tagstring.IsNotEmpty()) { FScanner sc; - sc.OpenMem("tagstring", tagstring.GetChars(), tagstring.Len()); + sc.OpenString("tagstring", tagstring); // scan the string as long as valid numbers can be found while (sc.CheckNumber()) { diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 4b9d710a3..9babe2e9c 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -195,9 +195,22 @@ void FScanner::OpenFile (const char *name) //========================================================================== void FScanner::OpenMem (const char *name, const char *buffer, int size) +{ + OpenString(name, FString(buffer, size)); +} + +//========================================================================== +// +// FScanner :: OpenString +// +// Like OpenMem, but takes a string directly. +// +//========================================================================== + +void FScanner::OpenString (const char *name, FString buffer) { Close (); - ScriptBuffer = FString(buffer, size); + ScriptBuffer = buffer; ScriptName = name; LumpNum = -1; PrepareScript (); diff --git a/src/sc_man.h b/src/sc_man.h index 3d9c2bec9..ba84cd00c 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -21,6 +21,7 @@ public: void Open(const char *lumpname); void OpenFile(const char *filename); void OpenMem(const char *name, const char *buffer, int size); + void OpenString(const char *name, FString buffer); void OpenLumpNum(int lump); void Close(); From dba76c1aea8fe8e9699d81eee67eeb95d383fa5d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 18:32:45 -0500 Subject: [PATCH 10/23] Disable PCM-8 output when not using DirectSound - PCM-8 sounds like garbage with WASAPI and WaveOut, so force anything not DirectSound to use PCM-16 if PCM-8 is selected. --- src/sound/fmodsound.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index b5af6a485..49d53117f 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -895,6 +895,15 @@ bool FMODSoundRenderer::Init() // Set software format eval = Enum_NumForName(SoundFormatNames, snd_output_format); format = eval >= 0 ? FMOD_SOUND_FORMAT(eval) : FMOD_SOUND_FORMAT_PCM16; + if (format == FMOD_SOUND_FORMAT_PCM8) + { + // PCM-8 sounds like garbage with anything but DirectSound. + FMOD_OUTPUTTYPE output; + if (FMOD_OK != Sys->getOutput(&output) || output != FMOD_OUTPUTTYPE_DSOUND) + { + format = FMOD_SOUND_FORMAT_PCM16; + } + } eval = Enum_NumForName(ResamplerNames, snd_resampler); resampler = eval >= 0 ? FMOD_DSP_RESAMPLER(eval) : FMOD_DSP_RESAMPLER_LINEAR; // These represented the frequency limits for hardware channels, which we never used anyway. From 7ee185340341eecf1d621b01176531cd011f7bb7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 19:09:33 -0500 Subject: [PATCH 11/23] Remove OpenAL and Sound Manager output options for FMOD - OpenAL never actualy worked properly and was removed in later FMODs. - Sound Manager was deprecated by Apple long ago and is not supported for 64-bit applications. It was also removed in later FMODs. --- src/sound/fmodsound.cpp | 6 ------ wadsrc/static/menudef.txt | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 49d53117f..1739556b4 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -165,9 +165,6 @@ static const FEnumList OutputNames[] = { "Windows Multimedia", FMOD_OUTPUTTYPE_WINMM }, { "WinMM", FMOD_OUTPUTTYPE_WINMM }, { "WaveOut", FMOD_OUTPUTTYPE_WINMM }, -#if FMOD_VERSION < 0x43400 - { "OpenAL", FMOD_OUTPUTTYPE_OPENAL }, -#endif { "WASAPI", FMOD_OUTPUTTYPE_WASAPI }, { "ASIO", FMOD_OUTPUTTYPE_ASIO }, @@ -182,9 +179,6 @@ static const FEnumList OutputNames[] = { "SDL", 666 }, // Mac -#if FMOD_VERSION < 0x43000 - { "Sound Manager", FMOD_OUTPUTTYPE_SOUNDMANAGER }, -#endif { "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO }, { NULL, 0 } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 07f841545..d62db3a75 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1390,7 +1390,6 @@ OptionString SoundOutputsWindows "WASAPI", "Vista WASAPI" "ASIO", "ASIO" "WaveOut", "WaveOut" - "OpenAL", "OpenAL (very beta)" "No sound", "No sound" } @@ -1408,7 +1407,6 @@ OptionString SoundOutputsUnix OptionString SoundOutputsMac { - "Sound Manager", "Sound Manager" "Core Audio", "Core Audio" "No sound", "No sound" } From a7ff9478a7d45a0734c91f2980223ebba2524ce7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 20:28:09 -0500 Subject: [PATCH 12/23] Fixed: S_PrecacheLevel() could create orphan channels - S_PrecacheLevel() must also mark currently playing sounds as used. If we don't, the sound could be unloaded and the underlying channel stopped without triggering a channel callback. That would leave the code in s_sound.cpp thinking the sound is still playing even though it isn't. - Added an invalid channel check to FMODSoundRenderer::StopChannel() so that orphan channels passed to it will be returned at least when S_StopAllChannels() is called. --- src/s_sound.cpp | 13 ++++++------- src/sound/fmodsound.cpp | 7 +++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 5b3d5457b..7b543c4e4 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -383,7 +383,7 @@ void S_Start () { // kill all playing sounds at start of level (trust me - a good idea) S_StopAllChannels(); - + // Check for local sound definitions. Only reload if they differ // from the previous ones. FString LocalSndInfo; @@ -487,6 +487,11 @@ void S_PrecacheLevel () { level.info->PrecacheSounds[i].MarkUsed(); } + // Don't unload sounds that are playing right now. + for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) + { + chan->SoundID.MarkUsed(); + } for (i = 1; i < S_sfx.Size(); ++i) { @@ -2083,12 +2088,6 @@ void S_ChannelEnded(FISoundChannel *ichan) evicted = (pos < len); } } - /* - else - { - evicted = false; - } - */ if (!evicted) { S_ReturnChannel(schan); diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 1739556b4..269720c48 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -2050,7 +2050,7 @@ FISoundChannel *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FISou //========================================================================== // -// FMODSoundRenderer :: StopSound +// FMODSoundRenderer :: StopChannel // //========================================================================== @@ -2058,7 +2058,10 @@ void FMODSoundRenderer::StopChannel(FISoundChannel *chan) { if (chan != NULL && chan->SysChannel != NULL) { - ((FMOD::Channel *)chan->SysChannel)->stop(); + if (((FMOD::Channel *)chan->SysChannel)->stop() == FMOD_ERR_INVALID_HANDLE) + { // The channel handle was invalid; pretend it ended. + S_ChannelEnded(chan); + } } } From 03c3621bb4d06547317985ea892c5ab6099f685c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 22:13:49 -0500 Subject: [PATCH 13/23] Use a different var to track unset DTA_FillColor instead of a default value - If palette index 255 happens to be white (e.g. as in Hexen), trying to use white with DTA_FillColor would treat it as if you had never passed it to DrawTexture(). --- src/v_draw.cpp | 4 +++- src/v_video.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index e2890841b..ce502c772 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -333,6 +333,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag int intval; bool translationset = false; bool virtBottom; + bool fillcolorset = false; if (img == NULL || img->UseType == FTexture::TEX_Null) { @@ -539,6 +540,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag case DTA_FillColor: parms->fillcolor = va_arg(tags, uint32); + fillcolorset = true; break; case DTA_Translation: @@ -711,7 +713,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag if (parms->style.BlendOp == 255) { - if (parms->fillcolor != ~0u) + if (fillcolorset) { if (parms->alphaChannel) { diff --git a/src/v_video.h b/src/v_video.h index 5250cdaa9..7593b7b4b 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -74,7 +74,7 @@ enum DTA_DestWidth, // width of area to draw to DTA_DestHeight, // height of area to draw to DTA_Alpha, // alpha value for translucency - DTA_FillColor, // color to stencil onto the destination + DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers) DTA_Translation, // translation table to recolor the source DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac From d6b8603cb6a762889a3586619e4a7ef7bea4fe14 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 22:27:56 -0500 Subject: [PATCH 14/23] Ignore sv_unlimited_pickup on items that stay - See http://forum.zdoom.org/viewtopic.php?f=2&t=47790 --- src/g_shared/a_pickups.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 2888ea2b6..5eda53ad6 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -593,7 +593,7 @@ bool AInventory::HandlePickup (AInventory *item) { if (item->GetClass() == GetClass()) { - if (Amount < MaxAmount || sv_unlimited_pickup) + if (Amount < MaxAmount || (sv_unlimited_pickup && !item->ShouldStay())) { if (Amount > 0 && Amount + item->Amount < 0) { From 0cbb3132e6612486d583c5ec08c6c6aaa8b95a01 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 22:35:38 -0500 Subject: [PATCH 15/23] Don't spam Dropped packet messages for disconnected players --- src/i_net.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i_net.cpp b/src/i_net.cpp index d3958e1e1..5957846d2 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -319,7 +319,11 @@ void PacketGet (void) } else if (c > 0) { //The packet is not from any in-game node, so we might as well discard it. - Printf("Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); + // Don't show the message for disconnect notifications. + if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT) + { + DPrintf("Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); + } doomcom.remotenode = -1; return; } From ca16d99445f881ba3b2dac1a37f2fa720a07cde2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 22:57:15 -0500 Subject: [PATCH 16/23] Fixed: FOptionMenuItem::GetIndent() did not handle localized strings --- src/menu/optionmenu.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index 9a7715265..57e69cfab 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -489,7 +489,13 @@ bool FOptionMenuItem::MouseEvent(int type, int x, int y) int FOptionMenuItem::GetIndent() { - return mCentered? 0 : SmallFont->StringWidth(mLabel); + if (mCentered) + { + return 0; + } + const char *label = mLabel; + if (*label == '$') label = GStrings(label+1); + return SmallFont->StringWidth(label); } void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed) From 8d501fdb9f1003ba839f697ec4c27dc9d5dc8f4c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 22 Apr 2015 23:22:27 -0500 Subject: [PATCH 17/23] Fix some issues with changing player viewheight at runtime - Viewheight change was delayed: Viewheight must be copied to player structure as well as the PlayerPawn. Not sure if should actually use deltaviewheight to spread the change out over a few tics instead of being instant. - Viewheight not preserved when travelling: player->viewheight must be restored from pawn->ViewHeight, because the temporary player set it back to the default viewheight. --- src/fragglescript/t_cmd.cpp | 1 + src/g_level.cpp | 1 + src/p_acs.cpp | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/src/fragglescript/t_cmd.cpp b/src/fragglescript/t_cmd.cpp index 190c6b984..74f366357 100644 --- a/src/fragglescript/t_cmd.cpp +++ b/src/fragglescript/t_cmd.cpp @@ -169,6 +169,7 @@ void FS_EmulateCmd(char * string) { // No, this is not correct. But this is the way Legacy WADs expect it to be handled! if (players[i].mo != NULL) players[i].mo->ViewHeight = playerviewheight; + players[i].viewheight = playerviewheight; players[i].Uncrouch(); } while (sc.GetString()) diff --git a/src/g_level.cpp b/src/g_level.cpp index fd6d8049a..713205f6f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1229,6 +1229,7 @@ void G_FinishTravel () pawn->lastenemy = NULL; pawn->player->mo = pawn; pawn->player->camera = pawn; + pawn->player->viewheight = pawn->ViewHeight; pawn->flags2 &= ~MF2_BLASTED; DObject::StaticPointerSubstitution (oldpawn, pawn); oldpawn->Destroy(); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 111fb99ba..43d7c7bd5 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3899,7 +3899,13 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) case APROP_ViewHeight: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + { static_cast(actor)->ViewHeight = value; + if (actor->player != NULL) + { + actor->player->viewheight = value; + } + } break; case APROP_AttackZOffset: From a54404074a290db80cb6789f273cf8715eef94ac Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Apr 2015 20:09:12 +0200 Subject: [PATCH 18/23] - fixed: IDs that map to nothing must be removed from the spawn/conversation ID maps. --- src/p_things.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index faf1091d5..50e15a1a8 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -659,8 +659,12 @@ void InitClassMap(FClassMap &themap, SpawnMap &thedata) pair->Value.filename.GetChars(), pair->Value.linenum, pair->Value.classname.GetChars()); error++; } + themap.Insert(pair->Key, cls); + } + else + { + themap.Remove(pair->Key); } - themap.Insert(pair->Key, cls); } if (error > 0) { From 6a6836b1e7a4e558313ffd630b839ddaf890bb46 Mon Sep 17 00:00:00 2001 From: Chronos Ouroboros Date: Thu, 23 Apr 2015 15:11:54 -0300 Subject: [PATCH 19/23] Added SpiralOffset to railgun functions. --- src/p_effect.cpp | 4 ++-- src/p_effect.h | 2 +- src/p_local.h | 2 +- src/p_map.cpp | 4 ++-- src/thingdef/thingdef_codeptr.cpp | 10 ++++++---- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/shared/inventory.txt | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 5633b4bff..1b7ce0bc8 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -586,7 +586,7 @@ void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, i } } -void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff, int flags, const PClass *spawnclass, angle_t angle, int duration, float sparsity, float drift) +void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff, int flags, const PClass *spawnclass, angle_t angle, int duration, float sparsity, float drift, int SpiralOffset) { double length, lengthsquared; int steps, i; @@ -678,7 +678,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end color1 = color1 == 0 ? -1 : ParticleColor(color1); pos = start; - deg = FAngle(270); + deg = FAngle(SpiralOffset); for (i = spiral_steps; i; i--) { particle_t *p = NewParticle (); diff --git a/src/p_effect.h b/src/p_effect.h index 755dd9ff3..6ca9dfea9 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -88,7 +88,7 @@ void P_RunEffects (void); void P_RunEffect (AActor *actor, int effects); -void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff = 0, int flags = 0, const PClass *spawnclass = NULL, angle_t angle = 0, int duration = 35, float sparsity = 1.0, float drift = 1.0); +void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff = 0, int flags = 0, const PClass *spawnclass = NULL, angle_t angle = 0, int duration = 35, float sparsity = 1.0, float drift = 1.0, int SpiralOffset = 270); void P_DrawSplash (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int kind); void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind); void P_DisconnectEffect (AActor *actor); diff --git a/src/p_local.h b/src/p_local.h index d4571421b..682101e7f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -474,7 +474,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); void P_CheckSplash(AActor *self, fixed_t distance); -void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, float maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, float maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags { diff --git a/src/p_map.cpp b/src/p_map.cpp index 1ad1728ce..6370fa849 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4140,7 +4140,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) // // //========================================================================== -void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, float maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, float sparsity, float drift, const PClass *spawnclass) +void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, float maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, float sparsity, float drift, const PClass *spawnclass, int SpiralOffset) { fixed_t vx, vy, vz; angle_t angle, pitch; @@ -4292,7 +4292,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i end.X = FIXED2FLOAT(trace.X); end.Y = FIXED2FLOAT(trace.Y); end.Z = FIXED2FLOAT(trace.Z); - P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift); + P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift, SpiralOffset); } //========================================================================== diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a006d04a1..b4c6a219a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1495,7 +1495,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { - ACTION_PARAM_START(16); + ACTION_PARAM_START(17); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_BOOL(UseAmmo, 2); @@ -1512,6 +1512,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) ACTION_PARAM_FLOAT(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); ACTION_PARAM_FIXED(Spawnofs_Z, 15); + ACTION_PARAM_INT(SpiralOffset, 16); if(Range==0) Range=8192*FRACUNIT; if(Sparsity==0) Sparsity=1.0; @@ -1540,7 +1541,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) slope = pr_crailgun.Random2() * (Spread_Z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angle, slope, Range, Duration, Sparsity, DriftSpeed, SpawnClass); + P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angle, slope, Range, Duration, Sparsity, DriftSpeed, SpawnClass, SpiralOffset); } //========================================================================== @@ -1558,7 +1559,7 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { - ACTION_PARAM_START(16); + ACTION_PARAM_START(17); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_COLOR(Color1, 2); @@ -1575,6 +1576,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) ACTION_PARAM_FLOAT(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); ACTION_PARAM_FIXED(Spawnofs_Z, 15); + ACTION_PARAM_INT(SpiralOffset, 16); if(Range==0) Range=8192*FRACUNIT; if(Sparsity==0) Sparsity=1.0; @@ -1658,7 +1660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) slopeoffset = pr_crailgun.Random2() * (Spread_Z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angleoffset, slopeoffset, Range, Duration, Sparsity, DriftSpeed, SpawnClass); + P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angleoffset, slopeoffset, Range, Duration, Sparsity, DriftSpeed, SpawnClass, SpiralOffset); self->x = saved_x; self->y = saved_y; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 7d8fad5bf..8a31b05c0 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -210,7 +210,7 @@ ACTOR Actor native //: Thinker action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET); - action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0); + action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); action native A_JumpIfCloser(float distance, state label); action native A_JumpIfTracerCloser(float distance, state label); diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 7860b9387..0c106417b 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -11,7 +11,7 @@ ACTOR Inventory native action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); - action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0); + action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_Light(int extralight); action native A_Light0(); action native A_Light1(); From 920a4fbf4595ab4f677c19aeb90464b8bdf118ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Apr 2015 21:27:36 +0200 Subject: [PATCH 20/23] - fixed: The HashTags function considered sector and line #0 invalid. --- src/p_tags.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 7e958dcca..d5c03ec9d 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -163,7 +163,7 @@ void FTagManager::HashTags() // Proceed from last to first so that lower targets appear first for (int i = allTags.Size() - 1; i >= 0; i--) { - if (allTags[i].target > 0) // only link valid entries + if (allTags[i].target >= 0) // only link valid entries { int hash = ((unsigned int)allTags[i].tag) % FTagManager::TAG_HASH_SIZE; allTags[i].nexttag = TagHashFirst[hash]; @@ -173,7 +173,7 @@ void FTagManager::HashTags() for (int i = allIDs.Size() - 1; i >= 0; i--) { - if (allIDs[i].target > 0) // only link valid entries + if (allIDs[i].target >= 0) // only link valid entries { int hash = ((unsigned int)allIDs[i].tag) % FTagManager::TAG_HASH_SIZE; allIDs[i].nexttag = IDHashFirst[hash]; From 75471df7877f23fe39a1e1784186388c6622bf00 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 24 Apr 2015 22:26:57 -0400 Subject: [PATCH 21/23] - Made a few Win32 calls optional in order to restore capatibility with Windows NT 4.0 (not that anyone is using NT 4, but it was a trivial fix) --- src/m_specialpaths.cpp | 26 ++++++++++++-------------- src/win32/i_system.cpp | 11 +++++++++-- src/win32/i_system.h | 29 +++++++++++++++++++++++++++++ src/win32/win32video.cpp | 5 ++++- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index a45c23dc7..086f170f8 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -22,6 +22,8 @@ #if defined(_WIN32) +#include "i_system.h" + typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); //=========================================================================== @@ -73,18 +75,7 @@ bool UseKnownFolders() bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) { - static GKFP SHGetKnownFolderPath = NULL; - static bool tested = false; - - if (!tested) - { - tested = true; - HMODULE shell32 = GetModuleHandle("shell32.dll"); - if (shell32 != NULL) - { - SHGetKnownFolderPath = (GKFP)GetProcAddress(shell32, "SHGetKnownFolderPath"); - } - } + static TOptWin32Proc SHGetKnownFolderPath("shell32.dll", "SHGetKnownFolderPath"); char pathstr[MAX_PATH]; @@ -92,6 +83,13 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create // new to Vista, hence the reason we support both. if (SHGetKnownFolderPath == NULL) { + static TOptWin32Proc + SHGetFolderPathA("shell32.dll", "SHGetFolderPathA"); + + // NT4 doesn't even have this function. + if (SHGetFolderPathA == NULL) + return false; + if (shell_folder < 0) { // Not supported by SHGetFolderPath return false; @@ -100,7 +98,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create { shell_folder |= CSIDL_FLAG_CREATE; } - if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr))) + if (FAILED(SHGetFolderPathA.Call(NULL, shell_folder, NULL, 0, pathstr))) { return false; } @@ -110,7 +108,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create else { PWSTR wpath; - if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) + if (FAILED(SHGetKnownFolderPath.Call(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) { return false; } diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 2dabe7de9..5b6a69c63 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1600,13 +1600,20 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { - DWORD buffsize = GetLongPathName(shortpath.GetChars(), NULL, 0); + static TOptWin32Proc + GetLongPathName("kernel32.dll", "GetLongPathNameW", "GetLongPathNameA"); + + // Doesn't exist on NT4 + if (GetLongPathName == NULL) + return shortpath; + + DWORD buffsize = GetLongPathName.Call(shortpath.GetChars(), NULL, 0); if (buffsize == 0) { // nothing to change (it doesn't exist, maybe?) return shortpath; } TCHAR *buff = new TCHAR[buffsize]; - DWORD buffsize2 = GetLongPathName(shortpath.GetChars(), buff, buffsize); + DWORD buffsize2 = GetLongPathName.Call(shortpath.GetChars(), buff, buffsize); if (buffsize2 >= buffsize) { // Failure! Just return the short path delete[] buff; diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 647a08d13..6872ca232 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -51,6 +51,35 @@ typedef enum { extern os_t OSPlatform; +// Helper template so that we can access newer Win32 functions with a single static +// variable declaration. If this were C++11 it could be totally transparent. +template +class TOptWin32Proc +{ + static Proto GetOptionalWin32Proc(const char* module, const char* function, const char* alt) + { + HMODULE hmodule = GetModuleHandle(module); + if (hmodule == NULL) + return NULL; + + Proto ret = (Proto)GetProcAddress(hmodule, function); + if(ret != NULL || alt == NULL) + return ret; + + // Lookup alternate function name (ex. ProcW -> ProcA) + return (Proto)GetProcAddress(hmodule, alt); + } + +public: + const Proto Call; + + TOptWin32Proc(const char* module, const char* function, const char* alt=NULL) + : Call(GetOptionalWin32Proc(module, function, alt)) {} + + // Wrapper object can be tested against NULL, but not directly called. + operator const void*() const { return Call; } +}; + // Called by DoomMain. void I_Init (void); diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 8aa74bfb5..690bb5725 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -414,7 +414,10 @@ void Win32Video::DumpAdapters() HMONITOR hm = D3D->GetAdapterMonitor(i); MONITORINFOEX mi; mi.cbSize = sizeof(mi); - if (GetMonitorInfo(hm, &mi)) + + TOptWin32Proc GetMonitorInfo("user32.dll", "GetMonitorInfoW"); + assert(GetMonitorInfo != NULL); // Missing in NT4, but so is D3D + if (GetMonitorInfo.Call(hm, &mi)) { mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s", mi.rcMonitor.right - mi.rcMonitor.left, From 0fd93cc033d9a40f1b7e9e73fb532897cc710a10 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 25 Apr 2015 18:10:26 +1200 Subject: [PATCH 22/23] Slightly more information on ACS serialize errors --- src/p_acs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 43d7c7bd5..753d7728f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1562,7 +1562,7 @@ void FBehavior::StaticSerializeModuleStates (FArchive &arc) if (modnum != StaticModules.Size()) { - I_Error ("Level was saved with a different number of ACS modules."); + I_Error("Level was saved with a different number of ACS modules. (Have %d, save has %d)", StaticModules.Size(), modnum); } for (modnum = 0; modnum < StaticModules.Size(); ++modnum) @@ -1583,7 +1583,7 @@ void FBehavior::StaticSerializeModuleStates (FArchive &arc) if (stricmp (modname, module->ModuleName) != 0) { delete[] modname; - I_Error ("Level was saved with a different set of ACS modules."); + I_Error("Level was saved with a different set or order of ACS modules. (Have %s, save has %s)", module->ModuleName, modname); } else if (ModSize != module->GetDataSize()) { From 682f3e230a382f72342e43ee8f0c603f211c3314 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 09:08:59 +0200 Subject: [PATCH 23/23] - fixed: We should not try calling unicode functions on ASCII strings. Should ZDoom ever switch to unicode I_GetLongPathName will have to be adjusted, but for now it must call GetLongPathNameA, not GetLongPathNameW. --- src/win32/i_system.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 5b6a69c63..d25229b67 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1601,7 +1601,7 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { static TOptWin32Proc - GetLongPathName("kernel32.dll", "GetLongPathNameW", "GetLongPathNameA"); + GetLongPathName("kernel32.dll", "GetLongPathNameA", NULL); // Doesn't exist on NT4 if (GetLongPathName == NULL)