mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-30 15:52:09 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
Conflicts: src/p_3dfloors.cpp
This commit is contained in:
commit
ab1d90038c
55 changed files with 967 additions and 557 deletions
|
@ -119,6 +119,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
blockhitscan = <bool>; // Line blocks hitscan attacks
|
||||
locknumber = <int>; // Line special is locked
|
||||
arg0str = <string>; // Alternate string-based version of arg0
|
||||
moreids = <string>; // Additional line IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
|
||||
|
||||
transparent = <bool>; // true = line is a Strife transparent line (alpha 0.25)
|
||||
|
||||
|
@ -201,6 +202,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
// sound sequence thing in the sector will override this property.
|
||||
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
||||
waterzone = <bool>; // Sector is under water and swimmable
|
||||
moreids = <string>; // 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
|
||||
===============================================================================
|
||||
|
|
|
@ -932,6 +932,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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<GKFP> 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<HRESULT(*)(HWND, int, HANDLE, DWORD, LPTSTR)>
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -326,6 +326,7 @@ xx(Arg4)
|
|||
xx(Arg0Str)
|
||||
xx(Arg1Str)
|
||||
xx(Id)
|
||||
xx(MoreIds)
|
||||
xx(V1)
|
||||
xx(V2)
|
||||
|
||||
|
|
|
@ -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<OPLDump *>(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<OPLDump *>(chips[0])->WriteDelay(ticks);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -850,7 +850,7 @@ void P_Spawn3DFloors (void)
|
|||
{
|
||||
if (line->args[1]&8)
|
||||
{
|
||||
line->id = line->args[4];
|
||||
tagManager.AddLineID(i, line->args[4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
@ -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)) ||
|
||||
|
@ -3899,7 +3899,13 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
|
|||
|
||||
case APROP_ViewHeight:
|
||||
if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
|
||||
{
|
||||
static_cast<APlayerPawn *>(actor)->ViewHeight = value;
|
||||
if (actor->player != NULL)
|
||||
{
|
||||
actor->player->viewheight = value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APROP_AttackZOffset:
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
@ -408,8 +412,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);
|
||||
|
|
|
@ -825,77 +825,6 @@ sector_t *sector_t::GetHeightSec() const
|
|||
}
|
||||
|
||||
|
||||
bool sector_t::HasTag(int checktag) const
|
||||
{
|
||||
return tag == checktag;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int line_t::GetMainId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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)];
|
||||
|
@ -2218,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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -2493,7 +2497,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 +3133,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,8 +3212,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();
|
||||
line_t::HashIds();
|
||||
tagManager.HashTags();
|
||||
times[4].Unclock();
|
||||
|
||||
times[5].Clock();
|
||||
|
@ -3340,6 +3343,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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -283,7 +232,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
|
|||
!repeat && // only non-repeatable triggers
|
||||
(special<Generic_Floor || special>Generic_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
|
||||
{
|
||||
|
@ -1792,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);
|
||||
}
|
||||
|
@ -2200,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;
|
||||
|
|
60
src/p_spec.h
60
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
|
||||
|
|
353
src/p_tags.cpp
Normal file
353
src/p_tags.cpp
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
** 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"
|
||||
#include "c_dispatch.h"
|
||||
|
||||
FTagManager tagManager;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
{
|
||||
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::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--)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
//
|
||||
// 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 >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag;
|
||||
if (start == -1) return -1;
|
||||
ret = tagManager.allTags[start].target;
|
||||
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 (tagManager.SectorHasTag(i, searchtag)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// killough 4/16/98: Same thing, only for linedefs
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int FLineIdIterator::Next()
|
||||
{
|
||||
while (start >= 0 && tagManager.allIDs[start].tag != searchtag) start = tagManager.allIDs[start].nexttag;
|
||||
if (start == -1) return -1;
|
||||
int ret = tagManager.allIDs[start].target;
|
||||
start = start = tagManager.allIDs[start].nexttag;
|
||||
return ret;
|
||||
}
|
133
src/p_tags.h
Normal file
133
src/p_tags.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
#ifndef P_TAGS_H
|
||||
#define P_TAGS_H 1
|
||||
|
||||
#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 FLineIdIterator;
|
||||
|
||||
class FTagManager
|
||||
{
|
||||
enum
|
||||
{
|
||||
TAG_HASH_SIZE = 256
|
||||
};
|
||||
|
||||
friend class FSectorTagIterator;
|
||||
friend class FLineIdIterator;
|
||||
|
||||
TArray<FTagItem> allTags;
|
||||
TArray<FTagItem> allIDs;
|
||||
TArray<int> startForSector;
|
||||
TArray<int> startForLine;
|
||||
int TagHashFirst[TAG_HASH_SIZE];
|
||||
int IDHashFirst[TAG_HASH_SIZE];
|
||||
|
||||
bool SectorHasTags(int sect) const
|
||||
{
|
||||
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()
|
||||
{
|
||||
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) 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);
|
||||
|
||||
void DumpTags();
|
||||
};
|
||||
|
||||
extern FTagManager tagManager;
|
||||
|
||||
class FSectorTagIterator
|
||||
{
|
||||
protected:
|
||||
int searchtag;
|
||||
int start;
|
||||
|
||||
public:
|
||||
FSectorTagIterator(int tag)
|
||||
{
|
||||
searchtag = tag;
|
||||
start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
|
||||
}
|
||||
|
||||
// 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 = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
int Next();
|
||||
int NextCompat(bool compat, int secnum);
|
||||
};
|
||||
|
||||
class FLineIdIterator
|
||||
{
|
||||
protected:
|
||||
int searchtag;
|
||||
int start;
|
||||
|
||||
public:
|
||||
FLineIdIterator(int id)
|
||||
{
|
||||
searchtag = id;
|
||||
start = tagManager.IDHashFirst[((unsigned int)id) % FTagManager::TAG_HASH_SIZE];
|
||||
}
|
||||
|
||||
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
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "r_state.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "w_wad.h"
|
||||
#include "p_tags.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -754,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));
|
||||
}
|
||||
|
@ -778,10 +779,11 @@ public:
|
|||
bool strifetrans = false;
|
||||
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;
|
||||
|
@ -814,7 +816,8 @@ public:
|
|||
continue;
|
||||
|
||||
case NAME_Id:
|
||||
ld->SetMainId(CheckInt(key));
|
||||
lineid = CheckInt(key);
|
||||
tagManager.AddLineID(index, lineid);
|
||||
continue;
|
||||
|
||||
case NAME_Sidefront:
|
||||
|
@ -1037,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))
|
||||
{
|
||||
|
@ -1060,6 +1058,17 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (tagstring.IsNotEmpty())
|
||||
{
|
||||
FScanner sc;
|
||||
sc.OpenString("tagstring", tagstring);
|
||||
// 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;
|
||||
|
@ -1067,8 +1076,8 @@ public:
|
|||
maplinedef_t mld;
|
||||
memset(&mld, 0, sizeof(mld));
|
||||
mld.special = ld->special;
|
||||
mld.tag = ld->GetMainId();
|
||||
P_TranslateLineDef(ld, &mld, false);
|
||||
mld.tag = lineid;
|
||||
P_TranslateLineDef(ld, &mld);
|
||||
ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY));
|
||||
}
|
||||
if (passuse && (ld->activation & SPAC_Use))
|
||||
|
@ -1267,6 +1276,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;
|
||||
|
@ -1330,7 +1340,7 @@ public:
|
|||
continue;
|
||||
|
||||
case NAME_Id:
|
||||
sec->SetMainTag((short)CheckInt(key));
|
||||
tagManager.AddSectorTag(index, CheckInt(key));
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
@ -1508,28 +1518,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.OpenString("tagstring", tagstring);
|
||||
// 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
@ -307,7 +307,7 @@ void P_TranslateTeleportThings ()
|
|||
|
||||
while ( (dest = iterator.Next()) )
|
||||
{
|
||||
if (dest->Sector->GetMainTag() == 0)
|
||||
if (!tagManager.SectorHasTags(dest->Sector))
|
||||
{
|
||||
dest->tid = 1;
|
||||
dest->AddToHash ();
|
||||
|
|
18
src/r_defs.h
18
src/r_defs.h
|
@ -686,11 +686,6 @@ struct sector_t
|
|||
return pos == floor? floorplane:ceilingplane;
|
||||
}
|
||||
|
||||
bool HasTag(int checktag) const;
|
||||
void SetMainTag(int tagnum);
|
||||
int GetMainTag() const;
|
||||
void ClearTags();
|
||||
static void HashTags();
|
||||
|
||||
bool PlaneMoving(int pos);
|
||||
|
||||
|
@ -709,12 +704,9 @@ struct sector_t
|
|||
TObjPtr<AActor> 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.
|
||||
|
||||
|
@ -986,22 +978,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);
|
||||
int GetMainId() const;
|
||||
void ClearIds();
|
||||
bool HasId(int id) const;
|
||||
static void HashIds();
|
||||
};
|
||||
|
||||
// phares 3/14/98
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
@ -895,6 +889,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.
|
||||
|
@ -2047,7 +2050,7 @@ FISoundChannel *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FISou
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMODSoundRenderer :: StopSound
|
||||
// FMODSoundRenderer :: StopChannel
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -2055,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -4520,7 +4522,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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1600,13 +1600,20 @@ unsigned int I_MakeRNGSeed()
|
|||
|
||||
FString I_GetLongPathName(FString shortpath)
|
||||
{
|
||||
DWORD buffsize = GetLongPathName(shortpath.GetChars(), NULL, 0);
|
||||
static TOptWin32Proc<DWORD (WINAPI*)(LPCTSTR, LPTSTR, DWORD)>
|
||||
GetLongPathName("kernel32.dll", "GetLongPathNameA", NULL);
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -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<typename Proto>
|
||||
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);
|
||||
|
||||
|
|
|
@ -414,7 +414,10 @@ void Win32Video::DumpAdapters()
|
|||
HMONITOR hm = D3D->GetAdapterMonitor(i);
|
||||
MONITORINFOEX mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfo(hm, &mi))
|
||||
|
||||
TOptWin32Proc<BOOL(WINAPI*)(HMONITOR, LPMONITORINFO)> 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,
|
||||
|
|
|
@ -210,7 +210,7 @@ ACTOR Actor native //: Thinker
|
|||
action native A_Jump(int chance = 256, state label, ...);
|
||||
action native A_CustomMissile(class<Actor> 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<Actor> 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<Actor> 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<Actor> 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<Actor> 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<Actor> 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);
|
||||
|
|
|
@ -11,7 +11,7 @@ ACTOR Inventory native
|
|||
action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus");
|
||||
action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
|
||||
action native A_FireCustomMissile(class<Actor> 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<Actor> 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<Actor> 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<Actor> 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<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270);
|
||||
action native A_Light(int extralight);
|
||||
action native A_Light0();
|
||||
action native A_Light1();
|
||||
|
|
|
@ -1402,7 +1402,6 @@ OptionString SoundOutputsWindows
|
|||
"WASAPI", "Vista WASAPI"
|
||||
"ASIO", "ASIO"
|
||||
"WaveOut", "WaveOut"
|
||||
"OpenAL", "OpenAL (very beta)"
|
||||
"No sound", "No sound"
|
||||
}
|
||||
|
||||
|
@ -1420,7 +1419,6 @@ OptionString SoundOutputsUnix
|
|||
|
||||
OptionString SoundOutputsMac
|
||||
{
|
||||
"Sound Manager", "Sound Manager"
|
||||
"Core Audio", "Core Audio"
|
||||
"No sound", "No sound"
|
||||
}
|
||||
|
|
|
@ -890,6 +890,10 @@
|
|||
RelativePath=".\src\p_switch.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_tags.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_teleport.cpp"
|
||||
>
|
||||
|
@ -1451,6 +1455,10 @@
|
|||
RelativePath=".\src\p_spec.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_tags.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_terrain.h"
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue