Conflicts:
	src/p_3dfloors.cpp
This commit is contained in:
Christoph Oelckers 2015-04-25 19:45:27 +02:00
commit ab1d90038c
55 changed files with 967 additions and 557 deletions

View file

@ -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
===============================================================================

View file

@ -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

View file

@ -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;

View file

@ -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())

View file

@ -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));

View file

@ -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();

View file

@ -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();

View file

@ -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)
{

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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)

View file

@ -326,6 +326,7 @@ xx(Arg4)
xx(Arg0Str)
xx(Arg1Str)
xx(Id)
xx(MoreIds)
xx(V1)
xx(V2)

View file

@ -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);
}

View file

@ -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 {

View file

@ -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
{

View file

@ -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))
{

View file

@ -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:

View file

@ -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 ();

View file

@ -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);

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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
{

View file

@ -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);
}
//==========================================================================

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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
View 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
View 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

View file

@ -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--;
}

View file

@ -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)
{

View file

@ -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.

View file

@ -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(&sectors[i]));
fwrite (&ms, sizeof(ms), 1, file);
}
return numsectors * sizeof(ms);

View file

@ -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 ();

View file

@ -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

View file

@ -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);

View file

@ -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 ();

View file

@ -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();

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -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)
{

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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();

View file

@ -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"
}

View file

@ -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"
>