Merge branch 'master' into openal

This commit is contained in:
Christoph Oelckers 2015-04-24 09:21:06 +02:00
commit 1f2a431d15
318 changed files with 7825 additions and 5901 deletions

View file

@ -2,8 +2,12 @@ cmake_minimum_required( VERSION 2.4 )
project(ZDoom) project(ZDoom)
if( COMMAND cmake_policy ) if( COMMAND cmake_policy )
cmake_policy( SET CMP0011 NEW ) if( POLICY CMP0011 )
cmake_policy( SET CMP0054 NEW ) cmake_policy( SET CMP0011 NEW )
endif( POLICY CMP0011 )
if( POLICY CMP0054 )
cmake_policy( SET CMP0054 NEW )
endif( POLICY CMP0054 )
endif( COMMAND cmake_policy ) endif( COMMAND cmake_policy )
list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ) list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} )

View file

@ -44,7 +44,9 @@ if(__create_launchers)
endif() endif()
set(__create_launchers YES) set(__create_launchers YES)
cmake_policy( SET CMP0026 OLD ) if( POLICY CMP0026 )
cmake_policy( SET CMP0026 OLD )
endif( POLICY CMP0026 )
include(CleanDirectoryList) include(CleanDirectoryList)

View file

@ -119,6 +119,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
blockhitscan = <bool>; // Line blocks hitscan attacks blockhitscan = <bool>; // Line blocks hitscan attacks
locknumber = <int>; // Line special is locked locknumber = <int>; // Line special is locked
arg0str = <string>; // Alternate string-based version of arg0 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) 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. // sound sequence thing in the sector will override this property.
hidden = <bool>; // if true this sector will not be drawn on the textured automap. hidden = <bool>; // if true this sector will not be drawn on the textured automap.
waterzone = <bool>; // Sector is under water and swimmable 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 * 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!) 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. Changed language describing the DIALOGUE lump to mention USDF as an option.
1.25 19.04.2015
Added 'moreids' for linedefs and sectors.
=============================================================================== ===============================================================================
EOF EOF
=============================================================================== ===============================================================================

View file

@ -783,6 +783,7 @@ set( NOT_COMPILED_SOURCE_FILES
g_hexen/a_fighterquietus.cpp g_hexen/a_fighterquietus.cpp
g_hexen/a_firedemon.cpp g_hexen/a_firedemon.cpp
g_hexen/a_flechette.cpp g_hexen/a_flechette.cpp
g_hexen/a_flies.cpp
g_hexen/a_fog.cpp g_hexen/a_fog.cpp
g_hexen/a_healingradius.cpp g_hexen/a_healingradius.cpp
g_hexen/a_heresiarch.cpp g_hexen/a_heresiarch.cpp
@ -875,6 +876,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
f_wipe.cpp f_wipe.cpp
farchive.cpp farchive.cpp
files.cpp files.cpp
g_doomedmap.cpp
g_game.cpp g_game.cpp
g_hub.cpp g_hub.cpp
g_level.cpp g_level.cpp
@ -935,6 +937,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
p_spec.cpp p_spec.cpp
p_states.cpp p_states.cpp
p_switch.cpp p_switch.cpp
p_tags.cpp
p_teleport.cpp p_teleport.cpp
p_terrain.cpp p_terrain.cpp
p_things.cpp p_things.cpp

View file

@ -1035,7 +1035,7 @@ public:
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
bool isFast(); bool isFast();
bool isSlow(); bool isSlow();
void SetIdle(); void SetIdle(bool nofunction=false);
void ClearCounters(); void ClearCounters();
FState *GetRaiseState(); FState *GetRaiseState();
void Revive(); void Revive();

View file

@ -43,158 +43,11 @@
#include "configfile.h" #include "configfile.h"
#include "i_system.h" #include "i_system.h"
#include "d_event.h" #include "d_event.h"
#include "w_wad.h"
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
/* Default keybindings for Doom (and all other games)
*/
static const FBinding DefBindings[] =
{
{ "`", "toggleconsole" },
{ "1", "slot 1" },
{ "2", "slot 2" },
{ "3", "slot 3" },
{ "4", "slot 4" },
{ "5", "slot 5" },
{ "6", "slot 6" },
{ "7", "slot 7" },
{ "8", "slot 8" },
{ "9", "slot 9" },
{ "0", "slot 0" },
{ "[", "invprev" },
{ "]", "invnext" },
{ "mwheelleft", "invprev" },
{ "mwheelright", "invnext" },
{ "enter", "invuse" },
{ "-", "sizedown" },
{ "=", "sizeup" },
{ "ctrl", "+attack" },
{ "alt", "+strafe" },
{ "shift", "+speed" },
{ "space", "+use" },
{ "rightarrow", "+right" },
{ "leftarrow", "+left" },
{ "uparrow", "+forward" },
{ "downarrow", "+back" },
{ ",", "+moveleft" },
{ ".", "+moveright" },
{ "mouse1", "+attack" },
{ "mouse2", "+strafe" },
{ "mouse3", "+forward" },
{ "mouse4", "+speed" },
{ "capslock", "toggle cl_run" },
{ "f1", "menu_help" },
{ "f2", "menu_save" },
{ "f3", "menu_load" },
{ "f4", "menu_options" },
{ "f5", "menu_display" },
{ "f6", "quicksave" },
{ "f7", "menu_endgame" },
{ "f8", "togglemessages" },
{ "f9", "quickload" },
{ "f11", "bumpgamma" },
{ "f10", "menu_quit" },
{ "tab", "togglemap" },
{ "pause", "pause" },
{ "sysrq", "screenshot" },
{ "t", "messagemode" },
{ "\\", "+showscores" },
{ "f12", "spynext" },
{ "mwheeldown", "weapnext" },
{ "mwheelup", "weapprev" },
// Generic joystick buttons
{ "joy1", "+attack" },
{ "joy2", "+strafe" },
{ "joy3", "+speed" },
{ "joy4", "+use" },
// Xbox 360 / PS2 controllers
{ "pad_a", "+use" },
{ "pad_y", "+jump" },
{ "rtrigger", "+attack" },
{ "ltrigger", "+altattack" },
{ "lshoulder", "weapprev" },
{ "rshoulder", "weapnext" },
{ "dpadleft", "invprev" },
{ "dpadright", "invnext" },
{ "dpaddown", "invuse" },
{ "dpadup", "togglemap" },
{ "pad_start", "pause" },
{ "pad_back", "menu_main" },
{ "lthumb", "crouch" },
{ NULL, NULL }
};
static const FBinding DefRavenBindings[] =
{
{ "pgup", "+moveup" },
{ "ins", "+movedown" },
{ "home", "land" },
{ "pgdn", "+lookup" },
{ "del", "+lookdown" },
{ "end", "centerview" },
{ NULL, NULL }
};
static const FBinding DefHereticBindings[] =
{
{ "backspace", "use ArtiTomeOfPower" },
{ NULL, NULL }
};
static const FBinding DefHexenBindings[] =
{
{ "/", "+jump" },
{ "backspace", "invuseall" },
{ "\\", "use ArtiHealth" },
{ "0", "useflechette" },
{ "9", "use ArtiBlastRadius" },
{ "8", "use ArtiTeleport" },
{ "7", "use ArtiTeleportOther" },
{ "6", "use ArtiPork" },
{ "5", "use ArtiInvulnerability2" },
{ "scroll", "+showscores" },
{ NULL, NULL }
};
static const FBinding DefStrifeBindings[] =
{
{ "a", "+jump" },
{ "w", "showpop 1" },
{ "backspace", "invdrop" },
{ "z", "showpop 3" },
{ "k", "showpop 2" },
{ "q", "invquery" },
{ NULL, NULL }
// not done
// h - use health
};
static const FBinding DefAutomapBindings[] =
{
{ "f", "am_togglefollow" },
{ "g", "am_togglegrid" },
{ "p", "am_toggletexture" },
{ "m", "am_setmark" },
{ "c", "am_clearmarks" },
{ "0", "am_gobig" },
{ "rightarrow", "+am_panright" },
{ "leftarrow", "+am_panleft" },
{ "uparrow", "+am_panup" },
{ "downarrow", "+am_pandown" },
{ "-", "+am_zoomout" },
{ "=", "+am_zoomin" },
{ "kp-", "+am_zoomout" },
{ "kp+", "+am_zoomin" },
{ "mwheelup", "am_zoom 1.2" },
{ "mwheeldown", "am_zoom -1.2" },
{ NULL, NULL }
};
const char *KeyNames[NUM_KEYS] = const char *KeyNames[NUM_KEYS] =
{ {
// This array is dependant on the particular keyboard input // This array is dependant on the particular keyboard input
@ -452,21 +305,6 @@ void FKeyBindings::DoBind (const char *key, const char *bind)
// //
//============================================================================= //=============================================================================
void FKeyBindings::SetBinds(const FBinding *binds)
{
while (binds->Key)
{
DoBind (binds->Key, binds->Bind);
binds++;
}
}
//=============================================================================
//
//
//
//=============================================================================
void FKeyBindings::UnbindAll () void FKeyBindings::UnbindAll ()
{ {
for (int i = 0; i < NUM_KEYS; ++i) for (int i = 0; i < NUM_KEYS; ++i)
@ -785,29 +623,37 @@ CCMD (rebind)
void C_BindDefaults () void C_BindDefaults ()
{ {
Bindings.SetBinds (DefBindings); int lump, lastlump = 0;
if (gameinfo.gametype & (GAME_Raven|GAME_Strife)) while ((lump = Wads.FindLump("DEFBINDS", &lastlump)) != -1)
{ {
Bindings.SetBinds (DefRavenBindings); FScanner sc(lump);
}
if (gameinfo.gametype == GAME_Heretic) while (sc.GetString())
{ {
Bindings.SetBinds (DefHereticBindings); FKeyBindings *dest = &Bindings;
} int key;
if (gameinfo.gametype == GAME_Hexen) // bind destination is optional and is the same as the console command
{ if (sc.Compare("bind"))
Bindings.SetBinds (DefHexenBindings); {
sc.MustGetString();
}
else if (sc.Compare("doublebind"))
{
dest = &DoubleBindings;
sc.MustGetString();
}
else if (sc.Compare("mapbind"))
{
dest = &AutomapBindings;
sc.MustGetString();
}
key = GetConfigKeyFromName(sc.String);
sc.MustGetString();
dest->SetBind(key, sc.String);
}
} }
if (gameinfo.gametype == GAME_Strife)
{
Bindings.SetBinds (DefStrifeBindings);
}
AutomapBindings.SetBinds(DefAutomapBindings);
} }
CCMD(binddefaults) CCMD(binddefaults)

View file

@ -42,19 +42,12 @@ class FCommandLine;
void C_NameKeys (char *str, int first, int second); void C_NameKeys (char *str, int first, int second);
struct FBinding
{
const char *Key;
const char *Bind;
};
class FKeyBindings class FKeyBindings
{ {
FString Binds[NUM_KEYS]; FString Binds[NUM_KEYS];
public: public:
void PerformBind(FCommandLine &argv, const char *msg); void PerformBind(FCommandLine &argv, const char *msg);
void SetBinds(const FBinding *binds);
bool DoKey(event_t *ev); bool DoKey(event_t *ev);
void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL); void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL);
int GetKeysForCommand (const char *cmd, int *first, int *second); int GetKeysForCommand (const char *cmd, int *first, int *second);

View file

@ -450,11 +450,10 @@ CCMD (exec)
for (int i = 1; i < argv.argc(); ++i) for (int i = 1; i < argv.argc(); ++i)
{ {
switch (C_ExecFile (argv[i], gamestate == GS_STARTUP)) if (!C_ExecFile(argv[i]))
{ {
case 1: Printf ("Could not open \"%s\"\n", argv[1]); break; Printf ("Could not exec \"%s\"\n", argv[i]);
case 2: Printf ("Error parsing \"%s\"\n", argv[1]); break; break;
default: break;
} }
} }
} }
@ -641,6 +640,23 @@ CCMD (error_fatal)
} }
} }
//==========================================================================
//
// CCMD crashout
//
// Debugging routine for testing the crash logger.
// Useless in a win32 debug build, because that doesn't enable the crash logger.
//
//==========================================================================
#if !defined(_WIN32) || !defined(_DEBUG)
CCMD (crashout)
{
*(volatile int *)0 = 0;
}
#endif
CCMD (dir) CCMD (dir)
{ {
FString dir, path; FString dir, path;
@ -889,21 +905,42 @@ CCMD(info)
"the NOBLOCKMAP flag or have height/radius of 0.\n"); "the NOBLOCKMAP flag or have height/radius of 0.\n");
} }
//----------------------------------------------------------------------------- typedef bool (*ActorTypeChecker) (AActor *);
//
//
//
//-----------------------------------------------------------------------------
CCMD(monster)
{
AActor * mo;
if (CheckCheatmode ()) return; static bool IsActorAMonster(AActor *mo)
{
return mo->flags3&MF3_ISMONSTER && !(mo->flags&MF_CORPSE) && !(mo->flags&MF_FRIENDLY);
}
static bool IsActorAnItem(AActor *mo)
{
return mo->IsKindOf(RUNTIME_CLASS(AInventory)) && mo->flags&MF_SPECIAL;
}
static bool IsActorACountItem(AActor *mo)
{
return mo->IsKindOf(RUNTIME_CLASS(AInventory)) && mo->flags&MF_SPECIAL && mo->flags&MF_COUNTITEM;
}
static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const char *FilterName)
{
AActor *mo;
const PClass *FilterClass = NULL;
if (FilterName != NULL)
{
FilterClass = PClass::FindClass(FilterName);
if (FilterClass == NULL || FilterClass->ActorInfo == NULL)
{
Printf("%s is not an actor class.\n", FilterName);
return;
}
}
TThinkerIterator<AActor> it; TThinkerIterator<AActor> it;
while ( (mo = it.Next()) ) while ( (mo = it.Next()) )
{ {
if (mo->flags3&MF3_ISMONSTER && !(mo->flags&MF_CORPSE) && !(mo->flags&MF_FRIENDLY)) if ((FilterClass == NULL || mo->IsA(FilterClass)) && IsActorType(mo))
{ {
Printf ("%s at (%d,%d,%d)\n", Printf ("%s at (%d,%d,%d)\n",
mo->GetClass()->TypeName.GetChars(), mo->GetClass()->TypeName.GetChars(),
@ -912,6 +949,18 @@ CCMD(monster)
} }
} }
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
CCMD(monster)
{
if (CheckCheatmode ()) return;
PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// //
@ -919,20 +968,21 @@ CCMD(monster)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CCMD(items) CCMD(items)
{ {
AActor * mo;
if (CheckCheatmode ()) return; if (CheckCheatmode ()) return;
TThinkerIterator<AActor> it;
while ( (mo = it.Next()) ) PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL);
{ }
if (mo->IsKindOf(RUNTIME_CLASS(AInventory)) && mo->flags&MF_SPECIAL)
{ //-----------------------------------------------------------------------------
Printf ("%s at (%d,%d,%d)\n", //
mo->GetClass()->TypeName.GetChars(), //
mo->x >> FRACBITS, mo->y >> FRACBITS, mo->z >> FRACBITS); //
} //-----------------------------------------------------------------------------
} CCMD(countitems)
{
if (CheckCheatmode ()) return;
PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -185,9 +185,6 @@ static const char *KeyConfCommands[] =
"clearplayerclasses" "clearplayerclasses"
}; };
static TArray<FString> StoredStartupSets;
static bool RunningStoredStartups;
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
IMPLEMENT_CLASS (DWaitingCommand) IMPLEMENT_CLASS (DWaitingCommand)
@ -540,18 +537,6 @@ void ResetButtonStates ()
} }
} }
void C_ExecStoredSets()
{
assert(!RunningStoredStartups);
RunningStoredStartups = true;
for (unsigned i = 0; i < StoredStartupSets.Size(); ++i)
{
C_DoCommand(StoredStartupSets[i]);
}
StoredStartupSets.Clear();
RunningStoredStartups = false;
}
void C_DoCommand (const char *cmd, int keynum) void C_DoCommand (const char *cmd, int keynum)
{ {
FConsoleCommand *com; FConsoleCommand *com;
@ -627,22 +612,7 @@ void C_DoCommand (const char *cmd, int keynum)
if ( (com = FindNameInHashTable (Commands, beg, len)) ) if ( (com = FindNameInHashTable (Commands, beg, len)) )
{ {
if (gamestate == GS_STARTUP && !RunningStoredStartups && if (gamestate != GS_STARTUP || ParsingKeyConf ||
len == 3 && strnicmp(beg, "set", 3) == 0)
{
// Save setting of unknown cvars for later, in case a loaded wad has a
// CVARINFO that defines it.
FCommandLine args(beg);
if (args.argc() > 1 && FindCVar(args[1], NULL) == NULL)
{
StoredStartupSets.Push(beg);
}
else
{
com->Run(args, players[consoleplayer].mo, keynum);
}
}
else if (gamestate != GS_STARTUP || ParsingKeyConf ||
(len == 3 && strnicmp (beg, "set", 3) == 0) || (len == 3 && strnicmp (beg, "set", 3) == 0) ||
(len == 7 && strnicmp (beg, "logfile", 7) == 0) || (len == 7 && strnicmp (beg, "logfile", 7) == 0) ||
(len == 9 && strnicmp (beg, "unbindall", 9) == 0) || (len == 9 && strnicmp (beg, "unbindall", 9) == 0) ||
@ -687,15 +657,7 @@ void C_DoCommand (const char *cmd, int keynum)
} }
else else
{ // We don't know how to handle this command { // We don't know how to handle this command
if (gamestate == GS_STARTUP && !RunningStoredStartups) Printf ("Unknown command \"%.*s\"\n", (int)len, beg);
{
// Save it for later, in case a CVARINFO defines it.
StoredStartupSets.Push(beg);
}
else
{
Printf ("Unknown command \"%.*s\"\n", (int)len, beg);
}
} }
} }
} }
@ -1368,7 +1330,7 @@ CCMD (key)
// Execute any console commands specified on the command line. // Execute any console commands specified on the command line.
// These all begin with '+' as opposed to '-'. // These all begin with '+' as opposed to '-'.
void C_ExecCmdLineParams () FExecList *C_ParseCmdLineParams(FExecList *exec)
{ {
for (int currArg = 1; currArg < Args->NumArgs(); ) for (int currArg = 1; currArg < Args->NumArgs(); )
{ {
@ -1389,10 +1351,15 @@ void C_ExecCmdLineParams ()
cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); cmdString = BuildString (cmdlen, Args->GetArgList (argstart));
if (!cmdString.IsEmpty()) if (!cmdString.IsEmpty())
{ {
C_DoCommand (&cmdString[1]); if (exec == NULL)
{
exec = new FExecList;
}
exec->AddCommand(&cmdString[1]);
} }
} }
} }
return exec;
} }
bool FConsoleCommand::IsAlias () bool FConsoleCommand::IsAlias ()
@ -1469,28 +1436,60 @@ void FConsoleAlias::SafeDelete ()
} }
} }
static BYTE PullinBad = 2; void FExecList::AddCommand(const char *cmd, const char *file)
static const char *PullinFile; {
extern TArray<FString> allwads; // Pullins are special and need to be separated from general commands.
// They also turned out to be a really bad idea, since they make things
// more complicated. :(
if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6]))
{
FCommandLine line(cmd);
C_SearchForPullins(this, file, line);
}
// Recursive exec: Parse this file now.
else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4]))
{
FCommandLine argv(cmd);
for (int i = 1; i < argv.argc(); ++i)
{
C_ParseExecFile(argv[i], this);
}
}
else
{
Commands.Push(cmd);
}
}
int C_ExecFile (const char *file, bool usePullin) void FExecList::ExecCommands() const
{
for (unsigned i = 0; i < Commands.Size(); ++i)
{
AddCommandString(Commands[i].LockBuffer());
Commands[i].UnlockBuffer();
}
}
void FExecList::AddPullins(TArray<FString> &wads) const
{
for (unsigned i = 0; i < Pullins.Size(); ++i)
{
D_AddFile(wads, Pullins[i]);
}
}
FExecList *C_ParseExecFile(const char *file, FExecList *exec)
{ {
FILE *f; FILE *f;
char cmd[4096]; char cmd[4096];
int retval = 0; int retval = 0;
BYTE pullinSaved = PullinBad;
const char *fileSaved = PullinFile;
if ( (f = fopen (file, "r")) ) if ( (f = fopen (file, "r")) )
{ {
PullinBad = 1-usePullin; while (fgets(cmd, countof(cmd)-1, f))
PullinFile = file;
while (fgets (cmd, 4095, f))
{ {
// Comments begin with // // Comments begin with //
char *stop = cmd + strlen (cmd) - 1; char *stop = cmd + strlen(cmd) - 1;
char *comment = cmd; char *comment = cmd;
int inQuote = 0; int inQuote = 0;
@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin)
{ // Comment in middle of line { // Comment in middle of line
*comment = 0; *comment = 0;
} }
if (exec == NULL)
AddCommandString (cmd); {
exec = new FExecList;
}
exec->AddCommand(cmd, file);
} }
if (!feof (f)) if (!feof(f))
{ {
retval = 2; Printf("Error parsing \"%s\"\n", file);
} }
fclose (f); fclose(f);
} }
else else
{ {
retval = 1; Printf ("Could not open \"%s\"\n", file);
}
return exec;
}
bool C_ExecFile (const char *file)
{
FExecList *exec = C_ParseExecFile(file, NULL);
if (exec != NULL)
{
exec->ExecCommands();
if (exec->Pullins.Size() > 0)
{
Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n");
}
delete exec;
}
return exec != NULL;
}
void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv)
{
const char *lastSlash;
assert(exec != NULL);
assert(file != NULL);
#ifdef __unix__
lastSlash = strrchr(file, '/');
#else
const char *lastSlash1, *lastSlash2;
lastSlash1 = strrchr(file, '/');
lastSlash2 = strrchr(file, '\\');
lastSlash = MAX(lastSlash1, lastSlash2);
#endif
for (int i = 1; i < argv.argc(); ++i)
{
// Try looking for the wad in the same directory as the .cfg
// before looking for it in the current directory.
if (lastSlash != NULL)
{
FString path(file, (lastSlash - file) + 1);
path += argv[i];
if (FileExists(path))
{
exec->Pullins.Push(path);
continue;
}
}
exec->Pullins.Push(argv[i]);
} }
PullinBad = pullinSaved;
PullinFile = fileSaved;
return retval;
} }
CCMD (pullin) CCMD (pullin)
{ {
if (PullinBad == 2) // Actual handling for pullin is now completely special-cased above
{ Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n"
Printf ("This command is only valid from .cfg\n" "files and only when used at startup.\n");
"files and only when used at startup.\n");
}
else if (argv.argc() > 1)
{
const char *lastSlash;
#ifdef __unix__
lastSlash = strrchr (PullinFile, '/');
#else
const char *lastSlash1, *lastSlash2;
lastSlash1 = strrchr (PullinFile, '/');
lastSlash2 = strrchr (PullinFile, '\\');
lastSlash = MAX (lastSlash1, lastSlash2);
#endif
if (PullinBad)
{
Printf ("Not loading:");
}
for (int i = 1; i < argv.argc(); ++i)
{
if (PullinBad)
{
Printf (" %s", argv[i]);
}
else
{
// Try looking for the wad in the same directory as the .cfg
// before looking for it in the current directory.
char *path = argv[i];
if (lastSlash != NULL)
{
size_t pathlen = lastSlash - PullinFile + strlen (argv[i]) + 2;
path = new char[pathlen];
strncpy (path, PullinFile, (lastSlash - PullinFile) + 1);
strcpy (path + (lastSlash - PullinFile) + 1, argv[i]);
if (!FileExists (path))
{
delete[] path;
path = argv[i];
}
else
{
FixPathSeperator (path);
}
}
D_AddFile (allwads, path);
if (path != argv[i])
{
delete[] path;
}
}
}
if (PullinBad)
{
Printf ("\n");
}
}
} }

View file

@ -39,31 +39,6 @@
class FConfigFile; class FConfigFile;
class APlayerPawn; class APlayerPawn;
extern bool CheckCheatmode (bool printmsg = true);
void C_ExecCmdLineParams ();
void C_ExecStoredSets();
// Add commands to the console as if they were typed in. Can handle wait
// and semicolon-separated commands. This function may modify the source
// string, but the string will be restored to its original state before
// returning. Therefore, commands passed must not be in read-only memory.
void AddCommandString (char *text, int keynum=0);
// Process a single console command. Does not handle wait.
void C_DoCommand (const char *cmd, int keynum=0);
int C_ExecFile (const char *cmd, bool usePullin);
// Write out alias commands to a file for all current aliases.
void C_ArchiveAliases (FConfigFile *f);
void C_SetAlias (const char *name, const char *cmd);
void C_ClearAliases ();
// build a single string out of multiple strings
FString BuildString (int argc, FString *argv);
// Class that can parse command lines // Class that can parse command lines
class FCommandLine class FCommandLine
{ {
@ -83,6 +58,44 @@ private:
bool noescapes; bool noescapes;
}; };
// Contains the contents of an exec'ed file
struct FExecList
{
TArray<FString> Commands;
TArray<FString> Pullins;
void AddCommand(const char *cmd, const char *file = NULL);
void ExecCommands() const;
void AddPullins(TArray<FString> &wads) const;
};
extern bool CheckCheatmode (bool printmsg = true);
FExecList *C_ParseCmdLineParams(FExecList *exec);
// Add commands to the console as if they were typed in. Can handle wait
// and semicolon-separated commands. This function may modify the source
// string, but the string will be restored to its original state before
// returning. Therefore, commands passed must not be in read-only memory.
void AddCommandString (char *text, int keynum=0);
// Process a single console command. Does not handle wait.
void C_DoCommand (const char *cmd, int keynum=0);
FExecList *C_ParseExecFile(const char *file, FExecList *source);
void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args);
bool C_ExecFile(const char *file);
// Write out alias commands to a file for all current aliases.
void C_ArchiveAliases (FConfigFile *f);
void C_SetAlias (const char *name, const char *cmd);
void C_ClearAliases ();
// build a single string out of multiple strings
FString BuildString (int argc, FString *argv);
typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key); typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key);
class FConsoleCommand class FConsoleCommand

View file

@ -957,7 +957,7 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
} }
} }
#elif defined(__sun) || defined(linux) #elif defined(__sun) || defined(__linux__)
//========================================================================== //==========================================================================
// //

View file

@ -49,6 +49,7 @@
#include "gi.h" #include "gi.h"
#include "g_level.h" #include "g_level.h"
#include "p_lnspec.h" #include "p_lnspec.h"
#include "p_tags.h"
#include "r_state.h" #include "r_state.h"
#include "w_wad.h" #include "w_wad.h"
@ -551,7 +552,8 @@ void SetCompatibilityParams()
{ {
if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors) if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors)
{ {
sectors[CompatParams[i + 1]].tag = CompatParams[i + 2]; // this assumes that the sector does not have any tags yet!
tagManager.AddSectorTag(CompatParams[i + 1], CompatParams[i + 2]);
} }
i += 3; i += 3;
break; break;
@ -595,12 +597,13 @@ CCMD (mapchecksum)
else else
{ {
map->GetChecksum(cksum); map->GetChecksum(cksum);
const char *wadname = Wads.GetWadName(Wads.GetLumpFile(map->lumpnum));
delete map; delete map;
for (size_t j = 0; j < sizeof(cksum); ++j) for (size_t j = 0; j < sizeof(cksum); ++j)
{ {
Printf("%02X", cksum[j]); Printf("%02X", cksum[j]);
} }
Printf(" // %s\n", argv[i]); Printf(" // %s %s\n", wadname, argv[i]);
} }
} }
} }

View file

@ -66,15 +66,13 @@ FConfigFile::FConfigFile ()
// //
//==================================================================== //====================================================================
FConfigFile::FConfigFile (const char *pathname, FConfigFile::FConfigFile (const char *pathname)
void (*nosechandler)(const char *pathname, FConfigFile *config, void *userdata),
void *userdata)
{ {
Sections = CurrentSection = NULL; Sections = CurrentSection = NULL;
LastSectionPtr = &Sections; LastSectionPtr = &Sections;
CurrentEntry = NULL; CurrentEntry = NULL;
ChangePathName (pathname); ChangePathName (pathname);
LoadConfigFile (nosechandler, userdata); LoadConfigFile ();
OkayToWrite = true; OkayToWrite = true;
FileExisted = true; FileExisted = true;
} }
@ -118,8 +116,7 @@ FConfigFile::~FConfigFile ()
delete[] (char *)entry; delete[] (char *)entry;
entry = nextentry; entry = nextentry;
} }
section->~FConfigSection(); delete section;
delete[] (char *)section;
section = nextsection; section = nextsection;
} }
} }
@ -140,7 +137,7 @@ FConfigFile &FConfigFile::operator = (const FConfigFile &other)
while (fromsection != NULL) while (fromsection != NULL)
{ {
fromentry = fromsection->RootEntry; fromentry = fromsection->RootEntry;
tosection = NewConfigSection (fromsection->Name); tosection = NewConfigSection (fromsection->SectionName);
while (fromentry != NULL) while (fromentry != NULL)
{ {
NewConfigEntry (tosection, fromentry->Key, fromentry->Value); NewConfigEntry (tosection, fromentry->Key, fromentry->Value);
@ -311,7 +308,7 @@ const char *FConfigFile::GetCurrentSection () const
{ {
if (CurrentSection != NULL) if (CurrentSection != NULL)
{ {
return CurrentSection->Name; return CurrentSection->SectionName.GetChars();
} }
return NULL; return NULL;
} }
@ -508,13 +505,29 @@ FConfigFile::FConfigSection *FConfigFile::FindSection (const char *name) const
{ {
FConfigSection *section = Sections; FConfigSection *section = Sections;
while (section != NULL && stricmp (section->Name, name) != 0) while (section != NULL && section->SectionName.CompareNoCase(name) != 0)
{ {
section = section->Next; section = section->Next;
} }
return section; return section;
} }
//====================================================================
//
// FConfigFile :: RenameSection
//
//====================================================================
void FConfigFile::RenameSection (const char *oldname, const char *newname) const
{
FConfigSection *section = FindSection(oldname);
if (section != NULL)
{
section->SectionName = newname;
}
}
//==================================================================== //====================================================================
// //
// FConfigFile :: FindEntry // FConfigFile :: FindEntry
@ -542,19 +555,15 @@ FConfigFile::FConfigEntry *FConfigFile::FindEntry (
FConfigFile::FConfigSection *FConfigFile::NewConfigSection (const char *name) FConfigFile::FConfigSection *FConfigFile::NewConfigSection (const char *name)
{ {
FConfigSection *section; FConfigSection *section;
char *memblock;
section = FindSection (name); section = FindSection (name);
if (section == NULL) if (section == NULL)
{ {
size_t namelen = strlen (name); section = new FConfigSection;
memblock = new char[sizeof(*section)+namelen];
section = ::new(memblock) FConfigSection;
section->RootEntry = NULL; section->RootEntry = NULL;
section->LastEntryPtr = &section->RootEntry; section->LastEntryPtr = &section->RootEntry;
section->Next = NULL; section->Next = NULL;
memcpy (section->Name, name, namelen); section->SectionName = name;
section->Name[namelen] = 0;
*LastSectionPtr = section; *LastSectionPtr = section;
LastSectionPtr = &section->Next; LastSectionPtr = &section->Next;
} }
@ -591,7 +600,7 @@ FConfigFile::FConfigEntry *FConfigFile::NewConfigEntry (
// //
//==================================================================== //====================================================================
void FConfigFile::LoadConfigFile (void (*nosechandler)(const char *pathname, FConfigFile *config, void *userdata), void *userdata) void FConfigFile::LoadConfigFile ()
{ {
FILE *file = fopen (PathName, "r"); FILE *file = fopen (PathName, "r");
bool succ; bool succ;
@ -605,14 +614,6 @@ void FConfigFile::LoadConfigFile (void (*nosechandler)(const char *pathname, FCo
succ = ReadConfig (file); succ = ReadConfig (file);
fclose (file); fclose (file);
FileExisted = succ; FileExisted = succ;
if (!succ)
{ // First valid line did not define a section
if (nosechandler != NULL)
{
nosechandler (PathName, this, userdata);
}
}
} }
//==================================================================== //====================================================================
@ -787,7 +788,7 @@ bool FConfigFile::WriteConfigFile () const
{ {
fputs (section->Note.GetChars(), file); fputs (section->Note.GetChars(), file);
} }
fprintf (file, "[%s]\n", section->Name); fprintf (file, "[%s]\n", section->SectionName.GetChars());
while (entry != NULL) while (entry != NULL)
{ {
if (strpbrk(entry->Value, "\r\n") == NULL) if (strpbrk(entry->Value, "\r\n") == NULL)

View file

@ -41,8 +41,7 @@ class FConfigFile
{ {
public: public:
FConfigFile (); FConfigFile ();
FConfigFile (const char *pathname, FConfigFile (const char *pathname);
void (*nosechandler)(const char *pathname, FConfigFile *config, void *userdata)=0, void *userdata=NULL);
FConfigFile (const FConfigFile &other); FConfigFile (const FConfigFile &other);
virtual ~FConfigFile (); virtual ~FConfigFile ();
@ -70,7 +69,7 @@ public:
const char *GetPathName () const { return PathName.GetChars(); } const char *GetPathName () const { return PathName.GetChars(); }
void ChangePathName (const char *path); void ChangePathName (const char *path);
void LoadConfigFile (void (*nosechandler)(const char *pathname, FConfigFile *config, void *userdata), void *userdata); void LoadConfigFile ();
bool WriteConfigFile () const; bool WriteConfigFile () const;
protected: protected:
@ -79,6 +78,7 @@ protected:
virtual char *ReadLine (char *string, int n, void *file) const; virtual char *ReadLine (char *string, int n, void *file) const;
bool ReadConfig (void *file); bool ReadConfig (void *file);
static const char *GenerateEndTag(const char *value); static const char *GenerateEndTag(const char *value);
void RenameSection(const char *oldname, const char *newname) const;
bool OkayToWrite; bool OkayToWrite;
bool FileExisted; bool FileExisted;
@ -94,11 +94,12 @@ private:
}; };
struct FConfigSection struct FConfigSection
{ {
FString SectionName;
FConfigEntry *RootEntry; FConfigEntry *RootEntry;
FConfigEntry **LastEntryPtr; FConfigEntry **LastEntryPtr;
FConfigSection *Next; FConfigSection *Next;
FString Note; FString Note;
char Name[1]; // + length of name //char Name[1]; // + length of name
}; };
FConfigSection *Sections; FConfigSection *Sections;

View file

@ -47,6 +47,7 @@
#include "v_video.h" #include "v_video.h"
#include "gameconfigfile.h" #include "gameconfigfile.h"
#include "resourcefiles/resourcefile.h" #include "resourcefiles/resourcefile.h"
#include "version.h"
CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
@ -137,12 +138,6 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
sc.MustGetString(); sc.MustGetString();
iwad->Autoname = sc.String; iwad->Autoname = sc.String;
} }
else if (sc.Compare("Group"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->Group = sc.String;
}
else if (sc.Compare("Config")) else if (sc.Compare("Config"))
{ {
sc.MustGetStringName("="); sc.MustGetStringName("=");
@ -224,6 +219,11 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
sc.ScriptError("Unknown keyword '%s'", sc.String); sc.ScriptError("Unknown keyword '%s'", sc.String);
} }
} }
if (iwad->MapInfo.IsEmpty())
{
// We must at least load the minimum defaults to allow the engine to run.
iwad->MapInfo = "mapinfo/mindefaults.txt";
}
} }
else if (sc.Compare("NAMES")) else if (sc.Compare("NAMES"))
{ {
@ -252,7 +252,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
//========================================================================== //==========================================================================
// //
// Lool for IWAD definition lump // Look for IWAD definition lump
// //
//========================================================================== //==========================================================================
@ -301,11 +301,11 @@ int FIWadManager::ScanIWAD (const char *iwad)
FResourceLump *lump = iwadfile->GetLump(ii); FResourceLump *lump = iwadfile->GetLump(ii);
CheckLumpName(lump->Name); CheckLumpName(lump->Name);
if (lump->FullName != NULL) if (lump->FullName.IsNotEmpty())
{ {
if (strnicmp(lump->FullName, "maps/", 5) == 0) if (strnicmp(lump->FullName, "maps/", 5) == 0)
{ {
FString mapname(lump->FullName+5, strcspn(lump->FullName+5, ".")); FString mapname(&lump->FullName[5], strcspn(&lump->FullName[5], "."));
CheckLumpName(mapname); CheckLumpName(mapname);
} }
} }
@ -392,7 +392,6 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
bool iwadparmfound = false; bool iwadparmfound = false;
FString custwad; FString custwad;
ParseIWadInfos(zdoom_wad);
wads.Resize(mIWadNames.Size()); wads.Resize(mIWadNames.Size());
foundwads.Resize(mIWads.Size()); foundwads.Resize(mIWads.Size());
memset(&foundwads[0], 0, foundwads.Size() * sizeof(foundwads[0])); memset(&foundwads[0], 0, foundwads.Size() * sizeof(foundwads[0]));
@ -504,19 +503,19 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
if (numwads == 0) if (numwads == 0)
{ {
I_FatalError ("Cannot find a game IWAD (doom.wad, doom2.wad, heretic.wad, etc.).\n" I_FatalError ("Cannot find a game IWAD (doom.wad, doom2.wad, heretic.wad, etc.).\n"
"Did you install ZDoom properly? You can do either of the following:\n" "Did you install " GAMENAME " properly? You can do either of the following:\n"
"\n" "\n"
#if defined(_WIN32) #if defined(_WIN32)
"1. Place one or more of these wads in the same directory as ZDoom.\n" "1. Place one or more of these wads in the same directory as " GAMENAME ".\n"
"2. Edit your zdoom-username.ini and add the directories of your iwads\n" "2. Edit your " GAMENAMELOWERCASE "-username.ini and add the directories of your iwads\n"
"to the list beneath [IWADSearch.Directories]"); "to the list beneath [IWADSearch.Directories]");
#elif defined(__APPLE__) #elif defined(__APPLE__)
"1. Place one or more of these wads in ~/Library/Application Support/zdoom/\n" "1. Place one or more of these wads in ~/Library/Application Support/" GAMENAMELOWERCASE "/\n"
"2. Edit your ~/Library/Preferences/zdoom.ini and add the directories\n" "2. Edit your ~/Library/Preferences/" GAMENAMELOWERCASE ".ini and add the directories\n"
"of your iwads to the list beneath [IWADSearch.Directories]"); "of your iwads to the list beneath [IWADSearch.Directories]");
#else #else
"1. Place one or more of these wads in ~/.config/zdoom/.\n" "1. Place one or more of these wads in ~/.config/" GAMENAMELOWERCASE "/.\n"
"2. Edit your ~/.config/zdoom/zdoom.ini and add the directories of your\n" "2. Edit your ~/.config/" GAMENAMELOWERCASE "/" GAMENAMELOWERCASE ".ini and add the directories of your\n"
"iwads to the list beneath [IWADSearch.Directories]"); "iwads to the list beneath [IWADSearch.Directories]");
#endif #endif
} }

View file

@ -214,6 +214,7 @@ bool autostart;
FString StoredWarp; FString StoredWarp;
bool advancedemo; bool advancedemo;
FILE *debugfile; FILE *debugfile;
FILE *hashfile;
event_t events[MAXEVENTS]; event_t events[MAXEVENTS];
int eventhead; int eventhead;
int eventtail; int eventtail;
@ -1656,7 +1657,7 @@ static const char *BaseFileSearch (const char *file, const char *ext, bool lookf
return wad; return wad;
} }
if (GameConfig->SetSection ("FileSearch.Directories")) if (GameConfig != NULL && GameConfig->SetSection ("FileSearch.Directories"))
{ {
const char *key; const char *key;
const char *value; const char *value;
@ -1722,12 +1723,13 @@ bool ConsiderPatches (const char *arg)
// //
//========================================================================== //==========================================================================
void D_MultiExec (DArgs *list, bool usePullin) FExecList *D_MultiExec (DArgs *list, FExecList *exec)
{ {
for (int i = 0; i < list->NumArgs(); ++i) for (int i = 0; i < list->NumArgs(); ++i)
{ {
C_ExecFile (list->GetArg (i), usePullin); exec = C_ParseExecFile(list->GetArg(i), exec);
} }
return exec;
} }
static void GetCmdLineFiles(TArray<FString> &wadfiles) static void GetCmdLineFiles(TArray<FString> &wadfiles)
@ -1977,10 +1979,6 @@ static void D_DoomInit()
} }
FRandom::StaticClearRandom (); FRandom::StaticClearRandom ();
Printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (); // load before initing other systems
} }
//========================================================================== //==========================================================================
@ -1989,8 +1987,10 @@ static void D_DoomInit()
// //
//========================================================================== //==========================================================================
static void AddAutoloadFiles(const char *group, const char *autoname) static void AddAutoloadFiles(const char *autoname)
{ {
LumpFilterIWAD.Format("%s.", autoname); // The '.' is appened to simplify parsing the string
if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload")) if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload"))
{ {
FString file; FString file;
@ -2021,25 +2021,14 @@ static void AddAutoloadFiles(const char *group, const char *autoname)
// Add common (global) wads // Add common (global) wads
D_AddConfigWads (allwads, "Global.Autoload"); D_AddConfigWads (allwads, "Global.Autoload");
// Add game-specific wads long len;
file = gameinfo.ConfigName; int lastpos = -1;
file += ".Autoload";
D_AddConfigWads (allwads, file);
// Add group-specific wads while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0)
if (group != NULL)
{
file = group;
file += ".Autoload";
D_AddConfigWads(allwads, file);
}
// Add IWAD-specific wads
if (autoname != NULL)
{ {
file = autoname; file = LumpFilterIWAD.Left(len) + ".Autoload";
file += ".Autoload";
D_AddConfigWads(allwads, file); D_AddConfigWads(allwads, file);
lastpos = len;
} }
} }
} }
@ -2211,7 +2200,8 @@ void D_DoomMain (void)
DArgs *execFiles; DArgs *execFiles;
TArray<FString> pwads; TArray<FString> pwads;
FString *args; FString *args;
int argcount; int argcount;
FIWadManager *iwad_man;
// +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here. // +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here.
FString logfile = Args->TakeValue("+logfile"); FString logfile = Args->TakeValue("+logfile");
@ -2220,9 +2210,27 @@ void D_DoomMain (void)
execLogfile(logfile); execLogfile(logfile);
} }
if (Args->CheckParm("-hashfiles"))
{
const char *filename = "fileinfo.txt";
Printf("Hashing loaded content to: %s\n", filename);
hashfile = fopen(filename, "w");
if (hashfile)
{
fprintf(hashfile, "%s version %s (%s)\n", GAMENAME, GetVersionString(), GetGitHash());
#ifdef __VERSION__
fprintf(hashfile, "Compiler version: %s\n", __VERSION__);
#endif
fprintf(hashfile, "Command line:");
for (int i = 0; i < Args->NumArgs(); ++i)
{
fprintf(hashfile, " %s", Args->GetArg(i));
}
fprintf(hashfile, "\n");
}
}
D_DoomInit(); D_DoomInit();
PClass::StaticInit ();
atterm(FinalGC);
// [RH] Make sure zdoom.pk3 is always loaded, // [RH] Make sure zdoom.pk3 is always loaded,
// as it contains magic stuff we need. // as it contains magic stuff we need.
@ -2234,6 +2242,14 @@ void D_DoomMain (void)
} }
FString basewad = wad; FString basewad = wad;
iwad_man = new FIWadManager;
iwad_man->ParseIWadInfos(basewad);
Printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (iwad_man); // load before initing other systems
PClass::StaticInit ();
atterm(FinalGC);
// reinit from here // reinit from here
@ -2255,7 +2271,11 @@ void D_DoomMain (void)
// restart is initiated without a defined IWAD assume for now that it's not going to change. // restart is initiated without a defined IWAD assume for now that it's not going to change.
if (iwad.IsEmpty()) iwad = lastIWAD; if (iwad.IsEmpty()) iwad = lastIWAD;
FIWadManager *iwad_man = new FIWadManager; if (iwad_man == NULL)
{
iwad_man = new FIWadManager;
iwad_man->ParseIWadInfos(basewad);
}
const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad); const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad);
gameinfo.gametype = iwad_info->gametype; gameinfo.gametype = iwad_info->gametype;
gameinfo.flags = iwad_info->flags; gameinfo.flags = iwad_info->flags;
@ -2270,36 +2290,54 @@ void D_DoomMain (void)
FBaseCVar::DisableCallbacks(); FBaseCVar::DisableCallbacks();
GameConfig->DoGameSetup (gameinfo.ConfigName); GameConfig->DoGameSetup (gameinfo.ConfigName);
AddAutoloadFiles(iwad_info->Group, iwad_info->Autoname); AddAutoloadFiles(iwad_info->Autoname);
// Run automatically executed files // Process automatically executed files
FExecList *exec;
execFiles = new DArgs; execFiles = new DArgs;
GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName);
D_MultiExec (execFiles, true); exec = D_MultiExec(execFiles, NULL);
// Run .cfg files at the start of the command line. // Process .cfg files at the start of the command line.
execFiles = Args->GatherFiles ("-exec"); execFiles = Args->GatherFiles ("-exec");
D_MultiExec (execFiles, true); exec = D_MultiExec(execFiles, exec);
C_ExecCmdLineParams (); // [RH] do all +set commands on the command line // [RH] process all + commands on the command line
exec = C_ParseCmdLineParams(exec);
CopyFiles(allwads, pwads); CopyFiles(allwads, pwads);
if (exec != NULL)
{
exec->AddPullins(allwads);
}
// Since this function will never leave we must delete this array here manually. // Since this function will never leave we must delete this array here manually.
pwads.Clear(); pwads.Clear();
pwads.ShrinkToFit(); pwads.ShrinkToFit();
if (hashfile)
{
Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n");
}
Printf ("W_Init: Init WADfiles.\n"); Printf ("W_Init: Init WADfiles.\n");
Wads.InitMultipleFiles (allwads); Wads.InitMultipleFiles (allwads);
allwads.Clear(); allwads.Clear();
allwads.ShrinkToFit(); allwads.ShrinkToFit();
SetMapxxFlag(); SetMapxxFlag();
GameConfig->DoKeySetup(gameinfo.ConfigName);
// Now that wads are loaded, define mod-specific cvars. // Now that wads are loaded, define mod-specific cvars.
ParseCVarInfo(); ParseCVarInfo();
// Try setting previously unknown cvars again, as a CVARINFO may have made them known. // Actually exec command line commands and exec files.
C_ExecStoredSets(); if (exec != NULL)
{
exec->ExecCommands();
delete exec;
exec = NULL;
}
// [RH] Initialize localizable strings. // [RH] Initialize localizable strings.
GStrings.LoadStrings (false); GStrings.LoadStrings (false);
@ -2414,6 +2452,8 @@ void D_DoomMain (void)
// Create replacements for dehacked pickups // Create replacements for dehacked pickups
FinishDehPatch(); FinishDehPatch();
InitActorNumsFromMapinfo();
InitSpawnablesFromMapinfo();
FActorInfo::StaticSetActorNums (); FActorInfo::StaticSetActorNums ();
//Added by MC: //Added by MC:
@ -2465,6 +2505,7 @@ void D_DoomMain (void)
FBaseCVar::EnableNoSet (); FBaseCVar::EnableNoSet ();
delete iwad_man; // now we won't need this anymore delete iwad_man; // now we won't need this anymore
iwad_man = NULL;
// [RH] Run any saved commands from the command line or autoexec.cfg now. // [RH] Run any saved commands from the command line or autoexec.cfg now.
gamestate = GS_FULLCONSOLE; gamestate = GS_FULLCONSOLE;

View file

@ -75,7 +75,6 @@ struct FIWADInfo
{ {
FString Name; // Title banner text for this IWAD FString Name; // Title banner text for this IWAD
FString Autoname; // Name of autoload ini section for this IWAD FString Autoname; // Name of autoload ini section for this IWAD
FString Group; // Groupname for this IWAD
FString Configname; // Name of config section for this IWAD FString Configname; // Name of config section for this IWAD
FString Required; // Requires another IWAD FString Required; // Requires another IWAD
DWORD FgColor; // Foreground color for title banner DWORD FgColor; // Foreground color for title banner
@ -116,15 +115,13 @@ extern FStartupInfo DoomStartupInfo;
// //
//========================================================================== //==========================================================================
struct FIWadManager class FIWadManager
{ {
private:
TArray<FIWADInfo> mIWads; TArray<FIWADInfo> mIWads;
TArray<FString> mIWadNames; TArray<FString> mIWadNames;
TArray<int> mLumpsFound; TArray<int> mLumpsFound;
void ParseIWadInfo(const char *fn, const char *data, int datasize); void ParseIWadInfo(const char *fn, const char *data, int datasize);
void ParseIWadInfos(const char *fn);
void ClearChecks(); void ClearChecks();
void CheckLumpName(const char *name); void CheckLumpName(const char *name);
int GetIWadInfo(); int GetIWadInfo();
@ -132,7 +129,19 @@ private:
int CheckIWAD (const char *doomwaddir, WadStuff *wads); int CheckIWAD (const char *doomwaddir, WadStuff *wads);
int IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad); int IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad);
public: public:
void ParseIWadInfos(const char *fn);
const FIWADInfo *FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad); const FIWADInfo *FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
const FString *GetAutoname(unsigned int num) const
{
if (num < mIWads.Size()) return &mIWads[num].Autoname;
else return NULL;
}
int GetIWadFlags(unsigned int num) const
{
if (num < mIWads.Size()) return mIWads[num].flags;
else return false;
}
}; };

View file

@ -443,10 +443,15 @@ public:
FName LastDamageType; // [RH] For damage-specific pain and death sounds FName LastDamageType; // [RH] For damage-specific pain and death sounds
//Added by MC: TObjPtr<AActor> MUSINFOactor; // For MUSINFO purposes
TObjPtr<DBot> Bot; SBYTE MUSINFOtics;
bool settings_controller; // Player can control game settings. bool settings_controller; // Player can control game settings.
SBYTE crouching;
SBYTE crouchdir;
//Added by MC:
TObjPtr<DBot> Bot;
float BlendR; // [RH] Final blending values float BlendR; // [RH] Final blending values
float BlendG; float BlendG;
@ -458,8 +463,6 @@ public:
int MinPitch; // Viewpitch limits (negative is up, positive is down) int MinPitch; // Viewpitch limits (negative is up, positive is down)
int MaxPitch; int MaxPitch;
SBYTE crouching;
SBYTE crouchdir;
fixed_t crouchfactor; fixed_t crouchfactor;
fixed_t crouchoffset; fixed_t crouchoffset;
fixed_t crouchviewdelta; fixed_t crouchviewdelta;

View file

@ -328,6 +328,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
info->Class = type; info->Class = type;
info->GameFilter = GAME_Any; info->GameFilter = GAME_Any;
info->SpawnID = 0; info->SpawnID = 0;
info->ConversationID = 0;
info->DoomEdNum = -1; info->DoomEdNum = -1;
info->OwnedStates = NULL; info->OwnedStates = NULL;
info->NumOwnedStates = 0; info->NumOwnedStates = 0;
@ -423,6 +424,7 @@ void PClass::InitializeActorInfo ()
info->Class = this; info->Class = this;
info->GameFilter = GAME_Any; info->GameFilter = GAME_Any;
info->SpawnID = 0; info->SpawnID = 0;
info->ConversationID = 0;
info->DoomEdNum = -1; info->DoomEdNum = -1;
info->OwnedStates = NULL; info->OwnedStates = NULL;
info->NumOwnedStates = 0; info->NumOwnedStates = 0;

View file

@ -337,6 +337,7 @@ struct mapthinghexen_t
}; };
class FArchive; class FArchive;
struct FDoomEdEntry;
// Internal representation of a mapthing // Internal representation of a mapthing
struct FMapThing struct FMapThing
@ -346,9 +347,10 @@ struct FMapThing
fixed_t y; fixed_t y;
fixed_t z; fixed_t z;
short angle; short angle;
short type;
WORD SkillFilter; WORD SkillFilter;
WORD ClassFilter; WORD ClassFilter;
short EdNum;
FDoomEdEntry *info;
DWORD flags; DWORD flags;
int special; int special;
int args[5]; int args[5];
@ -363,8 +365,6 @@ struct FMapThing
short pitch; short pitch;
short roll; short roll;
DWORD RenderStyle; DWORD RenderStyle;
void Serialize (FArchive &);
}; };
@ -429,10 +429,10 @@ struct FPlayerStart
short angle, type; short angle, type;
FPlayerStart() { } FPlayerStart() { }
FPlayerStart(const FMapThing *mthing) FPlayerStart(const FMapThing *mthing, int pnum)
: x(mthing->x), y(mthing->y), z(mthing->z), : x(mthing->x), y(mthing->y), z(mthing->z),
angle(mthing->angle), angle(mthing->angle),
type(mthing->type) type(pnum)
{ } { }
}; };
// Player spawn spots for deathmatch. // Player spawn spots for deathmatch.

View file

@ -69,3 +69,4 @@ int SinglePlayerClass[MAXPLAYERS];
bool ToggleFullscreen; bool ToggleFullscreen;
int BorderTopRefresh; int BorderTopRefresh;
FString LumpFilterIWAD;

View file

@ -172,6 +172,7 @@ extern bool playeringame[/*MAXPLAYERS*/];
// File handling stuff. // File handling stuff.
extern FILE* debugfile; extern FILE* debugfile;
extern FILE* hashfile;
// if true, load all graphics at level load // if true, load all graphics at level load
extern bool precache; extern bool precache;
@ -249,4 +250,7 @@ EXTERN_CVAR (Int, compatflags);
EXTERN_CVAR (Int, compatflags2); EXTERN_CVAR (Int, compatflags2);
extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags; extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags;
// Filters from AddAutoloadFiles(). Used to filter files from archives.
extern FString LumpFilterIWAD;
#endif #endif

View file

@ -46,6 +46,9 @@
#include "zstring.h" #include "zstring.h"
#include "vectors.h" #include "vectors.h"
struct PClass;
typedef TMap<int, const PClass *> FClassMap;
// Since this file is included by everything, it seems an appropriate place // Since this file is included by everything, it seems an appropriate place
// to check the NOASM/USEASM macros. // to check the NOASM/USEASM macros.

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! // 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; if (players[i].mo != NULL) players[i].mo->ViewHeight = playerviewheight;
players[i].viewheight = playerviewheight;
players[i].Uncrouch(); players[i].Uncrouch();
} }
while (sc.GetString()) while (sc.GetString())

View file

@ -67,6 +67,7 @@
#include "v_font.h" #include "v_font.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "farchive.h" #include "farchive.h"
#include "p_setup.h"
static FRandom pr_script("FScript"); static FRandom pr_script("FScript");
@ -312,18 +313,24 @@ static int T_GetPlayerNum(const svalue_t &arg)
// sectors directly by passing a negative value // sectors directly by passing a negative value
// //
//========================================================================== //==========================================================================
int T_FindSectorFromTag(int tagnum,int startsector) class FSSectorTagIterator : public FSectorTagIterator
{ {
if (tagnum<=0) public:
FSSectorTagIterator(int tag)
: FSectorTagIterator(tag)
{ {
if (startsector<0) if (tag < 0)
{ {
if (tagnum==-32768) return 0; searchtag = INT_MIN;
if (-tagnum<numsectors) return -tagnum; start = tag == -32768? 0 : -tag < numsectors? -tag : -1;
} }
return -1;
} }
return P_FindSectorFromTag(tagnum,startsector); };
inline int T_FindFirstSectorFromTag(int tagnum)
{
FSSectorTagIterator it(tagnum);
return it.Next();
} }
@ -1158,7 +1165,7 @@ void FParser::SF_ObjSector(void)
} }
t_return.type = svt_int; t_return.type = svt_int;
t_return.value.i = mo ? mo->Sector->tag : 0; // nullptr check t_return.value.i = mo ? tagManager.GetFirstSectorTag(mo->Sector) : 0; // nullptr check
} }
//========================================================================== //==========================================================================
@ -1420,7 +1427,7 @@ void FParser::SF_PointToDist(void)
double y = floatvalue(t_argv[3]) - floatvalue(t_argv[1]); double y = floatvalue(t_argv[3]) - floatvalue(t_argv[1]);
t_return.type = svt_fixed; t_return.type = svt_fixed;
t_return.value.f = FLOAT2FIXED(sqrt(x*x+y*y)*65536.f); t_return.value.f = FLOAT2FIXED(sqrt(x*x+y*y));
} }
} }
@ -1536,7 +1543,8 @@ void FParser::SF_StartSectorSound(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
int i=-1; int i=-1;
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sector = &sectors[i]; sector = &sectors[i];
S_Sound(sector, CHAN_BODY, T_FindSound(stringvalue(t_argv[1])), 1.0f, ATTN_NORM); S_Sound(sector, CHAN_BODY, T_FindSound(stringvalue(t_argv[1])), 1.0f, ATTN_NORM);
@ -1595,7 +1603,8 @@ void FParser::SF_FloorHeight(void)
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
if (sectors[i].floordata) continue; // don't move floors that are active! if (sectors[i].floordata) continue; // don't move floors that are active!
@ -1612,7 +1621,7 @@ void FParser::SF_FloorHeight(void)
} }
else else
{ {
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ {
script_error("sector not found with tagnum %i\n", tagnum); script_error("sector not found with tagnum %i\n", tagnum);
@ -1671,7 +1680,8 @@ void FParser::SF_MoveFloor(void)
// move all sectors with tag // move all sectors with tag
while ((secnum = T_FindSectorFromTag(tagnum, secnum)) >= 0) FSSectorTagIterator itr(tagnum);
while ((secnum = itr.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
// Don't start a second thinker on the same floor // Don't start a second thinker on the same floor
@ -1733,7 +1743,8 @@ void FParser::SF_CeilingHeight(void)
dest = fixedvalue(t_argv[1]); dest = fixedvalue(t_argv[1]);
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
if (sectors[i].ceilingdata) continue; // don't move ceilings that are active! if (sectors[i].ceilingdata) continue; // don't move ceilings that are active!
@ -1750,7 +1761,7 @@ void FParser::SF_CeilingHeight(void)
} }
else else
{ {
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ {
script_error("sector not found with tagnum %i\n", tagnum); script_error("sector not found with tagnum %i\n", tagnum);
@ -1823,7 +1834,8 @@ void FParser::SF_MoveCeiling(void)
silent=t_argc>4 ? intvalue(t_argv[4]):1; silent=t_argc>4 ? intvalue(t_argv[4]):1;
// move all sectors with tag // move all sectors with tag
while ((secnum = T_FindSectorFromTag(tagnum, secnum)) >= 0) FSSectorTagIterator itr(tagnum);
while ((secnum = itr.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
@ -1851,7 +1863,7 @@ void FParser::SF_LightLevel(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
// argv is sector tag // argv is sector tag
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ {
@ -1865,7 +1877,8 @@ void FParser::SF_LightLevel(void)
int i = -1; int i = -1;
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].SetLightLevel(intvalue(t_argv[1])); sectors[i].SetLightLevel(intvalue(t_argv[1]));
} }
@ -1984,7 +1997,8 @@ void FParser::SF_FadeLight(void)
destlevel = intvalue(t_argv[1]); destlevel = intvalue(t_argv[1]);
speed = t_argc>2 ? intvalue(t_argv[2]) : 1; speed = t_argc>2 ? intvalue(t_argv[2]) : 1;
for (i = -1; (i = P_FindSectorFromTag(sectag,i)) >= 0;) FSectorTagIterator it(sectag);
while ((i = it.Next()) >= 0)
{ {
if (!sectors[i].lightingdata) new DLightLevel(&sectors[i],destlevel,speed); if (!sectors[i].lightingdata) new DLightLevel(&sectors[i],destlevel,speed);
} }
@ -2006,7 +2020,7 @@ void FParser::SF_FloorTexture(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
// argv is sector tag // argv is sector tag
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;} { script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -2019,7 +2033,8 @@ void FParser::SF_FloorTexture(void)
FTextureID picnum = TexMan.GetTexture(t_argv[1].string, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); FTextureID picnum = TexMan.GetTexture(t_argv[1].string, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].SetTexture(sector_t::floor, picnum); sectors[i].SetTexture(sector_t::floor, picnum);
} }
@ -2057,7 +2072,7 @@ void FParser::SF_SectorColormap(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
// argv is sector tag // argv is sector tag
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;} { script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -2068,7 +2083,8 @@ void FParser::SF_SectorColormap(void)
{ {
DWORD cm = R_ColormapNumForName(t_argv[1].value.s); DWORD cm = R_ColormapNumForName(t_argv[1].value.s);
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].midmap=cm; sectors[i].midmap=cm;
sectors[i].heightsec=&sectors[i]; sectors[i].heightsec=&sectors[i];
@ -2094,7 +2110,7 @@ void FParser::SF_CeilingTexture(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
// argv is sector tag // argv is sector tag
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;} { script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -2107,7 +2123,8 @@ void FParser::SF_CeilingTexture(void)
FTextureID picnum = TexMan.GetTexture(t_argv[1].string, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); FTextureID picnum = TexMan.GetTexture(t_argv[1].string, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].SetTexture(sector_t::ceiling, picnum); sectors[i].SetTexture(sector_t::ceiling, picnum);
} }
@ -2210,9 +2227,6 @@ void FParser::SF_RunCommand(void)
// //
//========================================================================== //==========================================================================
// any linedef type
extern void P_TranslateLineDef (line_t *ld, maplinedef_t *mld);
void FParser::SF_LineTrigger() void FParser::SF_LineTrigger()
{ {
if (CheckArgs(1)) if (CheckArgs(1))
@ -2281,9 +2295,11 @@ void FParser::SF_SetLineBlocking(void)
{ {
blocking=blocks[blocking]; blocking=blocks[blocking];
int tag=intvalue(t_argv[0]); int tag=intvalue(t_argv[0]);
for (int i = -1; (i = P_FindLineFromID(tag, i)) >= 0;) FLineIdIterator itr(tag);
int i;
while ((i = itr.Next()) >= 0)
{ {
lines[i].flags = (lines[i].flags & ~(ML_BLOCKING|ML_BLOCKEVERYTHING)) | blocking; lines[i].flags = (lines[i].flags & ~(ML_BLOCKING | ML_BLOCKEVERYTHING)) | blocking;
} }
} }
} }
@ -2302,7 +2318,9 @@ void FParser::SF_SetLineMonsterBlocking(void)
int blocking = intvalue(t_argv[1]) ? ML_BLOCKMONSTERS : 0; int blocking = intvalue(t_argv[1]) ? ML_BLOCKMONSTERS : 0;
int tag=intvalue(t_argv[0]); int tag=intvalue(t_argv[0]);
for (int i = -1; (i = P_FindLineFromID(tag, i)) >= 0;) FLineIdIterator itr(tag);
int i;
while ((i = itr.Next()) >= 0)
{ {
lines[i].flags = (lines[i].flags & ~ML_BLOCKMONSTERS) | blocking; lines[i].flags = (lines[i].flags & ~ML_BLOCKMONSTERS) | blocking;
} }
@ -2357,12 +2375,13 @@ void FParser::SF_SetLineTexture(void)
texture = stringvalue(t_argv[3]); texture = stringvalue(t_argv[3]);
texturenum = TexMan.GetTexture(texture, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); texturenum = TexMan.GetTexture(texture, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
for (i = -1; (i = P_FindLineFromID(tag, i)) >= 0;) FLineIdIterator itr(tag);
while ((i = itr.Next()) >= 0)
{ {
// bad sidedef, Hexen just SEGV'd here! // bad sidedef, Hexen just SEGV'd here!
if(lines[i].sidedef[side] != NULL) if (lines[i].sidedef[side] != NULL)
{ {
if (position >=0 && position <=2) if (position >= 0 && position <= 2)
{ {
lines[i].sidedef[side]->SetTexture(position, texturenum); lines[i].sidedef[side]->SetTexture(position, texturenum);
} }
@ -2376,7 +2395,8 @@ void FParser::SF_SetLineTexture(void)
int sections = intvalue(t_argv[3]); int sections = intvalue(t_argv[3]);
// set all sectors with tag // set all sectors with tag
for (i = -1; (i = P_FindLineFromID(tag, i)) >= 0;) FLineIdIterator itr(tag);
while ((i = itr.Next()) >= 0)
{ {
side_t *sided = lines[i].sidedef[side]; side_t *sided = lines[i].sidedef[side];
if(sided != NULL) if(sided != NULL)
@ -4201,7 +4221,7 @@ void FParser::SF_SetColor(void)
{ {
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ {
@ -4222,7 +4242,8 @@ void FParser::SF_SetColor(void)
else return; else return;
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].ColorMap = GetSpecialLights (color, sectors[i].ColorMap->Fade, 0); sectors[i].ColorMap = GetSpecialLights (color, sectors[i].ColorMap->Fade, 0);
} }
@ -4291,7 +4312,7 @@ void FParser::SF_KillInSector()
while ((mo=it.Next())) while ((mo=it.Next()))
{ {
if (mo->flags3&MF3_ISMONSTER && mo->Sector->tag==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);
} }
} }
} }
@ -4314,7 +4335,7 @@ void FParser::SF_SectorType(void)
tagnum = intvalue(t_argv[0]); tagnum = intvalue(t_argv[0]);
// argv is sector tag // argv is sector tag
secnum = T_FindSectorFromTag(tagnum, -1); secnum = T_FindFirstSectorFromTag(tagnum);
if(secnum < 0) if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;} { script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -4327,7 +4348,8 @@ void FParser::SF_SectorType(void)
int spec = intvalue(t_argv[1]); int spec = intvalue(t_argv[1]);
// set all sectors with tag // set all sectors with tag
while ((i = T_FindSectorFromTag(tagnum, i)) >= 0) FSSectorTagIterator itr(tagnum);
while ((i = itr.Next()) >= 0)
{ {
sectors[i].special = spec; sectors[i].special = spec;
} }
@ -4355,18 +4377,17 @@ void FParser::SF_SetLineTrigger()
id=intvalue(t_argv[0]); id=intvalue(t_argv[0]);
spec=intvalue(t_argv[1]); spec=intvalue(t_argv[1]);
if (t_argc>2) tag=intvalue(t_argv[2]); if (t_argc>2) tag=intvalue(t_argv[2]);
for (i = -1; (i = P_FindLineFromID (id, i)) >= 0; ) FLineIdIterator itr(id);
while ((i = itr.Next()) >= 0)
{ {
if (t_argc==2) tag=lines[i].id;
maplinedef_t mld; maplinedef_t mld;
mld.special=spec; mld.special = spec;
mld.tag=tag; mld.tag = tag;
mld.flags=0; mld.flags = 0;
int f = lines[i].flags; int f = lines[i].flags;
P_TranslateLineDef(&lines[i], &mld); P_TranslateLineDef(&lines[i], &mld);
lines[i].id=tag; lines[i].flags = (lines[i].flags & (ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)) |
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));
(f & ~(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_SPAC_MASK|ML_FIRSTSIDEONLY));
} }
} }
@ -4375,33 +4396,13 @@ void FParser::SF_SetLineTrigger()
//========================================================================== //==========================================================================
// //
// new for GZDoom: Changes a sector's tag //
// (I only need this because MAP02 in RTC-3057 has some issues with the GL
// renderer that I can't fix without the scripts. But loading a FS on top on
// ACS still works so I can hack around it with this.)
// //
//========================================================================== //==========================================================================
void FParser::SF_ChangeTag() void FParser::SF_ChangeTag()
{ {
if (CheckArgs(2)) // Development garbage!
{
for (int secnum = -1; (secnum = P_FindSectorFromTag (t_argv[0].value.i, secnum)) >= 0; )
{
sectors[secnum].tag=t_argv[1].value.i;
}
// Recreate the hash tables
int i;
for (i=numsectors; --i>=0; ) sectors[i].firsttag = -1;
for (i=numsectors; --i>=0; )
{
int j = (unsigned) sectors[i].tag % (unsigned) numsectors;
sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = i;
}
}
} }

View file

@ -452,9 +452,9 @@ bool DFraggleThinker::wait_finished(DRunningScript *script)
case wt_tagwait: case wt_tagwait:
{ {
int secnum = -1; int secnum;
FSectorTagIterator itr(script->wait_data);
while ((secnum = P_FindSectorFromTag(script->wait_data, secnum)) >= 0) while ((secnum = itr.Next()) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
if(sec->floordata || sec->ceilingdata || sec->lightingdata) if(sec->floordata || sec->ceilingdata || sec->lightingdata)

View file

@ -584,7 +584,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
int j; int j;
int damage; int damage;
angle_t an; angle_t an;
AActor *thingToHit;
AActor *linetarget; AActor *linetarget;
ACTION_PARAM_START(7); ACTION_PARAM_START(7);
@ -615,42 +614,42 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
// self->target is the originator (player) of the missile // self->target is the originator (player) of the missile
P_AimLineAttack(self->target, an, distance, &linetarget, vrange); P_AimLineAttack(self->target, an, distance, &linetarget, vrange);
if (!linetarget) if (linetarget != NULL)
continue;
AActor *spray = Spawn(spraytype, linetarget->x, linetarget->y,
linetarget->z + (linetarget->height >> 2), ALLOW_REPLACE);
if (spray)
{ {
if (spray->flags6 & MF6_MTHRUSPECIES && spray->GetSpecies() == linetarget->GetSpecies()) AActor *spray = Spawn(spraytype, linetarget->x, linetarget->y,
linetarget->z + (linetarget->height >> 2), ALLOW_REPLACE);
int dmgFlags = 0;
FName dmgType = NAME_BFGSplash;
if (spray != NULL)
{ {
spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. if (spray->flags6 & MF6_MTHRUSPECIES && spray->GetSpecies() == linetarget->GetSpecies())
continue; {
spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them.
continue;
}
if (spray->flags5 & MF5_PUFFGETSOWNER) spray->target = self->target;
if (spray->flags3 & MF3_FOILINVUL) dmgFlags |= DMG_FOILINVUL;
if (spray->flags7 & MF7_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA;
dmgType = spray->DamageType;
} }
if (spray->flags5 & MF5_PUFFGETSOWNER)
spray->target = self->target;
}
if (defdamage == 0) if (defdamage == 0)
{ {
damage = 0; damage = 0;
for (j = 0; j < damagecnt; ++j) for (j = 0; j < damagecnt; ++j)
damage += (pr_bfgspray() & 7) + 1; damage += (pr_bfgspray() & 7) + 1;
} }
else else
{ {
// if this is used, damagecnt will be ignored // if this is used, damagecnt will be ignored
damage = defdamage; damage = defdamage;
} }
int dmgFlagPass = 0; int newdam = P_DamageMobj(linetarget, self->target, self->target, damage, dmgType, dmgFlags);
dmgFlagPass += (spray != NULL && (spray->flags3 & MF3_FOILINVUL)) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul wasn't working. P_TraceBleed(newdam > 0 ? newdam : damage, linetarget, self->target);
dmgFlagPass += (spray != NULL && (spray->flags7 & MF7_FOILBUDDHA)) ? DMG_FOILBUDDHA : 0; }
thingToHit = linetarget;
int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash),
dmgFlagPass);
P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target);
} }
} }

277
src/g_doomedmap.cpp Normal file
View file

@ -0,0 +1,277 @@
/*
** g_doomedmap.cpp
**
**---------------------------------------------------------------------------
** Copyright 1998-2015 Randy Heit
** 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 "info.h"
#include "p_lnspec.h"
#include "m_fixed.h"
#include "c_dispatch.h"
#include "templates.h"
#include "cmdlib.h"
#include "g_level.h"
#include "v_text.h"
#include "i_system.h"
const char *SpecialMapthingNames[] = {
"$Player1Start",
"$Player2Start",
"$Player3Start",
"$Player4Start",
"$Player5Start",
"$Player6Start",
"$Player7Start",
"$Player8Start",
"$DeathmatchStart",
"$SSeqOverride",
"$PolyAnchor",
"$PolySpawn",
"$PolySpawnCrush",
"$PolySpawnHurt",
"$SlopeFloorPointLine",
"$SlopeCeilingPointLine",
"$SetFloorSlope",
"$SetCeilingSlope",
"$VavoomFloor",
"$VavoomCeiling",
"$CopyFloorPlane",
"$CopyCeilingPlane",
"$VertexFloorZ",
"$VertexCeilingZ",
};
//==========================================================================
//
// Stuff that's only valid during definition time
//
//==========================================================================
struct MapinfoEdMapItem
{
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
short special;
bool argsdefined;
int args[5];
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
FString filename;
int linenum;
};
typedef TMap<int, MapinfoEdMapItem> IdMap;
static IdMap DoomEdFromMapinfo;
//==========================================================================
//
//
//==========================================================================
FDoomEdMap DoomEdMap;
static int STACK_ARGS sortnums (const void *a, const void *b)
{
return (*(const FDoomEdMap::Pair**)a)->Key - (*(const FDoomEdMap::Pair**)b)->Key;
}
CCMD (dumpmapthings)
{
TArray<FDoomEdMap::Pair*> infos(DoomEdMap.CountUsed());
FDoomEdMap::Iterator it(DoomEdMap);
FDoomEdMap::Pair *pair;
while (it.NextPair(pair))
{
infos.Push(pair);
}
if (infos.Size () == 0)
{
Printf ("No map things registered\n");
}
else
{
qsort (&infos[0], infos.Size (), sizeof(FDoomEdMap::Pair*), sortnums);
for (unsigned i = 0; i < infos.Size (); ++i)
{
if (infos[i]->Value.Type != NULL)
{
Printf("%6d %s\n", infos[i]->Key, infos[i]->Value.Type->TypeName.GetChars());
}
else if (infos[i]->Value.Special > 0)
{
Printf("%6d %s\n", infos[i]->Key, SpecialMapthingNames[infos[i]->Value.Special - 1]);
}
else
{
Printf("%6d none", infos[i]->Key);
}
}
}
}
void FMapInfoParser::ParseDoomEdNums()
{
TMap<int, bool> defined;
int error = 0;
MapinfoEdMapItem editem;
editem.filename = sc.ScriptName;
ParseOpenBrace();
while (true)
{
if (sc.CheckString("}")) return;
else if (sc.CheckNumber())
{
int ednum = sc.Number;
sc.MustGetStringName("=");
sc.MustGetString();
bool *def = defined.CheckKey(ednum);
if (def != NULL)
{
sc.ScriptMessage("Editor Number %d defined more than once", ednum);
error++;
}
defined[ednum] = true;
if (sc.String[0] == '$')
{
// todo: add special stuff like playerstarts and sound sequence overrides here, too.
editem.classname = NAME_None;
editem.special = sc.MustMatchString(SpecialMapthingNames) + 1; // todo: assign proper constants
}
else
{
editem.classname = sc.String;
editem.special = -1;
}
memset(editem.args, 0, sizeof(editem.args));
editem.argsdefined = false;
int minargs = 0;
int maxargs = 5;
FString specialname;
if (sc.CheckString(","))
{
editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing.
if (editem.special < 0) editem.special = 0;
if (!sc.CheckNumber())
{
sc.MustGetString();
specialname = sc.String; // save for later error reporting.
editem.special = P_FindLineSpecial(sc.String, &minargs, &maxargs);
if (editem.special == 0 || minargs == -1)
{
sc.ScriptMessage("Invalid special %s for Editor Number %d", sc.String, ednum);
error++;
minargs = 0;
maxargs = 5;
}
if (!sc.CheckString(","))
{
// special case: Special without arguments
if (minargs != 0)
{
sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = 0", specialname.GetChars(), minargs, maxargs);
error++;
}
DoomEdFromMapinfo.Insert(ednum, editem);
continue;
}
sc.MustGetNumber();
}
int i = 0;
while (i < 5)
{
editem.args[i] = sc.Number;
i++;
if (!sc.CheckString(",")) break;
sc.MustGetNumber();
}
if (specialname.IsNotEmpty() && (i < minargs || i > maxargs))
{
sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = %d", specialname.GetChars(), minargs, maxargs, i);
error++;
}
}
DoomEdFromMapinfo.Insert(ednum, editem);
}
else
{
sc.ScriptError("Number expected");
}
}
if (error > 0)
{
sc.ScriptError("%d errors encountered in DoomEdNum definition");
}
}
void InitActorNumsFromMapinfo()
{
DoomEdMap.Clear();
IdMap::Iterator it(DoomEdFromMapinfo);
IdMap::Pair *pair;
int error = 0;
while (it.NextPair(pair))
{
const PClass *cls = NULL;
if (pair->Value.classname != NAME_None)
{
cls = PClass::FindClass(pair->Value.classname);
if (cls == NULL)
{
Printf(TEXTCOLOR_RED "Script error, \"%s\" line %d:\nUnknown actor class %s\n",
pair->Value.filename.GetChars(), pair->Value.linenum, pair->Value.classname.GetChars());
error++;
}
}
FDoomEdEntry ent;
ent.Type = cls;
ent.Special = pair->Value.special;
ent.ArgsDefined = pair->Value.argsdefined;
memcpy(ent.Args, pair->Value.args, sizeof(ent.Args));
DoomEdMap.Insert(pair->Key, ent);
}
if (error > 0)
{
I_Error("%d unknown actor classes found", error);
}
DoomEdFromMapinfo.Clear(); // we do not need this any longer
}

View file

@ -2516,7 +2516,7 @@ bool G_ProcessIFFDemo (FString &mapname)
id = ReadLong (&demo_p); id = ReadLong (&demo_p);
if (id != ZDEM_ID) if (id != ZDEM_ID)
{ {
Printf ("Not a ZDoom demo file!\n"); Printf ("Not a " GAMENAME " demo file!\n");
return true; return true;
} }
@ -2541,12 +2541,12 @@ bool G_ProcessIFFDemo (FString &mapname)
demover = ReadWord (&demo_p); // ZDoom version demo was created with demover = ReadWord (&demo_p); // ZDoom version demo was created with
if (demover < MINDEMOVERSION) if (demover < MINDEMOVERSION)
{ {
Printf ("Demo requires an older version of ZDoom!\n"); Printf ("Demo requires an older version of " GAMENAME "!\n");
//return true; //return true;
} }
if (ReadWord (&demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version if (ReadWord (&demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version
{ {
Printf ("Demo requires a newer version of ZDoom!\n"); Printf ("Demo requires a newer version of " GAMENAME "!\n");
return true; return true;
} }
if (demover >= 0x21a) if (demover >= 0x21a)
@ -2673,7 +2673,7 @@ void G_DoPlayDemo (void)
if (ReadLong (&demo_p) != FORM_ID) if (ReadLong (&demo_p) != FORM_ID)
{ {
const char *eek = "Cannot play non-ZDoom demos.\n"; const char *eek = "Cannot play non-" GAMENAME " demos.\n";
C_ForgetCVars(); C_ForgetCVars();
M_Free(demobuffer); M_Free(demobuffer);

106
src/g_hexen/a_flies.cpp Normal file
View file

@ -0,0 +1,106 @@
static FRandom pr_fly("GetOffMeFly");
//===========================================================================
//
// FindCorpse
//
// Finds a corpse to buzz around. We can't use a blockmap check because
// corpses generally aren't linked into the blockmap.
//
//===========================================================================
static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit)
{
AActor *fallback = NULL;
sec->validcount = validcount;
// Search the current sector
for (AActor *check = sec->thinglist; check != NULL; check = check->snext)
{
if (check == fly)
continue;
if (!(check->flags & MF_CORPSE))
continue;
if (!P_CheckSight(fly, check))
continue;
fallback = check;
if (pr_fly(2)) // 50% chance to try to pick a different corpse
continue;
return check;
}
if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2)))
{
return fallback;
}
// Try neighboring sectors
for (int i = 0; i < sec->linecount; ++i)
{
line_t *line = sec->lines[i];
sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector;
if (sec2 != NULL && sec2->validcount != validcount)
{
AActor *neighbor = FindCorpse(fly, sec2, recurselimit);
if (neighbor != NULL)
{
return neighbor;
}
}
}
return fallback;
}
DEFINE_ACTION_FUNCTION(AActor, A_FlySearch)
{
// The version from the retail beta is not so great for general use:
// 1. Pick one of the first fifty thinkers at random.
// 2. Starting from that thinker, find one that is an actor, not itself,
// and within sight. Give up after 100 sequential thinkers.
// It's effectively useless if there are more than 150 thinkers on a map.
//
// So search the sectors instead. We can't potentially find something all
// the way on the other side of the map and we can't find invisible corpses,
// but at least we aren't crippled on maps with lots of stuff going on.
validcount++;
AActor *other = FindCorpse(self, self->Sector, 5);
if (other != NULL)
{
self->target = other;
self->SetState(self->FindState("Buzz"));
}
}
DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz)
{
AActor *targ = self->target;
if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5)
{
self->SetIdle();
return;
}
angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y);
self->angle = ang;
self->args[0]++;
ang >>= ANGLETOFINESHIFT;
if (!P_TryMove(self, self->x + 6 * finecosine[ang], self->y + 6 * finesine[ang], true))
{
self->SetIdle(true);
return;
}
if (self->args[0] & 2)
{
self->velx += (pr_fly() - 128) << BOBTOFINESHIFT;
self->vely += (pr_fly() - 128) << BOBTOFINESHIFT;
}
int zrand = pr_fly();
if (targ->z + 5*FRACUNIT < self->z && zrand > 150)
{
zrand = -zrand;
}
self->velz = zrand << BOBTOFINESHIFT;
if (pr_fly() < 40)
{
S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC);
}
}

View file

@ -38,6 +38,7 @@
#include "a_fighterquietus.cpp" #include "a_fighterquietus.cpp"
#include "a_firedemon.cpp" #include "a_firedemon.cpp"
#include "a_flechette.cpp" #include "a_flechette.cpp"
#include "a_flies.cpp"
#include "a_fog.cpp" #include "a_fog.cpp"
#include "a_healingradius.cpp" #include "a_healingradius.cpp"
#include "a_heresiarch.cpp" #include "a_heresiarch.cpp"

View file

@ -1229,6 +1229,7 @@ void G_FinishTravel ()
pawn->lastenemy = NULL; pawn->lastenemy = NULL;
pawn->player->mo = pawn; pawn->player->mo = pawn;
pawn->player->camera = pawn; pawn->player->camera = pawn;
pawn->player->viewheight = pawn->ViewHeight;
pawn->flags2 &= ~MF2_BLASTED; pawn->flags2 &= ~MF2_BLASTED;
DObject::StaticPointerSubstitution (oldpawn, pawn); DObject::StaticPointerSubstitution (oldpawn, pawn);
oldpawn->Destroy(); oldpawn->Destroy();
@ -1457,7 +1458,9 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
if (SaveVersion >= 3313) if (SaveVersion >= 3313)
{ {
arc << level.nextmusic; // This is a player property now
int nextmusic;
arc << nextmusic;
} }
// Hub transitions must keep the current total time // Hub transitions must keep the current total time

View file

@ -104,6 +104,9 @@ struct FMapInfoParser
void ParseIntermissionAction(FIntermissionDescriptor *Desc); void ParseIntermissionAction(FIntermissionDescriptor *Desc);
void ParseIntermission(); void ParseIntermission();
void ParseDoomEdNums();
void ParseSpawnNums();
void ParseConversationIDs();
void ParseAMColors(bool); void ParseAMColors(bool);
FName CheckEndSequence(); FName CheckEndSequence();
FName ParseEndGame(); FName ParseEndGame();
@ -336,6 +339,7 @@ struct level_info_t
TArray<FSpecialAction> specialactions; TArray<FSpecialAction> specialactions;
TArray<FSoundID> PrecacheSounds; TArray<FSoundID> PrecacheSounds;
TArray<FTextureID> PrecacheTextures;
level_info_t() level_info_t()
{ {
@ -412,7 +416,6 @@ struct FLevelLocals
int musicorder; int musicorder;
int cdtrack; int cdtrack;
unsigned int cdid; unsigned int cdid;
int nextmusic; // For MUSINFO purposes
FTextureID skytexture1; FTextureID skytexture1;
FTextureID skytexture2; FTextureID skytexture2;

View file

@ -1065,6 +1065,25 @@ DEFINE_MAP_OPTION(PrecacheSounds, true)
} while (parse.sc.CheckString(",")); } while (parse.sc.CheckString(","));
} }
DEFINE_MAP_OPTION(PrecacheTextures, true)
{
parse.ParseAssign();
do
{
parse.sc.MustGetString();
FTextureID tex = TexMan.CheckForTexture(parse.sc.String, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_ReturnFirst);
if (!tex.isValid())
{
parse.sc.ScriptMessage("Unknown texture \"%s\"", parse.sc.String);
}
else
{
info->PrecacheTextures.Push(tex);
}
} while (parse.sc.CheckString(","));
}
DEFINE_MAP_OPTION(redirect, true) DEFINE_MAP_OPTION(redirect, true)
{ {
parse.ParseAssign(); parse.ParseAssign();
@ -1857,6 +1876,42 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
sc.ScriptError("intermission definitions not supported with old MAPINFO syntax"); sc.ScriptError("intermission definitions not supported with old MAPINFO syntax");
} }
} }
else if (sc.Compare("doomednums"))
{
if (format_type != FMT_Old)
{
format_type = FMT_New;
ParseDoomEdNums();
}
else
{
sc.ScriptError("doomednums definitions not supported with old MAPINFO syntax");
}
}
else if (sc.Compare("spawnnums"))
{
if (format_type != FMT_Old)
{
format_type = FMT_New;
ParseSpawnNums();
}
else
{
sc.ScriptError("spawnnums definitions not supported with old MAPINFO syntax");
}
}
else if (sc.Compare("conversationids"))
{
if (format_type != FMT_Old)
{
format_type = FMT_New;
ParseConversationIDs();
}
else
{
sc.ScriptError("conversationids definitions not supported with old MAPINFO syntax");
}
}
else if (sc.Compare("automap") || sc.Compare("automap_overlay")) else if (sc.Compare("automap") || sc.Compare("automap_overlay"))
{ {
if (format_type != FMT_Old) if (format_type != FMT_Old)

View file

@ -1757,6 +1757,7 @@ IMPLEMENT_CLASS(APowerRegeneration)
void APowerRegeneration::DoEffect() void APowerRegeneration::DoEffect()
{ {
Super::DoEffect();
if (Owner != NULL && Owner->health > 0 && (level.time & 31) == 0) if (Owner != NULL && Owner->health > 0 && (level.time & 31) == 0)
{ {
if (P_GiveBody(Owner, Strength/FRACUNIT)) if (P_GiveBody(Owner, Strength/FRACUNIT))

View file

@ -593,7 +593,7 @@ bool AInventory::HandlePickup (AInventory *item)
{ {
if (item->GetClass() == GetClass()) 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) if (Amount > 0 && Amount + item->Amount < 0)
{ {

View file

@ -119,7 +119,9 @@ void ASkyCamCompat::BeginPlay ()
// Finally, skyboxify all tagged sectors // Finally, skyboxify all tagged sectors
// This involves changing their texture to the sky flat, because while // This involves changing their texture to the sky flat, because while
// EE works with any texture for its skybox portals, ZDoom doesn't. // EE works with any texture for its skybox portals, ZDoom doesn't.
for (int secnum =-1; (secnum = P_FindSectorFromTag (skybox_id, secnum)) != -1; ) FSectorTagIterator it(skybox_id);
int secnum;
while ((secnum = it.Next()) >= 0)
{ {
// plane: 0=floor, 1=ceiling, 2=both // plane: 0=floor, 1=ceiling, 2=both
if (refline->args[2] == 1 || refline->args[2] == 2) if (refline->args[2] == 1 || refline->args[2] == 2)

View file

@ -1502,7 +1502,7 @@ void DBaseStatusBar::DrawTopStuff (EHudState state)
{ {
screen->DrawText (SmallFont, CR_TAN, 0, ST_Y - 40 * CleanYfac, screen->DrawText (SmallFont, CR_TAN, 0, ST_Y - 40 * CleanYfac,
"Demo was recorded with a different version\n" "Demo was recorded with a different version\n"
"of ZDoom. Expect it to go out of sync.", "of " GAMENAME ". Expect it to go out of sync.",
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
} }

View file

@ -636,7 +636,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
} }
else if ((sec->special & 0xFF) == Scroll_StrifeCurrent) else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
{ {
int anglespeed = sec->tag - 100; int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4); fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
angle_t finean = (anglespeed / 10) << (32-3); angle_t finean = (anglespeed / 10) << (32-3);
finean >>= ANGLETOFINESHIFT; finean >>= ANGLETOFINESHIFT;

View file

@ -61,6 +61,7 @@ extern HWND Window;
#include "doomstat.h" #include "doomstat.h"
#include "i_system.h" #include "i_system.h"
#include "gi.h" #include "gi.h"
#include "d_main.h"
EXTERN_CVAR (Bool, con_centernotify) EXTERN_CVAR (Bool, con_centernotify)
EXTERN_CVAR (Int, msg0color) EXTERN_CVAR (Int, msg0color)
@ -75,7 +76,7 @@ EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp) EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, wi_percents) EXTERN_CVAR (Bool, wi_percents)
FGameConfigFile::FGameConfigFile () FGameConfigFile::FGameConfigFile (FIWadManager *iwad_man)
{ {
#ifdef __APPLE__ #ifdef __APPLE__
FString user_docs, user_app_support, local_app_support; FString user_docs, user_app_support, local_app_support;
@ -83,16 +84,10 @@ FGameConfigFile::FGameConfigFile ()
FString pathname; FString pathname;
OkayToWrite = false; // Do not allow saving of the config before DoGameSetup() OkayToWrite = false; // Do not allow saving of the config before DoGameSetup()
bMigrating = false;
bModSetup = false; bModSetup = false;
pathname = GetConfigPath (true); pathname = GetConfigPath (true);
ChangePathName (pathname); ChangePathName (pathname);
LoadConfigFile (MigrateStub, NULL); LoadConfigFile ();
if (!HaveSections ())
{ // Config file not found; try the old one
MigrateOldConfig ();
}
// If zdoom.ini was read from the program directory, switch // If zdoom.ini was read from the program directory, switch
// to the user directory now. If it was read from the user // to the user directory now. If it was read from the user
@ -169,28 +164,49 @@ FGameConfigFile::FGameConfigFile ()
// Create auto-load sections, so users know what's available. // Create auto-load sections, so users know what's available.
// Note that this totem pole is the reverse of the order that // Note that this totem pole is the reverse of the order that
// they will appear in the file. // they will appear in the file.
CreateSectionAtStart("Harmony.Autoload");
CreateSectionAtStart("UrbanBrawl.Autoload"); double last = 0;
CreateSectionAtStart("Chex3.Autoload"); if (SetSection ("LastRun"))
CreateSectionAtStart("Chex1.Autoload"); {
CreateSectionAtStart("Chex.Autoload"); const char *lastver = GetValueForKey ("Version");
CreateSectionAtStart("Strife.Autoload"); if (lastver != NULL) last = atof(lastver);
CreateSectionAtStart("HexenDK.Autoload"); }
CreateSectionAtStart("Hexen.Autoload");
CreateSectionAtStart("HereticSR.Autoload"); if (last < 211)
CreateSectionAtStart("Heretic.Autoload"); {
CreateSectionAtStart("FreeDM.Autoload"); RenameSection("Chex3.Autoload", "chex.chex3.Autoload");
CreateSectionAtStart("Freedoom2.Autoload"); RenameSection("Chex1.Autoload", "chex.chex1.Autoload");
CreateSectionAtStart("Freedoom1.Autoload"); RenameSection("HexenDK.Autoload", "hexen.deathkings.Autoload");
CreateSectionAtStart("Freedoom.Autoload"); RenameSection("HereticSR.Autoload", "heretic.shadow.Autoload");
CreateSectionAtStart("Plutonia.Autoload"); RenameSection("FreeDM.Autoload", "doom.freedoom.freedm.Autoload");
CreateSectionAtStart("TNT.Autoload"); RenameSection("Freedoom2.Autoload", "doom.freedoom.phase2.Autoload");
CreateSectionAtStart("Doom2BFG.Autoload"); RenameSection("Freedoom1.Autoload", "doom.freedoom.phase1.Autoload");
CreateSectionAtStart("Doom2.Autoload"); RenameSection("Freedoom.Autoload", "doom.freedoom.Autoload");
CreateSectionAtStart("DoomBFG.Autoload"); RenameSection("DoomBFG.Autoload", "doom.doom1.bfg.Autoload");
CreateSectionAtStart("DoomU.Autoload"); RenameSection("DoomU.Autoload", "doom.doom1.ultimate.Autoload");
CreateSectionAtStart("Doom1.Autoload"); RenameSection("Doom1.Autoload", "doom.doom1.registered.Autoload");
CreateSectionAtStart("Doom.Autoload"); RenameSection("TNT.Autoload", "doom.doom2.tnt.Autoload");
RenameSection("Plutonia.Autoload", "doom.doom2.plutonia.Autoload");
RenameSection("Doom2BFG.Autoload", "doom.doom2.bfg.Autoload");
RenameSection("Doom2.Autoload", "doom.doom2.commercial.Autoload");
}
const FString *pAuto;
for (int num = 0; (pAuto = iwad_man->GetAutoname(num)) != NULL; num++)
{
if (!(iwad_man->GetIWadFlags(num) & GI_SHAREWARE)) // we do not want autoload sections for shareware IWADs (which may have an autoname for resource filtering)
{
FString workname = *pAuto;
while (workname.IsNotEmpty())
{
FString section = workname + ".Autoload";
CreateSectionAtStart(section.GetChars());
long dotpos = workname.LastIndexOf('.');
if (dotpos < 0) break;
workname.Truncate(dotpos);
}
}
}
CreateSectionAtStart("Global.Autoload"); CreateSectionAtStart("Global.Autoload");
// The same goes for auto-exec files. // The same goes for auto-exec files.
@ -223,9 +239,10 @@ FGameConfigFile::FGameConfigFile ()
"# Wad files to automatically load depending on the game and IWAD you are\n" "# Wad files to automatically load depending on the game and IWAD you are\n"
"# playing. You may have have files that are loaded for all similar IWADs\n" "# playing. You may have have files that are loaded for all similar IWADs\n"
"# (the game) and files that are only loaded for particular IWADs. For example,\n" "# (the game) and files that are only loaded for particular IWADs. For example,\n"
"# any files listed under Doom.Autoload will be loaded for any version of Doom,\n" "# any files listed under 'doom.Autoload' will be loaded for any version of Doom,\n"
"# but files listed under Doom2.Autoload will only load when you are\n" "# but files listed under 'doom.doom2.Autoload' will only load when you are\n"
"# playing Doom 2.\n\n"); "# playing a Doom 2 based game (doom2.wad, tnt.wad or plutonia.wad), and files listed under\n"
"# 'doom.doom2.commercial.Autoload' only when playing doom2.wad.\n\n");
} }
FGameConfigFile::~FGameConfigFile () FGameConfigFile::~FGameConfigFile ()
@ -237,18 +254,6 @@ void FGameConfigFile::WriteCommentHeader (FILE *file) const
fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime()); fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
} }
void FGameConfigFile::MigrateStub (const char *pathname, FConfigFile *config, void *userdata)
{
static_cast<FGameConfigFile *>(config)->bMigrating = true;
}
void FGameConfigFile::MigrateOldConfig ()
{
// Set default key bindings. These will be overridden
// by the bindings in the config file if it exists.
C_SetDefaultBindings ();
}
void FGameConfigFile::DoGlobalSetup () void FGameConfigFile::DoGlobalSetup ()
{ {
if (SetSection ("GlobalSettings.Unknown")) if (SetSection ("GlobalSettings.Unknown"))
@ -361,10 +366,6 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
const char *key; const char *key;
const char *value; const char *value;
if (bMigrating)
{
MigrateOldConfig ();
}
sublen = countof(section) - 1 - mysnprintf (section, countof(section), "%s.", gamename); sublen = countof(section) - 1 - mysnprintf (section, countof(section), "%s.", gamename);
subsection = section + countof(section) - sublen - 1; subsection = section + countof(section) - sublen - 1;
section[countof(section) - 1] = '\0'; section[countof(section) - 1] = '\0';
@ -400,41 +401,6 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
ReadCVars (0); ReadCVars (0);
} }
if (!bMigrating)
{
C_SetDefaultBindings ();
}
strncpy (subsection, "Bindings", sublen);
if (SetSection (section))
{
Bindings.UnbindAll();
while (NextInSection (key, value))
{
Bindings.DoBind (key, value);
}
}
strncpy (subsection, "DoubleBindings", sublen);
if (SetSection (section))
{
DoubleBindings.UnbindAll();
while (NextInSection (key, value))
{
DoubleBindings.DoBind (key, value);
}
}
strncpy (subsection, "AutomapBindings", sublen);
if (SetSection (section))
{
AutomapBindings.UnbindAll();
while (NextInSection (key, value))
{
AutomapBindings.DoBind (key, value);
}
}
strncpy (subsection, "ConsoleAliases", sublen); strncpy (subsection, "ConsoleAliases", sublen);
if (SetSection (section)) if (SetSection (section))
{ {
@ -455,6 +421,39 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
OkayToWrite = true; OkayToWrite = true;
} }
// Moved from DoGameSetup so that it can happen after wads are loaded
void FGameConfigFile::DoKeySetup(const char *gamename)
{
static const struct { const char *label; FKeyBindings *bindings; } binders[] =
{
{ "Bindings", &Bindings },
{ "DoubleBindings", &DoubleBindings },
{ "AutomapBindings", &AutomapBindings },
{ NULL, NULL }
};
const char *key, *value;
sublen = countof(section) - 1 - mysnprintf(section, countof(section), "%s.", gamename);
subsection = section + countof(section) - sublen - 1;
section[countof(section) - 1] = '\0';
C_SetDefaultBindings ();
for (int i = 0; binders[i].label != NULL; ++i)
{
strncpy(subsection, binders[i].label, sublen);
if (SetSection(section))
{
FKeyBindings *bindings = binders[i].bindings;
bindings->UnbindAll();
while (NextInSection(key, value))
{
bindings->DoBind(key, value);
}
}
}
}
// Like DoGameSetup(), but for mod-specific cvars. // Like DoGameSetup(), but for mod-specific cvars.
// Called after CVARINFO has been parsed. // Called after CVARINFO has been parsed.
void FGameConfigFile::DoModSetup(const char *gamename) void FGameConfigFile::DoModSetup(const char *gamename)
@ -628,41 +627,20 @@ void FGameConfigFile::AddAutoexec (DArgs *list, const char *game)
mysnprintf (section, countof(section), "%s.AutoExec", game); mysnprintf (section, countof(section), "%s.AutoExec", game);
if (bMigrating) // If <game>.AutoExec section does not exist, create it
// with a default autoexec.cfg file present.
CreateStandardAutoExec(section, false);
// Run any files listed in the <game>.AutoExec section
if (!SectionIsEmpty())
{ {
FBaseCVar *autoexec = FindCVar ("autoexec", NULL); while (NextInSection (key, value))
if (autoexec != NULL)
{ {
UCVarValue val; if (stricmp (key, "Path") == 0 && *value != '\0')
char *path;
val = autoexec->GetGenericRep (CVAR_String);
path = copystring (val.String);
delete autoexec;
SetSection (section, true);
SetValueForKey ("Path", path);
list->AppendArg (path);
delete[] path;
}
}
else
{
// If <game>.AutoExec section does not exist, create it
// with a default autoexec.cfg file present.
CreateStandardAutoExec(section, false);
// Run any files listed in the <game>.AutoExec section
if (!SectionIsEmpty())
{
while (NextInSection (key, value))
{ {
if (stricmp (key, "Path") == 0 && *value != '\0') FString expanded_path = ExpandEnvVars(value);
if (FileExists(expanded_path))
{ {
FString expanded_path = ExpandEnvVars(value); list->AppendArg (ExpandEnvVars(value));
if (FileExists(expanded_path))
{
list->AppendArg (ExpandEnvVars(value));
}
} }
} }
} }
@ -673,13 +651,6 @@ void FGameConfigFile::SetRavenDefaults (bool isHexen)
{ {
UCVarValue val; UCVarValue val;
if (bMigrating)
{
con_centernotify.ResetToDefault ();
msg0color.ResetToDefault ();
color.ResetToDefault ();
}
val.Bool = false; val.Bool = false;
wi_percents.SetGenericRepDefault (val, CVAR_Bool); wi_percents.SetGenericRepDefault (val, CVAR_Bool);
val.Bool = true; val.Bool = true;

View file

@ -38,15 +38,17 @@
#include "configfile.h" #include "configfile.h"
class DArgs; class DArgs;
class FIWadManager;
class FGameConfigFile : public FConfigFile class FGameConfigFile : public FConfigFile
{ {
public: public:
FGameConfigFile (); FGameConfigFile (FIWadManager *iwad_man);
~FGameConfigFile (); ~FGameConfigFile ();
void DoGlobalSetup (); void DoGlobalSetup ();
void DoGameSetup (const char *gamename); void DoGameSetup (const char *gamename);
void DoKeySetup (const char *gamename);
void DoModSetup (const char *gamename); void DoModSetup (const char *gamename);
void ArchiveGlobalData (); void ArchiveGlobalData ();
void ArchiveGameData (const char *gamename); void ArchiveGameData (const char *gamename);
@ -59,13 +61,9 @@ protected:
void CreateStandardAutoExec (const char *section, bool start); void CreateStandardAutoExec (const char *section, bool start);
private: private:
static void MigrateStub (const char *pathname, FConfigFile *config, void *userdata);
void MigrateOldConfig ();
void SetRavenDefaults (bool isHexen); void SetRavenDefaults (bool isHexen);
void ReadCVars (DWORD flags); void ReadCVars (DWORD flags);
bool bMigrating;
bool bModSetup; bool bModSetup;
char section[64]; char section[64];

View file

@ -335,7 +335,6 @@ void FMapInfoParser::ParseGameInfo()
GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime") GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime")
GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle") GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle")
GAMEINFOKEY_STRING(Endoom, "endoom") GAMEINFOKEY_STRING(Endoom, "endoom")
GAMEINFOKEY_INT(player5start, "player5start")
GAMEINFOKEY_STRINGARRAY(quitmessages, "addquitmessages", 0, false) GAMEINFOKEY_STRINGARRAY(quitmessages, "addquitmessages", 0, false)
GAMEINFOKEY_STRINGARRAY(quitmessages, "quitmessages", 0, true) GAMEINFOKEY_STRINGARRAY(quitmessages, "quitmessages", 0, true)
GAMEINFOKEY_STRING(mTitleColor, "menufontcolor_title") GAMEINFOKEY_STRING(mTitleColor, "menufontcolor_title")

View file

@ -153,7 +153,6 @@ struct gameinfo_t
int definventorymaxamount; int definventorymaxamount;
int defaultrespawntime; int defaultrespawntime;
int defaultdropstyle; int defaultdropstyle;
int player5start;
DWORD pickupcolor; DWORD pickupcolor;
TArray<FString> quitmessages; TArray<FString> quitmessages;
FName mTitleColor; FName mTitleColor;

View file

@ -319,7 +319,11 @@ void PacketGet (void)
} }
else if (c > 0) else if (c > 0)
{ //The packet is not from any in-game node, so we might as well discard it. { //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; doomcom.remotenode = -1;
return; return;
} }

View file

@ -141,9 +141,6 @@ void FActorInfo::StaticInit ()
void FActorInfo::StaticSetActorNums () void FActorInfo::StaticSetActorNums ()
{ {
SpawnableThings.Clear();
DoomEdMap.Empty ();
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
{ {
PClass::m_RuntimeActors[i]->ActorInfo->RegisterIDs (); PClass::m_RuntimeActors[i]->ActorInfo->RegisterIDs ();
@ -159,6 +156,15 @@ void FActorInfo::RegisterIDs ()
{ {
const PClass *cls = PClass::FindClass(Class->TypeName); const PClass *cls = PClass::FindClass(Class->TypeName);
// Conversation IDs have never been filtered by game so we cannot start doing that.
if (ConversationID > 0)
{
StrifeTypes[ConversationID] = cls;
if (cls != Class)
{
Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars());
}
}
if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype)) if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype))
{ {
if (SpawnID > 0) if (SpawnID > 0)
@ -171,23 +177,22 @@ void FActorInfo::RegisterIDs ()
} }
if (DoomEdNum != -1) if (DoomEdNum != -1)
{ {
DoomEdMap.AddType (DoomEdNum, cls); FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum);
if (oldent != NULL && oldent->Special == -2)
{
Printf(TEXTCOLOR_RED"Editor number %d defined twice for classes '%s' and '%s'\n", DoomEdNum, cls->TypeName.GetChars(), oldent->Type->TypeName.GetChars());
}
FDoomEdEntry ent;
memset(&ent, 0, sizeof(ent));
ent.Type = cls;
ent.Special = -2; // use -2 instead of -1 so that we can recognize DECORATE defined entries and print a warning message if duplicates occur.
DoomEdMap.Insert(DoomEdNum, ent);
if (cls != Class) if (cls != Class)
{ {
Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars()); Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars());
} }
} }
} }
// Fill out the list for Chex Quest with Doom's actors
if (gameinfo.gametype == GAME_Chex && DoomEdMap.FindType(DoomEdNum) == NULL &&
(GameFilter & GAME_Doom))
{
DoomEdMap.AddType (DoomEdNum, Class, true);
if (cls != Class)
{
Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars());
}
}
} }
//========================================================================== //==========================================================================
@ -389,139 +394,6 @@ fixed_t *DmgFactors::CheckFactor(FName type)
return pdf; return pdf;
} }
//==========================================================================
//
//
//==========================================================================
FDoomEdMap DoomEdMap;
FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE];
FDoomEdMap::~FDoomEdMap()
{
Empty();
}
void FDoomEdMap::AddType (int doomednum, const PClass *type, bool temporary)
{
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
FDoomEdEntry *entry = DoomEdHash[hash];
while (entry && entry->DoomEdNum != doomednum)
{
entry = entry->HashNext;
}
if (entry == NULL)
{
entry = new FDoomEdEntry;
entry->HashNext = DoomEdHash[hash];
entry->DoomEdNum = doomednum;
DoomEdHash[hash] = entry;
}
else if (!entry->temp)
{
Printf (PRINT_BOLD, "Warning: %s and %s both have doomednum %d.\n",
type->TypeName.GetChars(), entry->Type->TypeName.GetChars(), doomednum);
}
entry->temp = temporary;
entry->Type = type;
}
void FDoomEdMap::DelType (int doomednum)
{
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
FDoomEdEntry **prev = &DoomEdHash[hash];
FDoomEdEntry *entry = *prev;
while (entry && entry->DoomEdNum != doomednum)
{
prev = &entry->HashNext;
entry = entry->HashNext;
}
if (entry != NULL)
{
*prev = entry->HashNext;
delete entry;
}
}
void FDoomEdMap::Empty ()
{
int bucket;
for (bucket = 0; bucket < DOOMED_HASHSIZE; ++bucket)
{
FDoomEdEntry *probe = DoomEdHash[bucket];
while (probe != NULL)
{
FDoomEdEntry *next = probe->HashNext;
delete probe;
probe = next;
}
DoomEdHash[bucket] = NULL;
}
}
const PClass *FDoomEdMap::FindType (int doomednum) const
{
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
FDoomEdEntry *entry = DoomEdHash[hash];
while (entry && entry->DoomEdNum != doomednum)
entry = entry->HashNext;
return entry ? entry->Type : NULL;
}
struct EdSorting
{
const PClass *Type;
int DoomEdNum;
};
static int STACK_ARGS sortnums (const void *a, const void *b)
{
return ((const EdSorting *)a)->DoomEdNum -
((const EdSorting *)b)->DoomEdNum;
}
void FDoomEdMap::DumpMapThings ()
{
TArray<EdSorting> infos (PClass::m_Types.Size());
int i;
for (i = 0; i < DOOMED_HASHSIZE; ++i)
{
FDoomEdEntry *probe = DoomEdHash[i];
while (probe != NULL)
{
EdSorting sorting = { probe->Type, probe->DoomEdNum };
infos.Push (sorting);
probe = probe->HashNext;
}
}
if (infos.Size () == 0)
{
Printf ("No map things registered\n");
}
else
{
qsort (&infos[0], infos.Size (), sizeof(EdSorting), sortnums);
for (i = 0; i < (int)infos.Size (); ++i)
{
Printf ("%6d %s\n",
infos[i].DoomEdNum, infos[i].Type->TypeName.GetChars());
}
}
}
CCMD (dumpmapthings)
{
FDoomEdMap::DumpMapThings ();
}
static void SummonActor (int command, int command2, FCommandLine argv) static void SummonActor (int command, int command2, FCommandLine argv)
{ {
if (CheckCheatmode ()) if (CheckCheatmode ())

View file

@ -266,7 +266,8 @@ struct FActorInfo
FActorInfo *Replacee; FActorInfo *Replacee;
int NumOwnedStates; int NumOwnedStates;
BYTE GameFilter; BYTE GameFilter;
BYTE SpawnID; WORD SpawnID;
WORD ConversationID;
SWORD DoomEdNum; SWORD DoomEdNum;
FStateLabels *StateList; FStateLabels *StateList;
DmgFactors *DamageFactors; DmgFactors *DamageFactors;
@ -278,34 +279,51 @@ struct FActorInfo
TArray<const PClass *> ForbiddenToPlayerClass; TArray<const PClass *> ForbiddenToPlayerClass;
}; };
class FDoomEdMap struct FDoomEdEntry
{ {
public: const PClass *Type;
~FDoomEdMap(); short Special;
bool ArgsDefined;
const PClass *FindType (int doomednum) const; int Args[5];
void AddType (int doomednum, const PClass *type, bool temporary = false);
void DelType (int doomednum);
void Empty ();
static void DumpMapThings ();
private:
enum { DOOMED_HASHSIZE = 256 };
struct FDoomEdEntry
{
FDoomEdEntry *HashNext;
const PClass *Type;
int DoomEdNum;
bool temp;
};
static FDoomEdEntry *DoomEdHash[DOOMED_HASHSIZE];
}; };
enum ESpecialMapthings
{
SMT_Player1Start = 1,
SMT_Player2Start,
SMT_Player3Start,
SMT_Player4Start,
SMT_Player5Start,
SMT_Player6Start,
SMT_Player7Start,
SMT_Player8Start,
SMT_DeathmatchStart,
SMT_SSeqOverride,
SMT_PolyAnchor,
SMT_PolySpawn,
SMT_PolySpawnCrush,
SMT_PolySpawnHurt,
SMT_SlopeFloorPointLine,
SMT_SlopeCeilingPointLine,
SMT_SetFloorSlope,
SMT_SetCeilingSlope,
SMT_VavoomFloor,
SMT_VavoomCeiling,
SMT_CopyFloorPlane,
SMT_CopyCeilingPlane,
SMT_VertexFloorZ,
SMT_VertexCeilingZ,
};
typedef TMap<int, FDoomEdEntry> FDoomEdMap;
extern FDoomEdMap DoomEdMap; extern FDoomEdMap DoomEdMap;
void InitActorNumsFromMapinfo();
int GetSpriteIndex(const char * spritename, bool add = true); int GetSpriteIndex(const char * spritename, bool add = true);
TArray<FName> &MakeStateNameList(const char * fname); TArray<FName> &MakeStateNameList(const char * fname);
void AddStateLight(FState *state, const char *lname); void AddStateLight(FState *state, const char *lname);

View file

@ -410,9 +410,9 @@ CCMD (writeini)
// M_LoadDefaults // M_LoadDefaults
// //
void M_LoadDefaults () void M_LoadDefaults (FIWadManager *iwad_man)
{ {
GameConfig = new FGameConfigFile; GameConfig = new FGameConfigFile(iwad_man);
GameConfig->DoGlobalSetup (); GameConfig->DoGlobalSetup ();
atterm (M_SaveDefaultsFinal); atterm (M_SaveDefaultsFinal);
} }

View file

@ -28,6 +28,7 @@
class FConfigFile; class FConfigFile;
class FGameConfigFile; class FGameConfigFile;
class FIWadManager;
extern FGameConfigFile *GameConfig; extern FGameConfigFile *GameConfig;
@ -40,7 +41,7 @@ void M_FindResponseFile (void);
// Pass a NULL to get the original behavior. // Pass a NULL to get the original behavior.
void M_ScreenShot (const char *filename); void M_ScreenShot (const char *filename);
void M_LoadDefaults (); void M_LoadDefaults (FIWadManager *iwad_man);
bool M_SaveDefaults (const char *filename); bool M_SaveDefaults (const char *filename);
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen); void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen);

View file

@ -204,7 +204,7 @@ FString M_GetConfigPath(bool for_reading)
{ {
path += "/" GAME_DIR; path += "/" GAME_DIR;
CreatePath(path); CreatePath(path);
path += "/zdoom.ini"; path += "/" GAMENAMELOWERCASE ".ini";
} }
else else
{ // construct "$PROGDIR/zdoom-$USER.ini" { // construct "$PROGDIR/zdoom-$USER.ini"
@ -224,11 +224,11 @@ FString M_GetConfigPath(bool for_reading)
*probe = '_'; *probe = '_';
++probe; ++probe;
} }
path << "zdoom-" << uname << ".ini"; path << GAMENAMELOWERCASE "-" << uname << ".ini";
} }
else else
{ // Couldn't get user name, so just use zdoom.ini { // Couldn't get user name, so just use zdoom.ini
path += "zdoom.ini"; path += GAMENAMELOWERCASE ".ini";
} }
} }
@ -239,7 +239,7 @@ FString M_GetConfigPath(bool for_reading)
if (!FileExists(path)) if (!FileExists(path))
{ {
path = progdir; path = progdir;
path << "zdoom.ini"; path << GAMENAMELOWERCASE ".ini";
} }
} }
@ -411,11 +411,11 @@ FString M_GetConfigPath(bool for_reading)
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{ {
FString path; FString path;
path << cpath << "/zdoom.ini"; path << cpath << "/" GAMENAMELOWERCASE ".ini";
return path; return path;
} }
// Ungh. // Ungh.
return "zdoom.ini"; return GAMENAMELOWERCASE ".ini";
} }
//=========================================================================== //===========================================================================
@ -497,12 +497,12 @@ FString GetUserFile (const char *file)
// This can be removed after a release or two // This can be removed after a release or two
// Transfer the old zdoom directory to the new location // Transfer the old zdoom directory to the new location
bool moved = false; bool moved = false;
FString oldpath = NicePath("~/.zdoom/"); FString oldpath = NicePath("~/." GAMENAMELOWERCASE "/");
if (stat (oldpath, &extrainfo) != -1) if (stat (oldpath, &extrainfo) != -1)
{ {
if (rename(oldpath, path) == -1) if (rename(oldpath, path) == -1)
{ {
I_Error ("Failed to move old zdoom directory (%s) to new location (%s).", I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).",
oldpath.GetChars(), path.GetChars()); oldpath.GetChars(), path.GetChars());
} }
else else
@ -598,7 +598,7 @@ FString M_GetCajunPath(const char *botfilename)
FString M_GetConfigPath(bool for_reading) FString M_GetConfigPath(bool for_reading)
{ {
return GetUserFile("zdoom.ini"); return GetUserFile(GAMENAMELOWERCASE ".ini");
} }
//=========================================================================== //===========================================================================

View file

@ -489,7 +489,13 @@ bool FOptionMenuItem::MouseEvent(int type, int x, int y)
int FOptionMenuItem::GetIndent() 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) void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)

View file

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

View file

@ -45,6 +45,35 @@
// TYPES ------------------------------------------------------------------- // 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 -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -59,6 +88,173 @@
// CODE -------------------------------------------------------------------- // 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 // 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 FILE *file = fopen(Filename, "wb");
// is RAW. Otherwise, you can use DRO. if (file == NULL)
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)
{ {
Printf("Could not open %s for writing.\n", Filename.GetChars()); Printf("Could not open %s for writing.\n", Filename.GetChars());
return 0; 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); chips[0] = new OPL_RDOSdump(file);
NeedClockRate = true;
} }
else else
{ {
fwrite("DBRAWOPL" chips[0] = new OPL_DOSBOXdump(file, numchips > 1);
"\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;
} }
TimePerTick = 0;
TickMul = 1;
CurTime = 0;
CurIntTime = 0;
CurChip = 0;
OPLchannels = OPL2CHANNELS * numchips; OPLchannels = OPL2CHANNELS * numchips;
OPLwriteInitState(false); NumChips = numchips;
IsOPL3 = numchips > 1;
OPLwriteInitState(initopl3);
return numchips; 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 // DiskWriterIO :: SetClockRate
@ -280,39 +371,7 @@ void DiskWriterIO :: SetChip(int chipnum)
void DiskWriterIO::SetClockRate(double samples_per_tick) void DiskWriterIO::SetClockRate(double samples_per_tick)
{ {
TimePerTick = samples_per_tick / OPL_SAMPLE_RATE * 1000.0; static_cast<OPLDump *>(chips[0])->SetClockRate(samples_per_tick);
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);
}
}
} }
//========================================================================== //==========================================================================
@ -323,50 +382,5 @@ void DiskWriterIO::SetClockRate(double samples_per_tick)
void DiskWriterIO :: WriteDelay(int ticks) void DiskWriterIO :: WriteDelay(int ticks)
{ {
if (ticks <= 0) static_cast<OPLDump *>(chips[0])->WriteDelay(ticks);
{
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);
}
}
} }

View file

@ -195,25 +195,11 @@ struct DiskWriterIO : public OPLio
DiskWriterIO(const char *filename); DiskWriterIO(const char *filename);
~DiskWriterIO(); ~DiskWriterIO();
int OPLinit(uint numchips, bool notused=false, bool notused2=false); int OPLinit(uint numchips, bool notused, bool initopl3);
void OPLdeinit();
void OPLwriteReg(int which, uint reg, uchar data);
void SetClockRate(double samples_per_tick); void SetClockRate(double samples_per_tick);
void WriteDelay(int ticks); void WriteDelay(int ticks);
void SetChip(int chipnum);
FILE *File;
FString Filename; 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 { struct musicBlock {

View file

@ -220,7 +220,8 @@ static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
int tag=line->args[0]; int tag=line->args[0];
sector_t * sec = line->frontsector, * ss; sector_t * sec = line->frontsector, * ss;
for (s=-1; (s = P_FindSectorFromTag(tag,s)) >= 0;) FSectorTagIterator it(tag);
while ((s = it.Next()) >= 0)
{ {
ss=&sectors[s]; ss=&sectors[s];
@ -488,7 +489,7 @@ void P_Recalculate3DFloors(sector_t * sector)
// by the clipping code below. // by the clipping code below.
ffloors.Push(pick); ffloors.Push(pick);
} }
else if ((pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) || (!(pick->flags&(FF_ALLSIDES|FF_BOTHPLANES)))) && pick->flags&FF_EXISTS) else if ((pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) || (!(pick->flags&FF_RENDERALL))) && pick->flags&FF_EXISTS)
{ {
// We must check if this nonsolid segment gets clipped from the top by another 3D floor // We must check if this nonsolid segment gets clipped from the top by another 3D floor
if (solid != NULL && solid_bottom < height) if (solid != NULL && solid_bottom < height)
@ -843,7 +844,7 @@ void P_Spawn3DFloors (void)
{ {
if (line->args[1]&8) if (line->args[1]&8)
{ {
line->id = line->args[4]; tagManager.AddLineID(i, line->args[4]);
} }
else else
{ {

View file

@ -143,7 +143,9 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
if (tag == 0) if (tag == 0)
{ {
for(int line = -1; (line = P_FindLineFromID(lineid,line)) >= 0; ) FLineIdIterator itr(lineid);
int line;
while ((line = itr.Next()) >= 0)
{ {
line_t *ln = &lines[line]; line_t *ln = &lines[line];
@ -157,13 +159,15 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
} }
else else
{ {
for(int sec = -1; (sec = P_FindSectorFromTag(tag, sec)) >= 0; ) FSectorTagIterator it(tag);
int sec;
while ((sec = it.Next()) >= 0)
{ {
for (int line = 0; line < sectors[sec].linecount; line ++) for (int line = 0; line < sectors[sec].linecount; line ++)
{ {
line_t *ln = sectors[sec].lines[line]; line_t *ln = sectors[sec].lines[line];
if (lineid != 0 && ln->id != lineid) continue; if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX)) if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
{ {

View file

@ -1341,7 +1341,7 @@ DPlaneWatcher::DPlaneWatcher (AActor *it, line_t *line, int lineSide, bool ceili
{ {
int secnum; int secnum;
secnum = P_FindSectorFromTag (tag, -1); secnum = P_FindFirstSectorFromTag (tag);
if (secnum >= 0) if (secnum >= 0)
{ {
secplane_t plane; secplane_t plane;
@ -1409,12 +1409,6 @@ void DPlaneWatcher::Tick ()
// own behavior is loaded (if it has one). // own behavior is loaded (if it has one).
void FBehavior::StaticLoadDefaultModules () void FBehavior::StaticLoadDefaultModules ()
{ {
// When playing Strife, STRFHELP is always loaded.
if (gameinfo.gametype == GAME_Strife)
{
StaticLoadModule (Wads.CheckNumForName ("STRFHELP", ns_acslibrary));
}
// Scan each LOADACS lump and load the specified modules in order // Scan each LOADACS lump and load the specified modules in order
int lump, lastlump = 0; int lump, lastlump = 0;
@ -3217,7 +3211,7 @@ do_count:
if (actor->health > 0 && if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind))) (kind == NULL || actor->IsA (kind)))
{ {
if (actor->Sector->tag == tag || tag == -1) if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{ {
// Don't count items in somebody's inventory // Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) || if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||
@ -3237,7 +3231,7 @@ do_count:
if (actor->health > 0 && if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind))) (kind == NULL || actor->IsA (kind)))
{ {
if (actor->Sector->tag == tag || tag == -1) if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{ {
// Don't count items in somebody's inventory // Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) || if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||
@ -3274,7 +3268,8 @@ void DLevelScript::ChangeFlat (int tag, int name, bool floorOrCeiling)
flat = TexMan.GetTexture (flatname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); flat = TexMan.GetTexture (flatname, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{ {
int pos = floorOrCeiling? sector_t::ceiling : sector_t::floor; int pos = floorOrCeiling? sector_t::ceiling : sector_t::floor;
sectors[secnum].SetTexture(pos, flat); sectors[secnum].SetTexture(pos, flat);
@ -3305,7 +3300,8 @@ void DLevelScript::SetLineTexture (int lineid, int side, int position, int name)
texture = TexMan.GetTexture (texname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); texture = TexMan.GetTexture (texname, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
while ((linenum = P_FindLineFromID (lineid, linenum)) >= 0) FLineIdIterator itr(lineid);
while ((linenum = itr.Next()) >= 0)
{ {
side_t *sidedef; side_t *sidedef;
@ -3903,7 +3899,13 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
case APROP_ViewHeight: case APROP_ViewHeight:
if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
{
static_cast<APlayerPawn *>(actor)->ViewHeight = value; static_cast<APlayerPawn *>(actor)->ViewHeight = value;
if (actor->player != NULL)
{
actor->player->viewheight = value;
}
}
break; break;
case APROP_AttackZOffset: case APROP_AttackZOffset:
@ -4463,7 +4465,7 @@ int DLevelScript::SideFromID(int id, int side)
} }
else else
{ {
int line = P_FindLineFromID(id, -1); int line = P_FindFirstLineFromID(id);
if (line == -1) return -1; if (line == -1) return -1;
if (lines[line].sidedef[side] == NULL) return -1; if (lines[line].sidedef[side] == NULL) return -1;
return lines[line].sidedef[side]->Index; return lines[line].sidedef[side]->Index;
@ -4479,7 +4481,7 @@ int DLevelScript::LineFromID(int id)
} }
else else
{ {
return P_FindLineFromID(id, -1); return P_FindFirstLineFromID(id);
} }
} }
@ -4767,25 +4769,19 @@ static void SetActorRoll(AActor *activator, int tid, int angle, bool interpolate
} }
} }
static void SetActorTeleFog(AActor *activator, int tid, FName telefogsrc, FName telefogdest) static void SetActorTeleFog(AActor *activator, int tid, FString telefogsrc, FString telefogdest)
{ {
//Simply put, if it doesn't exist, it won't change. One can use "" in this scenario. // Set the actor's telefog to the specified actor. Handle "" as "don't
const PClass *check; // change" since "None" should work just fine for disabling the fog (given
// that it will resolve to NAME_None which is not a valid actor name).
if (tid == 0) if (tid == 0)
{ {
if (activator != NULL) if (activator != NULL)
{ {
check = PClass::FindClass(telefogsrc); if (telefogsrc.IsNotEmpty())
if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null")) activator->TeleFogSourceType = PClass::FindClass(telefogsrc);
activator->TeleFogSourceType = NULL; if (telefogdest.IsNotEmpty())
else activator->TeleFogDestType = PClass::FindClass(telefogdest);
activator->TeleFogSourceType = check;
check = PClass::FindClass(telefogdest);
if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null"))
activator->TeleFogDestType = NULL;
else
activator->TeleFogDestType = check;
} }
} }
else else
@ -4793,19 +4789,14 @@ static void SetActorTeleFog(AActor *activator, int tid, FName telefogsrc, FName
FActorIterator iterator(tid); FActorIterator iterator(tid);
AActor *actor; AActor *actor;
const PClass * const src = telefogsrc.IsNotEmpty() ? PClass::FindClass(telefogsrc) : NULL;
const PClass * const dest = telefogdest.IsNotEmpty() ? PClass::FindClass(telefogdest) : NULL;
while ((actor = iterator.Next())) while ((actor = iterator.Next()))
{ {
check = PClass::FindClass(telefogsrc); if (telefogsrc.IsNotEmpty())
if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null")) actor->TeleFogSourceType = src;
actor->TeleFogSourceType = NULL; if (telefogdest.IsNotEmpty())
else actor->TeleFogDestType = dest;
actor->TeleFogSourceType = check;
check = PClass::FindClass(telefogdest);
if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null"))
actor->TeleFogDestType = NULL;
else
actor->TeleFogDestType = check;
} }
} }
} }
@ -4856,10 +4847,10 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
return 0; // Not implemented yet return 0; // Not implemented yet
case ACSF_GetSectorUDMFInt: case ACSF_GetSectorUDMFInt:
return GetUDMFInt(UDMF_Sector, P_FindSectorFromTag(args[0], -1), FBehavior::StaticLookupString(args[1])); return GetUDMFInt(UDMF_Sector, P_FindFirstSectorFromTag(args[0]), FBehavior::StaticLookupString(args[1]));
case ACSF_GetSectorUDMFFixed: case ACSF_GetSectorUDMFFixed:
return GetUDMFFixed(UDMF_Sector, P_FindSectorFromTag(args[0], -1), FBehavior::StaticLookupString(args[1])); return GetUDMFFixed(UDMF_Sector, P_FindFirstSectorFromTag(args[0]), FBehavior::StaticLookupString(args[1]));
case ACSF_GetSideUDMFInt: case ACSF_GetSideUDMFInt:
return GetUDMFInt(UDMF_Side, SideFromID(args[0], args[1]), FBehavior::StaticLookupString(args[2])); return GetUDMFInt(UDMF_Side, SideFromID(args[0], args[1]), FBehavior::StaticLookupString(args[2]));
@ -5186,11 +5177,11 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
int space = args[2] < CHAN_FLOOR || args[2] > CHAN_INTERIOR ? CHAN_FULLHEIGHT : args[2]; int space = args[2] < CHAN_FLOOR || args[2] > CHAN_INTERIOR ? CHAN_FULLHEIGHT : args[2];
if (seqname != NULL) if (seqname != NULL)
{ {
int secnum = -1; FSectorTagIterator it(args[0]);
int s;
while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) while ((s = it.Next()) >= 0)
{ {
SN_StartSequence(&sectors[secnum], args[2], seqname, 0); SN_StartSequence(&sectors[s], args[2], seqname, 0);
} }
} }
} }
@ -5709,9 +5700,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_SetLineActivation: case ACSF_SetLineActivation:
if (argCount >= 2) if (argCount >= 2)
{ {
int line = -1; int line;
FLineIdIterator itr(args[0]);
while ((line = P_FindLineFromID(args[0], line)) >= 0) while ((line = itr.Next()) >= 0)
{ {
lines[line].activation = args[1]; lines[line].activation = args[1];
} }
@ -5721,7 +5712,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_GetLineActivation: case ACSF_GetLineActivation:
if (argCount > 0) if (argCount > 0)
{ {
int line = P_FindLineFromID(args[0], -1); int line = P_FindFirstLineFromID(args[0]);
return line >= 0 ? lines[line].activation : 0; return line >= 0 ? lines[line].activation : 0;
} }
break; break;
@ -5969,11 +5960,13 @@ int DLevelScript::RunScript ()
// Wait for tagged sector(s) to go inactive, then enter // Wait for tagged sector(s) to go inactive, then enter
// state running // state running
{ {
int secnum = -1; int secnum;
FSectorTagIterator it(statedata);
while ((secnum = P_FindSectorFromTag (statedata, secnum)) >= 0) while ((secnum = it.Next()) >= 0)
{
if (sectors[secnum].floordata || sectors[secnum].ceilingdata) if (sectors[secnum].floordata || sectors[secnum].ceilingdata)
return resultValue; return resultValue;
}
// If we got here, none of the tagged sectors were busy // If we got here, none of the tagged sectors were busy
state = SCRIPT_Running; state = SCRIPT_Running;
@ -8013,9 +8006,10 @@ scriptwait:
case PCD_SETLINEBLOCKING: case PCD_SETLINEBLOCKING:
{ {
int line = -1; int line;
while ((line = P_FindLineFromID (STACK(2), line)) >= 0) FLineIdIterator itr(STACK(2));
while ((line = itr.Next()) >= 0)
{ {
switch (STACK(1)) switch (STACK(1))
{ {
@ -8048,9 +8042,10 @@ scriptwait:
case PCD_SETLINEMONSTERBLOCKING: case PCD_SETLINEMONSTERBLOCKING:
{ {
int line = -1; int line;
while ((line = P_FindLineFromID (STACK(2), line)) >= 0) FLineIdIterator itr(STACK(2));
while ((line = itr.Next()) >= 0)
{ {
if (STACK(1)) if (STACK(1))
lines[line].flags |= ML_BLOCKMONSTERS; lines[line].flags |= ML_BLOCKMONSTERS;
@ -8075,7 +8070,8 @@ scriptwait:
arg0 = -FName(FBehavior::StaticLookupString(arg0)); arg0 = -FName(FBehavior::StaticLookupString(arg0));
} }
while ((linenum = P_FindLineFromID (STACK(7), linenum)) >= 0) FLineIdIterator itr(STACK(7));
while ((linenum = itr.Next()) >= 0)
{ {
line_t *line = &lines[linenum]; line_t *line = &lines[linenum];
line->special = specnum; line->special = specnum;
@ -8535,7 +8531,7 @@ scriptwait:
fixed_t z = 0; fixed_t z = 0;
if (tag != 0) if (tag != 0)
secnum = P_FindSectorFromTag (tag, -1); secnum = P_FindFirstSectorFromTag (tag);
else else
secnum = int(P_PointInSector (x, y) - sectors); secnum = int(P_PointInSector (x, y) - sectors);
@ -8557,7 +8553,7 @@ scriptwait:
case PCD_GETSECTORLIGHTLEVEL: case PCD_GETSECTORLIGHTLEVEL:
{ {
int secnum = P_FindSectorFromTag (STACK(1), -1); int secnum = P_FindFirstSectorFromTag (STACK(1));
int z = -1; int z = -1;
if (secnum >= 0) if (secnum >= 0)

View file

@ -716,30 +716,31 @@ static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites,
mapthings[count].args[1] = xsprites[i].Data4; mapthings[count].args[1] = xsprites[i].Data4;
mapthings[count].args[2] = xsprites[i].Data1; mapthings[count].args[2] = xsprites[i].Data1;
mapthings[count].args[3] = xsprites[i].Data2; mapthings[count].args[3] = xsprites[i].Data2;
mapthings[count].type = 14065; mapthings[count].EdNum = 14065;
} }
else if (xsprites != NULL && sprites[i].lotag == 1) else if (xsprites != NULL && sprites[i].lotag == 1)
{ // Blood player start { // Blood player start
if (xsprites[i].Data1 < 4) if (xsprites[i].Data1 < 4)
mapthings[count].type = 1 + xsprites[i].Data1; mapthings[count].EdNum= 1 + xsprites[i].Data1;
else else
mapthings[count].type = gameinfo.player5start + xsprites[i].Data1 - 4; mapthings[count].EdNum = 4001 + xsprites[i].Data1 - 4;
} }
else if (xsprites != NULL && sprites[i].lotag == 2) else if (xsprites != NULL && sprites[i].lotag == 2)
{ // Bloodbath start { // Bloodbath start
mapthings[count].type = 11; mapthings[count].EdNum = 11;
} }
else else
{ {
if (sprites[i].cstat & 32768) continue; if (sprites[i].cstat & 32768) continue;
if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue; if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue;
mapthings[count].type = 9988; mapthings[count].EdNum = 9988;
mapthings[count].args[0] = sprites[i].picnum; mapthings[count].args[0] = sprites[i].picnum;
mapthings[count].args[2] = sprites[i].xrepeat; mapthings[count].args[2] = sprites[i].xrepeat;
mapthings[count].args[3] = sprites[i].yrepeat; mapthings[count].args[3] = sprites[i].yrepeat;
mapthings[count].args[4] = sprites[i].cstat; mapthings[count].args[4] = sprites[i].cstat;
} }
mapthings[count].info = DoomEdMap.CheckKey(mapthings[count].EdNum);
count++; count++;
} }
return count; return count;
@ -780,14 +781,14 @@ vertex_t *FindVertex (fixed_t x, fixed_t y)
static void CreateStartSpot (fixed_t *pos, FMapThing *start) static void CreateStartSpot (fixed_t *pos, FMapThing *start)
{ {
short angle = LittleShort(*(WORD *)(&pos[3])); short angle = LittleShort(*(WORD *)(&pos[3]));
FMapThing mt = FMapThing mt = { 0, };
{
0, (LittleLong(pos[0])<<12), ((-LittleLong(pos[1]))<<12), 0,// tid, x, y, z mt.x = LittleLong(pos[0])<<12;
short(Scale ((2048-angle)&2047, 360, 2048)), 1, // angle, type mt.y = (-LittleLong(pos[1]))<<12;
0, 0, // Skillfilter, Classfilter mt.angle = short(Scale((2048-angle)&2047, 360, 2048));
7|MTF_SINGLE|224, // flags mt.info = DoomEdMap.CheckKey(1);
0, {0}, 0 // special is 0, args and Conversation are 0 mt.EdNum = 1;
}; mt.flags = 7|MTF_SINGLE|224;
*start = mt; *start = mt;
} }

View file

@ -510,9 +510,9 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
P_ActivateInStasisCeiling (tag); P_ActivateInStasisCeiling (tag);
} }
secnum = -1;
// affects all sectors with the same tag as the linedef // affects all sectors with the same tag as the linedef
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{ {
rtn |= !!DCeiling::Create(&sectors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush); rtn |= !!DCeiling::Create(&sectors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
} }

View file

@ -60,6 +60,7 @@
#include "farchive.h" #include "farchive.h"
#include "p_lnspec.h" #include "p_lnspec.h"
#include "r_utility.h" #include "r_utility.h"
#include "p_local.h"
#include "menu/menu.h" #include "menu/menu.h"
// The conversations as they exist inside a SCRIPTxx lump. // The conversations as they exist inside a SCRIPTxx lump.
@ -105,11 +106,10 @@ void GiveSpawner (player_t *player, const PClass *type);
TArray<FStrifeDialogueNode *> StrifeDialogues; TArray<FStrifeDialogueNode *> StrifeDialogues;
typedef TMap<int, const PClass *> FStrifeTypeMap; // maps conversation IDs to actor classes
typedef TMap<int, int> FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) typedef TMap<int, int> FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS)
typedef TMap<FName, int> FDialogueMap; // maps actor class names to dialogue array index typedef TMap<FName, int> FDialogueMap; // maps actor class names to dialogue array index
static FStrifeTypeMap StrifeTypes; FClassMap StrifeTypes;
static FDialogueIDMap DialogueRoots; static FDialogueIDMap DialogueRoots;
static FDialogueMap ClassRoots; static FDialogueMap ClassRoots;
static int ConversationMenuY; static int ConversationMenuY;

View file

@ -484,8 +484,8 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
else else
{ // [RH] Remote door { // [RH] Remote door
secnum = -1; FSectorTagIterator it(tag);
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0) while ((secnum = it.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
// if the ceiling is already moving, don't start the door action // if the ceiling is already moving, don't start the door action
@ -812,7 +812,8 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay)
return false; return false;
} }
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
if (sec->ceilingdata != NULL) if (sec->ceilingdata != NULL)

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; double length, lengthsquared;
int steps, i; int steps, i;
@ -678,7 +678,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end
color1 = color1 == 0 ? -1 : ParticleColor(color1); color1 = color1 == 0 ? -1 : ParticleColor(color1);
pos = start; pos = start;
deg = FAngle(270); deg = FAngle(SpiralOffset);
for (i = spiral_steps; i; i--) for (i = spiral_steps; i; i--)
{ {
particle_t *p = NewParticle (); particle_t *p = NewParticle ();

View file

@ -88,7 +88,7 @@ void P_RunEffects (void);
void P_RunEffect (AActor *actor, int effects); 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_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_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind);
void P_DisconnectEffect (AActor *actor); void P_DisconnectEffect (AActor *actor);

View file

@ -44,6 +44,7 @@
#include "thingdef/thingdef.h" #include "thingdef/thingdef.h"
#include "d_dehacked.h" #include "d_dehacked.h"
#include "g_level.h" #include "g_level.h"
#include "r_data/r_translate.h"
#include "teaminfo.h" #include "teaminfo.h"
#include "gi.h" #include "gi.h"
@ -2615,7 +2616,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
info = corpsehit->GetDefault(); info = corpsehit->GetDefault();
if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) if (GetTranslationType(corpsehit->Translation) == TRANSLATION_Blood)
{ {
corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses
} }
@ -3203,10 +3204,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die)
ACTION_PARAM_START(1); ACTION_PARAM_START(1);
ACTION_PARAM_NAME(damagetype, 0); ACTION_PARAM_NAME(damagetype, 0);
if (self->flags & MF_MISSILE) P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED);
P_ExplodeMissile(self, NULL, NULL);
else
P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED);
} }
// //

View file

@ -290,28 +290,13 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
rtn = false; rtn = false;
// check if a manual trigger; if so do just the sector on the backside // check if a manual trigger; if so do just the sector on the backside
if (tag == 0) FSectorTagIterator it(tag, line);
{ while ((secnum = it.Next()) >= 0)
if (!line || !(sec = line->backsector))
return rtn;
secnum = (int)(sec-sectors);
goto manual_floor;
}
secnum = -1;
while (tag && (secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
manual_floor:
// ALREADY MOVING? IF SO, KEEP GOING... // ALREADY MOVING? IF SO, KEEP GOING...
if (sec->PlaneMoving(sector_t::floor)) if (sec->PlaneMoving(sector_t::floor))
{ {
// There was a test for 0/non-0 here, supposed to prevent 0-tags from executing "continue" and searching for unrelated sectors
// Unfortunately, the condition had been reversed, so that searches for tag-0 would continue,
// while numbered tags would abort (return false, even if some floors have been successfully triggered)
// All occurences of the condition (faulty or not) have been replaced by a looping condition: Looping only occurs if we're looking for a non-0 tag.
continue; continue;
} }
@ -545,9 +530,9 @@ manual_floor:
bool EV_FloorCrushStop (int tag) bool EV_FloorCrushStop (int tag)
{ {
int secnum = -1; int secnum;
FSectorTagIterator it(tag);
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) while ((secnum = it.Next()) >= 0)
{ {
sector_t *sec = sectors + secnum; sector_t *sec = sectors + secnum;
@ -562,21 +547,6 @@ bool EV_FloorCrushStop (int tag)
return true; return true;
} }
//==========================================================================
//
// Linear tag search to emulate stair building from Doom.exe
//
//==========================================================================
static int P_FindSectorFromTagLinear (int tag, int start)
{
for (int i=start+1;i<numsectors;i++)
{
if (sectors[i].tag == tag) return i;
}
return -1;
}
//========================================================================== //==========================================================================
// //
// BUILD A STAIRCASE! // BUILD A STAIRCASE!
@ -591,7 +561,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt, fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt,
int usespecials) int usespecials)
{ {
int secnum; int secnum = -1;
int osecnum; //jff 3/4/98 save old loop index int osecnum; //jff 3/4/98 save old loop index
int height; int height;
fixed_t stairstep; fixed_t stairstep;
@ -607,44 +577,27 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
sector_t* prev = NULL; sector_t* prev = NULL;
DFloor* floor; DFloor* floor;
bool manual = false;
if (speed == 0) if (speed == 0)
return false; return false;
persteptime = FixedDiv (stairsize, speed) >> FRACBITS; persteptime = FixedDiv (stairsize, speed) >> FRACBITS;
int (* FindSector) (int tag, int start) =
(i_compatflags & COMPATF_STAIRINDEX)? P_FindSectorFromTagLinear : P_FindSectorFromTag;
// check if a manual trigger, if so do just the sector on the backside // check if a manual trigger, if so do just the sector on the backside
if (tag == 0) FSectorTagIterator itr(tag, line);
{
if (!line || !(sec = line->backsector))
return rtn;
secnum = (int)(sec-sectors);
manual = true;
goto manual_stair;
}
// The compatibility mode doesn't work with a hashing algorithm. // The compatibility mode doesn't work with a hashing algorithm.
// It needs the original linear search method. This was broken in Boom. // It needs the original linear search method. This was broken in Boom.
bool compatible = tag != 0 && (i_compatflags & COMPATF_STAIRINDEX);
secnum = -1; while ((secnum = itr.NextCompat(compatible, secnum)) >= 0)
while ((secnum = FindSector (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
manual_stair:
// ALREADY MOVING? IF SO, KEEP GOING... // ALREADY MOVING? IF SO, KEEP GOING...
//jff 2/26/98 add special lockout condition to wait for entire //jff 2/26/98 add special lockout condition to wait for entire
//staircase to build before retriggering //staircase to build before retriggering
if (sec->PlaneMoving(sector_t::floor) || sec->stairlock) if (sec->PlaneMoving(sector_t::floor) || sec->stairlock)
{ {
if (!manual) continue;
continue;
else
return rtn;
} }
// new floor thinker // new floor thinker
@ -781,14 +734,6 @@ manual_stair:
// [RH] make sure the first sector doesn't point to a previous one, otherwise // [RH] make sure the first sector doesn't point to a previous one, otherwise
// it can infinite loop when the first sector stops moving. // it can infinite loop when the first sector stops moving.
sectors[osecnum].prevsec = -1; sectors[osecnum].prevsec = -1;
if (manual)
{
return rtn;
}
if (!(i_compatflags & COMPATF_STAIRINDEX))
{
secnum = osecnum; //jff 3/4/98 restore loop index
}
} }
return rtn; return rtn;
} }
@ -811,21 +756,13 @@ bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed)
vertex_t* spot; vertex_t* spot;
fixed_t height; fixed_t height;
secnum = -1;
rtn = false; rtn = false;
if (tag == 0) FSectorTagIterator itr(tag, line);
{ while ((secnum = itr.Next()) >= 0)
if (!line || !(s1 = line->backsector))
return rtn;
goto manual_donut;
}
while (tag && (secnum = P_FindSectorFromTag(tag,secnum)) >= 0)
{ {
s1 = &sectors[secnum]; // s1 is pillar's sector s1 = &sectors[secnum]; // s1 is pillar's sector
manual_donut:
// ALREADY MOVING? IF SO, KEEP GOING... // ALREADY MOVING? IF SO, KEEP GOING...
if (s1->PlaneMoving(sector_t::floor)) if (s1->PlaneMoving(sector_t::floor))
continue; // safe now, because we check that tag is non-0 in the looping condition [fdari] continue; // safe now, because we check that tag is non-0 in the looping condition [fdari]
@ -1042,19 +979,12 @@ bool EV_DoElevator (line_t *line, DElevator::EElevator elevtype,
secnum = -1; secnum = -1;
rtn = false; rtn = false;
if (tag == 0) FSectorTagIterator itr(tag, line);
{
if (!line || !(sec = line->backsector))
return rtn;
goto manual_elevator;
}
// act on all sectors with the same tag as the triggering linedef // act on all sectors with the same tag as the triggering linedef
while (tag && (secnum = P_FindSectorFromTag (tag, secnum)) >= 0) // never loop for a non-0 tag (condition moved to beginning of loop) [FDARI] while ((secnum = itr.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
manual_elevator:
// If either floor or ceiling is already activated, skip it // If either floor or ceiling is already activated, skip it
if (sec->PlaneMoving(sector_t::floor) || sec->ceilingdata) //jff 2/22/98 if (sec->PlaneMoving(sector_t::floor) || sec->ceilingdata) //jff 2/22/98
continue; // the loop used to break at the end if tag were 0, but would miss that step if "continue" occured [FDARI] continue; // the loop used to break at the end if tag were 0, but would miss that step if "continue" occured [FDARI]
@ -1142,10 +1072,10 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
sector_t *sec; sector_t *sec;
sector_t *secm; sector_t *secm;
secnum = -1;
rtn = false; rtn = false;
// change all sectors with the same tag as the linedef // change all sectors with the same tag as the linedef
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
@ -1374,20 +1304,12 @@ bool EV_StartWaggle (int tag, line_t *line, int height, int speed, int offset,
bool retCode; bool retCode;
retCode = false; retCode = false;
sectorIndex = -1;
if (tag == 0) FSectorTagIterator itr(tag, line);
{
if (!line || !(sector = line->backsector))
return retCode;
goto manual_waggle;
}
while ((sectorIndex = itr.Next()) >= 0)
while (tag && (sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{ {
sector = &sectors[sectorIndex]; sector = &sectors[sectorIndex];
manual_waggle:
if ((!ceiling && sector->PlaneMoving(sector_t::floor)) || if ((!ceiling && sector->PlaneMoving(sector_t::floor)) ||
(ceiling && sector->PlaneMoving(sector_t::ceiling))) (ceiling && sector->PlaneMoving(sector_t::ceiling)))
{ // Already busy with another thinker { // Already busy with another thinker

View file

@ -338,7 +338,14 @@ static bool LoadGLSegs(FileReader * lump)
ml->side=LittleShort(ml->side); ml->side=LittleShort(ml->side);
segs[i].sidedef = ldef->sidedef[ml->side]; segs[i].sidedef = ldef->sidedef[ml->side];
segs[i].frontsector = ldef->sidedef[ml->side]->sector; if (ldef->sidedef[ml->side] != NULL)
{
segs[i].frontsector = ldef->sidedef[ml->side]->sector;
}
else
{
segs[i].frontsector = NULL;
}
if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL)
{ {
segs[i].backsector = ldef->sidedef[ml->side^1]->sector; segs[i].backsector = ldef->sidedef[ml->side^1]->sector;
@ -346,7 +353,7 @@ static bool LoadGLSegs(FileReader * lump)
else else
{ {
ldef->flags &= ~ML_TWOSIDED; ldef->flags &= ~ML_TWOSIDED;
segs[i].backsector = 0; segs[i].backsector = NULL;
} }
} }
@ -385,7 +392,14 @@ static bool LoadGLSegs(FileReader * lump)
ml->side=LittleShort(ml->side); ml->side=LittleShort(ml->side);
segs[i].sidedef = ldef->sidedef[ml->side]; segs[i].sidedef = ldef->sidedef[ml->side];
segs[i].frontsector = ldef->sidedef[ml->side]->sector; if (ldef->sidedef[ml->side] != NULL)
{
segs[i].frontsector = ldef->sidedef[ml->side]->sector;
}
else
{
segs[i].frontsector = NULL;
}
if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL)
{ {
segs[i].backsector = ldef->sidedef[ml->side^1]->sector; segs[i].backsector = ldef->sidedef[ml->side^1]->sector;
@ -393,7 +407,7 @@ static bool LoadGLSegs(FileReader * lump)
else else
{ {
ldef->flags &= ~ML_TWOSIDED; ldef->flags &= ~ML_TWOSIDED;
segs[i].backsector = 0; segs[i].backsector = NULL;
} }
} }

View file

@ -925,9 +925,9 @@ static inline bool MustForcePain(AActor *target, AActor *inflictor)
(inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)); (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS));
} }
static inline bool isFakePain(AActor *target, AActor *inflictor) static inline bool isFakePain(AActor *target, AActor *inflictor, int damage)
{ {
return ((target->flags7 & MF7_ALLOWPAIN) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))); return ((target->flags7 & MF7_ALLOWPAIN && damage > 0) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)));
} }
@ -950,13 +950,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
int fakeDamage = 0; int fakeDamage = 0;
int holdDamage = 0; int holdDamage = 0;
if (damage < 0) damage = 0;
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
{ // Shouldn't happen { // Shouldn't happen
return -1; return -1;
} }
//Rather than unnecessarily call the function over and over again, let's be a little more efficient. //Rather than unnecessarily call the function over and over again, let's be a little more efficient.
fakedPain = (isFakePain(target, inflictor)); fakedPain = (isFakePain(target, inflictor, damage));
forcedPain = (MustForcePain(target, inflictor)); forcedPain = (MustForcePain(target, inflictor));
// Spectral targets only take damage from spectral projectiles. // Spectral targets only take damage from spectral projectiles.
@ -989,9 +991,11 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
if (fakedPain) if (fakedPain)
{ {
invulpain = true; //This returns -1 later. // big mess here: What do we use for the pain threshold?
fakeDamage = damage; // We cannot run the various damage filters below so for consistency it needs to be 0.
goto fakepain; //The label is above the massive pile of checks. damage = 0;
invulpain = true;
goto fakepain;
} }
else else
return -1; return -1;
@ -1010,12 +1014,6 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
} }
} }
if ((fakedPain) && (damage < TELEFRAG_DAMAGE))
{
//Intentionally do not jump to fakepain because the damage hasn't been dished out yet.
//Once it's dished out, THEN we can disregard damage factors affecting pain chances.
fakeDamage = damage;
}
if (inflictor != NULL) if (inflictor != NULL)
{ {
@ -1035,7 +1033,9 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
target->velx = target->vely = target->velz = 0; target->velx = target->vely = target->velz = 0;
} }
if (!(flags & DMG_FORCED)) // DMG_FORCED skips all special damage checks
player = target->player;
if (!(flags & DMG_FORCED)) // DMG_FORCED skips all special damage checks, TELEFRAG_DAMAGE may not be reduced at all
{ {
if (target->flags2 & MF2_DORMANT) if (target->flags2 & MF2_DORMANT)
{ {
@ -1043,105 +1043,97 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
return -1; return -1;
} }
player = target->player; if (damage < TELEFRAG_DAMAGE) // TELEFRAG_DAMAGE may not be reduced at all or it may not guarantee its effect.
if (player && damage > 1 && damage < TELEFRAG_DAMAGE)
{ {
// Take half damage in trainer mode if (player && damage > 1)
damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor));
}
// Special damage types
if (inflictor)
{
if (inflictor->flags4 & MF4_SPECTRAL)
{ {
if (player != NULL) // Take half damage in trainer mode
damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor));
}
// Special damage types
if (inflictor)
{
if (inflictor->flags4 & MF4_SPECTRAL)
{ {
if (!deathmatch && inflictor->FriendPlayer > 0) if (player != NULL)
return -1; {
if (!deathmatch && inflictor->FriendPlayer > 0)
return -1;
}
else if (target->flags4 & MF4_SPECTRAL)
{
if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor))
return -1;
}
} }
else if (target->flags4 & MF4_SPECTRAL)
damage = inflictor->DoSpecialDamage(target, damage, mod);
if (damage < 0)
{ {
if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor)) return -1;
return -1;
} }
} }
if (damage > 0)
damage = inflictor->DoSpecialDamage (target, damage, mod);
if ((damage == -1) && (target->player == NULL)) //This isn't meant for the player.
{
if (fakedPain) //Hold off ending the function before we can deal the pain chances.
goto fakepain;
return -1;
}
}
// Handle active damage modifiers (e.g. PowerDamage)
if (source != NULL)
{
int olddam = damage; int olddam = damage;
if (source->Inventory != NULL) if (damage > 0 && source != NULL)
{ {
source->Inventory->ModifyDamage(olddam, mod, damage, false); damage = FixedMul(damage, source->DamageMultiply);
// Handle active damage modifiers (e.g. PowerDamage)
if (damage > 0 && source->Inventory != NULL)
{
source->Inventory->ModifyDamage(damage, mod, damage, false);
}
} }
damage = FixedMul(damage, source->DamageMultiply); // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers.
if (damage > 0 && (target->Inventory != NULL) && !(flags & DMG_NO_PROTECT))
if (((source->flags7 & MF7_CAUSEPAIN) && (fakeDamage <= 0)) || (olddam != damage && damage <= 0))
{ // Still allow FORCEPAIN
if (forcedPain)
goto dopain;
else if (fakedPain)
goto fakepain;
return -1;
}
}
// Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers.
if ((target->Inventory != NULL) && !(flags & DMG_NO_PROTECT))
{
int olddam = damage;
target->Inventory->ModifyDamage(olddam, mod, damage, true);
if ((olddam != damage && damage <= 0) && target->player == NULL)
{ // Still allow FORCEPAIN and make sure we're still passing along fake damage to hit enemies for their pain states.
if (forcedPain)
goto dopain;
else if (fakedPain)
goto fakepain;
return -1;
}
}
if (!(flags & DMG_NO_FACTOR))
{
damage = FixedMul(damage, target->DamageFactor);
if (damage > 0)
{ {
damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, mod, target->GetClass()->ActorInfo->DamageFactors); target->Inventory->ModifyDamage(damage, mod, damage, true);
}
if (damage > 0 && !(flags & DMG_NO_FACTOR))
{
damage = FixedMul(damage, target->DamageFactor);
if (damage > 0)
{
damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, mod, target->GetClass()->ActorInfo->DamageFactors);
}
} }
if (damage <= 0 && target->player == NULL)
{ // Still allow FORCEPAIN
if (forcedPain)
goto dopain;
else if (fakedPain)
goto fakepain;
return -1; if (damage >= 0)
{
damage = target->TakeSpecialDamage(inflictor, source, damage, mod);
}
// '<0' is handled below. This only handles the case where damage gets reduced to 0.
if (damage == 0 && olddam > 0)
{
{ // Still allow FORCEPAIN
if (forcedPain)
{
goto dopain;
}
else if (fakedPain)
{
goto fakepain;
}
return -1;
}
} }
} }
if (damage > 0) if (target->flags5 & MF5_NODAMAGE)
damage = target->TakeSpecialDamage (inflictor, source, damage, mod); {
damage = 0;
}
} }
if (damage == -1 && target->player == NULL) //Make sure it's not a player, the pain has yet to be processed with cheats. if (damage < 0)
{ {
if (fakedPain) // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain.
goto fakepain;
return -1; return -1;
} }
// Push the target unless the source's weapon's kickback is 0. // Push the target unless the source's weapon's kickback is 0.
// (i.e. Gauntlets/Chainsaw) // (i.e. Gauntlets/Chainsaw)
if (!(plrDontThrust) && inflictor && inflictor != target // [RH] Not if hurting own self if (!plrDontThrust && inflictor && inflictor != target // [RH] Not if hurting own self
&& !(target->flags & MF_NOCLIP) && !(target->flags & MF_NOCLIP)
&& !(inflictor->flags2 & MF2_NODMGTHRUST) && !(inflictor->flags2 & MF2_NODMGTHRUST)
&& !(flags & DMG_THRUSTLESS) && !(flags & DMG_THRUSTLESS)
@ -1182,10 +1174,11 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust); fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust);
} }
thrust = FLOAT2FIXED(fltthrust); thrust = FLOAT2FIXED(fltthrust);
// Don't apply ultra-small damage thrust.
if (thrust < FRACUNIT / 100) // Don't apply ultra-small damage thrust
thrust = 0; if (thrust < FRACUNIT/100) thrust = 0;
// make fall forwards sometimes // make fall forwards sometimes
if ((damage < 40) && (damage > target->health) if ((damage < 40) && (damage > target->health)
@ -1194,7 +1187,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// [RH] But only if not too fast and not flying // [RH] But only if not too fast and not flying
&& thrust < 10*FRACUNIT && thrust < 10*FRACUNIT
&& !(target->flags & MF_NOGRAVITY) && !(target->flags & MF_NOGRAVITY)
&& (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL))) && (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL))
)
{ {
ang += ANG180; ang += ANG180;
thrust *= 4; thrust *= 4;
@ -1230,8 +1224,22 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
if (damage < TELEFRAG_DAMAGE) if (damage < TELEFRAG_DAMAGE)
{ // Still allow telefragging :-( { // Still allow telefragging :-(
damage = (int)((float)damage * level.teamdamage); damage = (int)((float)damage * level.teamdamage);
if (damage <= 0) if (damage < 0)
{
return damage; return damage;
}
else if (damage == 0)
{
if (forcedPain)
{
goto dopain;
}
else if (fakedPain)
{
goto fakepain;
}
return -1;
}
} }
} }
@ -1268,7 +1276,6 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)))) else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))))
{ {
invulpain = true; invulpain = true;
fakeDamage = damage;
goto fakepain; goto fakepain;
} }
else else
@ -1325,7 +1332,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// but telefragging should still do enough damage to kill the player) // but telefragging should still do enough damage to kill the player)
// Ignore players that are already dead. // Ignore players that are already dead.
// [MC]Buddha2 absorbs telefrag damage, and anything else thrown their way. // [MC]Buddha2 absorbs telefrag damage, and anything else thrown their way.
if (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && (damage < TELEFRAG_DAMAGE))) && (player->playerstate != PST_DEAD)) if (!(flags & DMG_FORCED) && (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && (damage < TELEFRAG_DAMAGE))) && (player->playerstate != PST_DEAD)))
{ {
// If this is a voodoo doll we need to handle the real player as well. // If this is a voodoo doll we need to handle the real player as well.
player->mo->health = target->health = player->health = 1; player->mo->health = target->health = player->health = 1;
@ -1390,7 +1397,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
if (target->health <= 0) if (target->health <= 0)
{ {
//[MC]Buddha flag for monsters. //[MC]Buddha flag for monsters.
if ((target->flags7 & MF7_BUDDHA) && (damage < TELEFRAG_DAMAGE) && ((inflictor == NULL || !(inflictor->flags3 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA))) if (!(flags & DMG_FORCED) && ((target->flags7 & MF7_BUDDHA) && (damage < TELEFRAG_DAMAGE) && ((inflictor == NULL || !(inflictor->flags7 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA))))
{ //FOILBUDDHA or Telefrag damage must kill it. { //FOILBUDDHA or Telefrag damage must kill it.
target->health = 1; target->health = 1;
} }
@ -1451,15 +1458,6 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
fakepain: //Needed so we can skip the rest of the above, but still obey the original rules. fakepain: //Needed so we can skip the rest of the above, but still obey the original rules.
//CAUSEPAIN can always attempt to trigger the chances of pain.
//ALLOWPAIN can do the same, only if the (unfiltered aka fake) damage is greater than 0.
if ((((target->flags7 & MF7_ALLOWPAIN) && (fakeDamage > 0))
|| ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))))
{
holdDamage = damage; //Store the modified damage away after factors are taken into account.
damage = fakeDamage; //Retrieve the original damage.
}
if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) &&
(target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY))
{ {
@ -1474,7 +1472,7 @@ fakepain: //Needed so we can skip the rest of the above, but still obey the orig
} }
} }
if ((((damage >= target->PainThreshold)) && (pr_damagemobj() < painchance)) if (((damage >= target->PainThreshold) && (pr_damagemobj() < painchance))
|| (inflictor != NULL && (inflictor->flags6 & MF6_FORCEPAIN))) || (inflictor != NULL && (inflictor->flags6 & MF6_FORCEPAIN)))
{ {
dopain: dopain:
@ -1555,10 +1553,6 @@ dopain:
{ {
return -1; //NOW we return -1! return -1; //NOW we return -1!
} }
else if (fakedPain)
{
return holdDamage; //This is the calculated damage after all is said and done.
}
return damage; return damage;
} }

View file

@ -189,9 +189,8 @@ DFlicker::DFlicker (sector_t *sector, int upper, int lower)
void EV_StartLightFlickering (int tag, int upper, int lower) void EV_StartLightFlickering (int tag, int upper, int lower)
{ {
int secnum; int secnum;
FSectorTagIterator it(tag);
secnum = -1; while ((secnum = it.Next()) >= 0)
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0)
{ {
new DFlicker (&sectors[secnum], upper, lower); new DFlicker (&sectors[secnum], upper, lower);
} }
@ -359,9 +358,8 @@ DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync)
void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics) void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics)
{ {
int secnum; int secnum;
FSectorTagIterator it(tag);
secnum = -1; while ((secnum = it.Next()) >= 0)
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
if (sec->lightingdata) if (sec->lightingdata)
@ -374,9 +372,8 @@ void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics)
void EV_StartLightStrobing (int tag, int utics, int ltics) void EV_StartLightStrobing (int tag, int utics, int ltics)
{ {
int secnum; int secnum;
FSectorTagIterator it(tag);
secnum = -1; while ((secnum = it.Next()) >= 0)
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
if (sec->lightingdata) if (sec->lightingdata)
@ -396,16 +393,14 @@ void EV_StartLightStrobing (int tag, int utics, int ltics)
void EV_TurnTagLightsOff (int tag) void EV_TurnTagLightsOff (int tag)
{ {
int i;
int secnum; int secnum;
FSectorTagIterator it(tag);
// [RH] Don't do a linear search while ((secnum = it.Next()) >= 0)
for (secnum = -1; (secnum = P_FindSectorFromTag (tag, secnum)) >= 0; )
{ {
sector_t *sector = sectors + secnum; sector_t *sector = sectors + secnum;
int min = sector->lightlevel; int min = sector->lightlevel;
for (i = 0; i < sector->linecount; i++) for (int i = 0; i < sector->linecount; i++)
{ {
sector_t *tsec = getNextSector (sector->lines[i],sector); sector_t *tsec = getNextSector (sector->lines[i],sector);
if (!tsec) if (!tsec)
@ -427,10 +422,9 @@ void EV_TurnTagLightsOff (int tag)
void EV_LightTurnOn (int tag, int bright) void EV_LightTurnOn (int tag, int bright)
{ {
int secnum = -1; int secnum;
FSectorTagIterator it(tag);
// [RH] Don't do a linear search while ((secnum = it.Next()) >= 0)
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sector_t *sector = sectors + secnum; sector_t *sector = sectors + secnum;
int tbright = bright; //jff 5/17/98 search for maximum PER sector int tbright = bright; //jff 5/17/98 search for maximum PER sector
@ -480,15 +474,14 @@ void EV_LightTurnOn (int tag, int bright)
void EV_LightTurnOnPartway (int tag, fixed_t frac) void EV_LightTurnOnPartway (int tag, fixed_t frac)
{ {
int i;
frac = clamp<fixed_t> (frac, 0, FRACUNIT); frac = clamp<fixed_t> (frac, 0, FRACUNIT);
// Search all sectors for ones with same tag as activating line // Search all sectors for ones with same tag as activating line
i = -1; int secnum;
while ((i = P_FindSectorFromTag (tag, i)) >= 0) FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{ {
sector_t *temp, *sector = sectors + i; sector_t *temp, *sector = &sectors[secnum];
int j, bright = 0, min = sector->lightlevel; int j, bright = 0, min = sector->lightlevel;
for (j = 0; j < sector->linecount; ++j) for (j = 0; j < sector->linecount; ++j)
@ -520,9 +513,9 @@ void EV_LightTurnOnPartway (int tag, fixed_t frac)
void EV_LightChange (int tag, int value) void EV_LightChange (int tag, int value)
{ {
int secnum = -1; int secnum;
FSectorTagIterator it(tag);
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) while ((secnum = it.Next()) >= 0)
{ {
sectors[secnum].SetLightLevel(sectors[secnum].lightlevel + value); sectors[secnum].SetLightLevel(sectors[secnum].lightlevel + value);
} }
@ -681,8 +674,8 @@ void EV_StartLightGlowing (int tag, int upper, int lower, int tics)
lower = temp; lower = temp;
} }
secnum = -1; FSectorTagIterator it(tag);
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0) while ((secnum = it.Next()) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
if (sec->lightingdata) if (sec->lightingdata)
@ -701,9 +694,8 @@ void EV_StartLightGlowing (int tag, int upper, int lower, int tics)
void EV_StartLightFading (int tag, int value, int tics) void EV_StartLightFading (int tag, int value, int tics)
{ {
int secnum; int secnum;
FSectorTagIterator it(tag);
secnum = -1; while ((secnum = it.Next()) >= 0)
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
if (sec->lightingdata) if (sec->lightingdata)
@ -846,7 +838,7 @@ void EV_StopLightEffect (int tag)
while ((effect = iterator.Next()) != NULL) while ((effect = iterator.Next()) != NULL)
{ {
if (effect->GetSector()->tag == tag) if (tagManager.SectorHasTag(effect->GetSector(), tag))
{ {
effect->Destroy(); 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--) for(int i = scrollplane.Sectors.Size()-1; i>=0; i--)
{ {
if (scrollplane.Sectors[i].Sector->tag == tag) if (tagManager.SectorHasTag(scrollplane.Sectors[i].Sector, tag))
{ {
scrollplane.Sectors.Delete(i); scrollplane.Sectors.Delete(i);
} }
@ -316,7 +316,9 @@ bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype)
if (movetype > 0) if (movetype > 0)
{ {
for(int sec = -1; (sec = P_FindSectorFromTag(tag, sec)) >= 0; ) int sec;
FSectorTagIterator itr(tag);
while ((sec = itr.Next()) >= 0)
{ {
// Don't attach to self! // Don't attach to self!
if (control != &sectors[sec]) if (control != &sectors[sec])
@ -346,7 +348,9 @@ void P_AddSectorLinksByID(sector_t *control, int id, INTBOOL ceiling)
{ {
extsector_t::linked::plane &scrollplane = ceiling? control->e->Linked.Ceiling : control->e->Linked.Floor; extsector_t::linked::plane &scrollplane = ceiling? control->e->Linked.Ceiling : control->e->Linked.Floor;
for(int line = -1; (line = P_FindLineFromID(id, line)) >= 0; ) FLineIdIterator itr(id);
int line;
while ((line = itr.Next()) >= 0)
{ {
line_t *ld = &lines[line]; line_t *ld = &lines[line];

View file

@ -1266,7 +1266,7 @@ FUNC(LS_Thing_Destroy)
while (actor) while (actor)
{ {
AActor *temp = iterator.Next (); AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && actor->Sector->tag == arg2) if (actor->flags & MF_SHOOTABLE && tagManager.SectorHasTag(actor->Sector, arg2))
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None); P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp; actor = temp;
} }
@ -1279,7 +1279,7 @@ FUNC(LS_Thing_Destroy)
while (actor) while (actor)
{ {
AActor *temp = iterator.Next (); AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || actor->Sector->tag == 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); P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp; actor = temp;
} }
@ -1914,9 +1914,9 @@ FUNC(LS_Sector_ChangeSound)
if (!arg0) if (!arg0)
return false; return false;
secNum = -1;
rtn = false; rtn = false;
while ((secNum = P_FindSectorFromTag (arg0, secNum)) >= 0) FSectorTagIterator itr(arg0);
while ((secNum = itr.Next()) >= 0)
{ {
sectors[secNum].seqType = arg1; sectors[secNum].seqType = arg1;
rtn = true; rtn = true;
@ -1933,9 +1933,9 @@ FUNC(LS_Sector_ChangeFlags)
if (!arg0) if (!arg0)
return false; return false;
secNum = -1;
rtn = false; rtn = false;
while ((secNum = P_FindSectorFromTag (arg0, secNum)) >= 0) FSectorTagIterator itr(arg0);
while ((secNum = itr.Next()) >= 0)
{ {
sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2; sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2;
rtn = true; rtn = true;
@ -1969,10 +1969,11 @@ void AdjustPusher (int tag, int magnitude, int angle, DPusher::EPusher type)
} }
size_t numcollected = Collection.Size (); size_t numcollected = Collection.Size ();
int secnum = -1; int secnum;
// Now create pushers for any sectors that don't already have them. // Now create pushers for any sectors that don't already have them.
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator itr(tag);
while ((secnum = itr.Next()) >= 0)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < numcollected; i++) for (i = 0; i < numcollected; i++)
@ -2020,9 +2021,9 @@ FUNC(LS_Sector_SetTranslucent)
{ {
if (arg0 != 0) if (arg0 != 0)
{ {
int secnum = -1; int secnum;
FSectorTagIterator itr(arg0);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetAlpha(arg1, Scale(arg2, OPAQUE, 255)); sectors[secnum].SetAlpha(arg1, Scale(arg2, OPAQUE, 255));
sectors[secnum].ChangeFlags(arg1, ~PLANEF_ADDITIVE, arg3? PLANEF_ADDITIVE:0); sectors[secnum].ChangeFlags(arg1, ~PLANEF_ADDITIVE, arg3? PLANEF_ADDITIVE:0);
@ -2037,7 +2038,7 @@ FUNC(LS_Sector_SetLink)
{ {
if (arg0 != 0) // control tag == 0 is for static initialization and must not be handled here if (arg0 != 0) // control tag == 0 is for static initialization and must not be handled here
{ {
int control = P_FindSectorFromTag(arg0, -1); int control = P_FindFirstSectorFromTag(arg0);
if (control >= 0) if (control >= 0)
{ {
return P_AddSectorLinks(&sectors[control], arg1, arg2, arg3); return P_AddSectorLinks(&sectors[control], arg1, arg2, arg3);
@ -2062,7 +2063,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int
{ {
int wallnum = scroller->GetWallNum (); int wallnum = scroller->GetWallNum ();
if (wallnum >= 0 && sides[wallnum].linedef->id == id && if (wallnum >= 0 && tagManager.LineHasID(sides[wallnum].linedef, id) &&
int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum && int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum &&
Where == scroller->GetScrollParts()) Where == scroller->GetScrollParts())
{ {
@ -2081,7 +2082,7 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int
while ( (collect.Obj = iterator.Next ()) ) while ( (collect.Obj = iterator.Next ()) )
{ {
if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 && if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
sides[collect.RefNum].linedef->id == id && tagManager.LineHasID(sides[collect.RefNum].linedef, id) &&
int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum && int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum &&
Where == ((DScroller *)collect.Obj)->GetScrollParts()) Where == ((DScroller *)collect.Obj)->GetScrollParts())
{ {
@ -2092,10 +2093,11 @@ static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int
} }
size_t numcollected = Collection.Size (); size_t numcollected = Collection.Size ();
int linenum = -1; int linenum;
// Now create scrollers for any walls that don't already have them. // Now create scrollers for any walls that don't already have them.
while ((linenum = P_FindLineFromID (id, linenum)) >= 0) FLineIdIterator itr(id);
while ((linenum = itr.Next()) >= 0)
{ {
if (lines[linenum].sidedef[sidechoice] != NULL) if (lines[linenum].sidedef[sidechoice] != NULL)
{ {
@ -2167,7 +2169,7 @@ static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed
{ {
if (scroller->IsType (type)) if (scroller->IsType (type))
{ {
if (sectors[scroller->GetAffectee ()].tag == tag) if (tagManager.SectorHasTag(scroller->GetAffectee (), tag))
{ {
i++; i++;
scroller->SetRate (dx, dy); scroller->SetRate (dx, dy);
@ -2181,7 +2183,8 @@ static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed
} }
// Need to create scrollers for the sector(s) // Need to create scrollers for the sector(s)
for (i = -1; (i = P_FindSectorFromTag (tag, i)) >= 0; ) FSectorTagIterator itr(tag);
while ((i = itr.Next()) >= 0)
{ {
new DScroller (type, dx, dy, -1, i, 0); new DScroller (type, dx, dy, -1, i, 0);
} }
@ -2240,8 +2243,10 @@ FUNC(LS_Sector_SetDamage)
// problems by adding an unwanted constructor. // problems by adding an unwanted constructor.
// Since it doesn't really matter whether the type is translated // Since it doesn't really matter whether the type is translated
// here or in P_PlayerInSpecialSector I think it's the best solution. // here or in P_PlayerInSpecialSector I think it's the best solution.
int secnum = -1; FSectorTagIterator itr(arg0);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) { int secnum;
while ((secnum = itr.Next()) >= 0)
{
sectors[secnum].damage = arg1; sectors[secnum].damage = arg1;
sectors[secnum].mod = arg2; sectors[secnum].mod = arg2;
} }
@ -2251,14 +2256,15 @@ FUNC(LS_Sector_SetDamage)
FUNC(LS_Sector_SetGravity) FUNC(LS_Sector_SetGravity)
// Sector_SetGravity (tag, intpart, fracpart) // Sector_SetGravity (tag, intpart, fracpart)
{ {
int secnum = -1;
float gravity; float gravity;
if (arg2 > 99) if (arg2 > 99)
arg2 = 99; arg2 = 99;
gravity = (float)arg1 + (float)arg2 * 0.01f; gravity = (float)arg1 + (float)arg2 * 0.01f;
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
sectors[secnum].gravity = gravity; sectors[secnum].gravity = gravity;
return true; return true;
@ -2267,9 +2273,9 @@ FUNC(LS_Sector_SetGravity)
FUNC(LS_Sector_SetColor) FUNC(LS_Sector_SetColor)
// Sector_SetColor (tag, r, g, b, desaturate) // Sector_SetColor (tag, r, g, b, desaturate)
{ {
int secnum = -1; FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetColor(arg1, arg2, arg3, arg4); sectors[secnum].SetColor(arg1, arg2, arg3, arg4);
} }
@ -2280,9 +2286,9 @@ FUNC(LS_Sector_SetColor)
FUNC(LS_Sector_SetFade) FUNC(LS_Sector_SetFade)
// Sector_SetFade (tag, r, g, b) // Sector_SetFade (tag, r, g, b)
{ {
int secnum = -1; FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetFade(arg1, arg2, arg3); sectors[secnum].SetFade(arg1, arg2, arg3);
} }
@ -2292,11 +2298,12 @@ FUNC(LS_Sector_SetFade)
FUNC(LS_Sector_SetCeilingPanning) FUNC(LS_Sector_SetCeilingPanning)
// Sector_SetCeilingPanning (tag, x-int, x-frac, y-int, y-frac) // Sector_SetCeilingPanning (tag, x-int, x-frac, y-int, y-frac)
{ {
int secnum = -1;
fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100); fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100); fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetXOffset(sector_t::ceiling, xofs); sectors[secnum].SetXOffset(sector_t::ceiling, xofs);
sectors[secnum].SetYOffset(sector_t::ceiling, yofs); sectors[secnum].SetYOffset(sector_t::ceiling, yofs);
@ -2307,11 +2314,12 @@ FUNC(LS_Sector_SetCeilingPanning)
FUNC(LS_Sector_SetFloorPanning) FUNC(LS_Sector_SetFloorPanning)
// Sector_SetFloorPanning (tag, x-int, x-frac, y-int, y-frac) // Sector_SetFloorPanning (tag, x-int, x-frac, y-int, y-frac)
{ {
int secnum = -1;
fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100); fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100); fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetXOffset(sector_t::floor, xofs); sectors[secnum].SetXOffset(sector_t::floor, xofs);
sectors[secnum].SetYOffset(sector_t::floor, yofs); sectors[secnum].SetYOffset(sector_t::floor, yofs);
@ -2322,7 +2330,6 @@ FUNC(LS_Sector_SetFloorPanning)
FUNC(LS_Sector_SetFloorScale) FUNC(LS_Sector_SetFloorScale)
// Sector_SetFloorScale (tag, x-int, x-frac, y-int, y-frac) // Sector_SetFloorScale (tag, x-int, x-frac, y-int, y-frac)
{ {
int secnum = -1;
fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100); fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100); fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);
@ -2331,7 +2338,9 @@ FUNC(LS_Sector_SetFloorScale)
if (yscale) if (yscale)
yscale = FixedDiv (FRACUNIT, yscale); yscale = FixedDiv (FRACUNIT, yscale);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
if (xscale) if (xscale)
sectors[secnum].SetXScale(sector_t::floor, xscale); sectors[secnum].SetXScale(sector_t::floor, xscale);
@ -2344,7 +2353,6 @@ FUNC(LS_Sector_SetFloorScale)
FUNC(LS_Sector_SetCeilingScale) FUNC(LS_Sector_SetCeilingScale)
// Sector_SetCeilingScale (tag, x-int, x-frac, y-int, y-frac) // Sector_SetCeilingScale (tag, x-int, x-frac, y-int, y-frac)
{ {
int secnum = -1;
fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100); fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100); fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);
@ -2353,7 +2361,9 @@ FUNC(LS_Sector_SetCeilingScale)
if (yscale) if (yscale)
yscale = FixedDiv (FRACUNIT, yscale); yscale = FixedDiv (FRACUNIT, yscale);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
if (xscale) if (xscale)
sectors[secnum].SetXScale(sector_t::ceiling, xscale); sectors[secnum].SetXScale(sector_t::ceiling, xscale);
@ -2366,14 +2376,14 @@ FUNC(LS_Sector_SetCeilingScale)
FUNC(LS_Sector_SetFloorScale2) FUNC(LS_Sector_SetFloorScale2)
// Sector_SetFloorScale2 (tag, x-factor, y-factor) // Sector_SetFloorScale2 (tag, x-factor, y-factor)
{ {
int secnum = -1;
if (arg1) if (arg1)
arg1 = FixedDiv (FRACUNIT, arg1); arg1 = FixedDiv (FRACUNIT, arg1);
if (arg2) if (arg2)
arg2 = FixedDiv (FRACUNIT, arg2); arg2 = FixedDiv (FRACUNIT, arg2);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
if (arg1) if (arg1)
sectors[secnum].SetXScale(sector_t::floor, arg1); sectors[secnum].SetXScale(sector_t::floor, arg1);
@ -2386,14 +2396,14 @@ FUNC(LS_Sector_SetFloorScale2)
FUNC(LS_Sector_SetCeilingScale2) FUNC(LS_Sector_SetCeilingScale2)
// Sector_SetFloorScale2 (tag, x-factor, y-factor) // Sector_SetFloorScale2 (tag, x-factor, y-factor)
{ {
int secnum = -1;
if (arg1) if (arg1)
arg1 = FixedDiv (FRACUNIT, arg1); arg1 = FixedDiv (FRACUNIT, arg1);
if (arg2) if (arg2)
arg2 = FixedDiv (FRACUNIT, arg2); arg2 = FixedDiv (FRACUNIT, arg2);
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
if (arg1) if (arg1)
sectors[secnum].SetXScale(sector_t::ceiling, arg1); sectors[secnum].SetXScale(sector_t::ceiling, arg1);
@ -2406,11 +2416,12 @@ FUNC(LS_Sector_SetCeilingScale2)
FUNC(LS_Sector_SetRotation) FUNC(LS_Sector_SetRotation)
// Sector_SetRotation (tag, floor-angle, ceiling-angle) // Sector_SetRotation (tag, floor-angle, ceiling-angle)
{ {
int secnum = -1;
angle_t ceiling = arg2 * ANGLE_1; angle_t ceiling = arg2 * ANGLE_1;
angle_t floor = arg1 * ANGLE_1; angle_t floor = arg1 * ANGLE_1;
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
sectors[secnum].SetAngle(sector_t::floor, floor); sectors[secnum].SetAngle(sector_t::floor, floor);
sectors[secnum].SetAngle(sector_t::ceiling, ceiling); sectors[secnum].SetAngle(sector_t::ceiling, ceiling);
@ -2421,30 +2432,28 @@ FUNC(LS_Sector_SetRotation)
FUNC(LS_Line_AlignCeiling) FUNC(LS_Line_AlignCeiling)
// Line_AlignCeiling (lineid, side) // Line_AlignCeiling (lineid, side)
{ {
int line = P_FindLineFromID (arg0, -1);
bool ret = 0; bool ret = 0;
if (line < 0) FLineIdIterator itr(arg0);
I_Error ("Sector_AlignCeiling: Lineid %d is undefined", arg0); int line;
do while ((line = itr.Next()) >= 0)
{ {
ret |= P_AlignFlat (line, !!arg1, 1); ret |= P_AlignFlat (line, !!arg1, 1);
} while ( (line = P_FindLineFromID (arg0, line)) >= 0); }
return ret; return ret;
} }
FUNC(LS_Line_AlignFloor) FUNC(LS_Line_AlignFloor)
// Line_AlignFloor (lineid, side) // Line_AlignFloor (lineid, side)
{ {
int line = P_FindLineFromID (arg0, -1);
bool ret = 0; bool ret = 0;
if (line < 0) FLineIdIterator itr(arg0);
I_Error ("Sector_AlignFloor: Lineid %d is undefined", arg0); int line;
do while ((line = itr.Next()) >= 0)
{ {
ret |= P_AlignFlat (line, !!arg1, 0); ret |= P_AlignFlat (line, !!arg1, 0);
} while ( (line = P_FindLineFromID (arg0, line)) >= 0); }
return ret; return ret;
} }
@ -2456,7 +2465,9 @@ FUNC(LS_Line_SetTextureOffset)
if (arg0 == 0 || arg3 < 0 || arg3 > 1) if (arg0 == 0 || arg3 < 0 || arg3 > 1)
return false; return false;
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; ) FLineIdIterator itr(arg0);
int line;
while ((line = itr.Next()) >= 0)
{ {
side_t *side = lines[line].sidedef[arg3]; side_t *side = lines[line].sidedef[arg3];
if (side != NULL) if (side != NULL)
@ -2507,7 +2518,9 @@ FUNC(LS_Line_SetTextureScale)
if (arg0 == 0 || arg3 < 0 || arg3 > 1) if (arg0 == 0 || arg3 < 0 || arg3 > 1)
return false; return false;
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; ) FLineIdIterator itr(arg0);
int line;
while ((line = itr.Next()) >= 0)
{ {
side_t *side = lines[line].sidedef[arg3]; side_t *side = lines[line].sidedef[arg3];
if (side != NULL) if (side != NULL)
@ -2578,7 +2591,9 @@ FUNC(LS_Line_SetBlocking)
if (arg2 & 1) clearflags |= flagtrans[i]; if (arg2 & 1) clearflags |= flagtrans[i];
} }
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; ) FLineIdIterator itr(arg0);
int line;
while ((line = itr.Next()) >= 0)
{ {
lines[line].flags = (lines[line].flags & ~clearflags) | setflags; lines[line].flags = (lines[line].flags & ~clearflags) | setflags;
} }
@ -2871,8 +2886,9 @@ FUNC(LS_SetPlayerProperty)
FUNC(LS_TranslucentLine) FUNC(LS_TranslucentLine)
// TranslucentLine (id, amount, type) // TranslucentLine (id, amount, type)
{ {
int linenum = -1; FLineIdIterator itr(arg0);
while ((linenum = P_FindLineFromID (arg0, linenum)) >= 0) int linenum;
while ((linenum = itr.Next()) >= 0)
{ {
lines[linenum].Alpha = Scale(clamp(arg1, 0, 255), FRACUNIT, 255); lines[linenum].Alpha = Scale(clamp(arg1, 0, 255), FRACUNIT, 255);
if (arg2 == 0) if (arg2 == 0)
@ -2997,10 +3013,11 @@ FUNC(LS_ForceField)
FUNC(LS_ClearForceField) FUNC(LS_ClearForceField)
// ClearForceField (tag) // ClearForceField (tag)
{ {
int secnum = -1;
bool rtn = false; bool rtn = false;
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) FSectorTagIterator itr(arg0);
int secnum;
while ((secnum = itr.Next()) >= 0)
{ {
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
rtn = true; rtn = true;

View file

@ -160,7 +160,8 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh
// //
// [RH] P_THINGS // [RH] P_THINGS
// //
extern TMap<int, const PClass *> SpawnableThings; extern FClassMap SpawnableThings;
extern FClassMap StrifeTypes;
bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid);
bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle,
@ -174,6 +175,7 @@ void P_RemoveThing(AActor * actor);
bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_Raise(AActor *thing, AActor *raiser);
bool P_Thing_CanRaise(AActor *thing); bool P_Thing_CanRaise(AActor *thing);
const PClass *P_GetSpawnableType(int spawnnum); const PClass *P_GetSpawnableType(int spawnnum);
void InitSpawnablesFromMapinfo();
// //
// P_MAPUTL // P_MAPUTL
@ -472,7 +474,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing); 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); 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_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 enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags
{ {
@ -591,19 +593,6 @@ struct polyspawns_t
short type; short type;
}; };
enum
{
PO_HEX_ANCHOR_TYPE = 3000,
PO_HEX_SPAWN_TYPE,
PO_HEX_SPAWNCRUSH_TYPE,
// [RH] Thing numbers that don't conflict with Doom things
PO_ANCHOR_TYPE = 9300,
PO_SPAWN_TYPE,
PO_SPAWNCRUSH_TYPE,
PO_SPAWNHURT_TYPE
};
extern int po_NumPolyobjs; extern int po_NumPolyobjs;
extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn

View file

@ -1034,7 +1034,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// Both things overlap in x or y direction // Both things overlap in x or y direction
bool unblocking = false; bool unblocking = false;
if (tm.FromPMove) if (tm.FromPMove || tm.thing->player != NULL)
{ {
// Both actors already overlap. To prevent them from remaining stuck allow the move if it // Both actors already overlap. To prevent them from remaining stuck allow the move if it
// takes them further apart or the move does not change the position (when called from P_ChangeSector.) // takes them further apart or the move does not change the position (when called from P_ChangeSector.)
@ -1288,7 +1288,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// Do damage // Do damage
damage = tm.thing->GetMissileDamage((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); damage = tm.thing->GetMissileDamage((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1);
if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN)) if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN) || (tm.thing->flags7 & MF7_CAUSEPAIN))
{ {
int newdam = P_DamageMobj(thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); int newdam = P_DamageMobj(thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType);
if (damage > 0) if (damage > 0)
@ -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; fixed_t vx, vy, vz;
angle_t angle, pitch; angle_t angle, pitch;
@ -4243,13 +4243,16 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor); P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor);
} }
if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN)
{
P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType);
}
int dmgFlagPass = DMG_INFLICTOR_IS_PUFF; int dmgFlagPass = DMG_INFLICTOR_IS_PUFF;
dmgFlagPass += (puffDefaults->flags3 & MF3_FOILINVUL) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul check wasn't working. if (puffDefaults != NULL) // is this even possible?
dmgFlagPass += (puffDefaults->flags7 & MF7_FOILBUDDHA) ? DMG_FOILBUDDHA : 0; {
if (puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN)
{
P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType);
}
if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL;
if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA;
}
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass); int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass);
if (bleed) if (bleed)
@ -4289,7 +4292,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
end.X = FIXED2FLOAT(trace.X); end.X = FIXED2FLOAT(trace.X);
end.Y = FIXED2FLOAT(trace.Y); end.Y = FIXED2FLOAT(trace.Y);
end.Z = FIXED2FLOAT(trace.Z); 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);
} }
//========================================================================== //==========================================================================
@ -4787,7 +4790,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT) / (double)FRACUNIT; points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT) / (double)FRACUNIT;
// points and bombdamage should be the same sign // points and bombdamage should be the same sign
if (((bombspot->flags7 & MF7_CAUSEPAIN) || (points * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) if (((points * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
double velz; double velz;
double thrust; double thrust;

View file

@ -384,11 +384,6 @@ void AActor::Serialize (FArchive &arc)
} }
} }
void FMapThing::Serialize (FArchive &arc)
{
arc << thingid << x << y << z << angle << type << flags << special
<< args[0] << args[1] << args[2] << args[3] << args[4];
}
AActor::AActor () throw() AActor::AActor () throw()
{ {
@ -3442,7 +3437,7 @@ void AActor::Tick ()
} }
else if (scrolltype == Scroll_StrifeCurrent) else if (scrolltype == Scroll_StrifeCurrent)
{ // Strife scroll special { // Strife scroll special
int anglespeed = sec->tag - 100; int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t carryspeed = DivScale32 (anglespeed % 10, 16*CARRYFACTOR); fixed_t carryspeed = DivScale32 (anglespeed % 10, 16*CARRYFACTOR);
angle_t fineangle = (anglespeed / 10) << (32-3); angle_t fineangle = (anglespeed / 10) << (32-3);
fineangle >>= ANGLETOFINESHIFT; fineangle >>= ANGLETOFINESHIFT;
@ -4480,7 +4475,8 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
p->mo->ResetAirSupply(false); p->mo->ResetAirSupply(false);
p->Uncrouch(); p->Uncrouch();
p->MinPitch = p->MaxPitch = 0; // will be filled in by PostBeginPlay()/netcode p->MinPitch = p->MaxPitch = 0; // will be filled in by PostBeginPlay()/netcode
p->MUSINFOactor = NULL;
p->MUSINFOtics = -1;
p->velx = p->vely = 0; // killough 10/98: initialize bobbing to 0. p->velx = p->vely = 0; // killough 10/98: initialize bobbing to 0.
@ -4596,70 +4592,83 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
AActor *mobj; AActor *mobj;
fixed_t x, y, z; fixed_t x, y, z;
if (mthing->type == 0 || mthing->type == -1) if (mthing->EdNum == 0 || mthing->EdNum == -1)
return NULL; return NULL;
// count deathmatch start positions // find which type to spawn
if (mthing->type == 11) FDoomEdEntry *mentry = mthing->info;
{
FPlayerStart start(mthing);
deathmatchstarts.Push(start);
return NULL;
}
// Convert Strife starts to Hexen-style starts if (mentry == NULL)
if (gameinfo.gametype == GAME_Strife && mthing->type >= 118 && mthing->type <= 127)
{ {
mthing->args[0] = mthing->type - 117; // [RH] Don't die if the map tries to spawn an unknown thing
mthing->type = 1; Printf ("Unknown type %i at (%i, %i)\n",
} mthing->EdNum,
mthing->x>>FRACBITS, mthing->y>>FRACBITS);
// [RH] Record polyobject-related things mentry = DoomEdMap.CheckKey(0);
if (gameinfo.gametype == GAME_Hexen) if (mentry == NULL) // we need a valid entry for the rest of this function so if we can't find a default, let's exit right away.
{
switch (mthing->type)
{ {
case PO_HEX_ANCHOR_TYPE: return NULL;
mthing->type = PO_ANCHOR_TYPE;
break;
case PO_HEX_SPAWN_TYPE:
mthing->type = PO_SPAWN_TYPE;
break;
case PO_HEX_SPAWNCRUSH_TYPE:
mthing->type = PO_SPAWNCRUSH_TYPE;
break;
} }
} }
if (mentry->Type == NULL && mentry->Special <= 0)
if (mthing->type == PO_ANCHOR_TYPE ||
mthing->type == PO_SPAWN_TYPE ||
mthing->type == PO_SPAWNCRUSH_TYPE ||
mthing->type == PO_SPAWNHURT_TYPE)
{ {
polyspawns_t *polyspawn = new polyspawns_t; // has been explicitly set to not spawning anything.
polyspawn->next = polyspawns;
polyspawn->x = mthing->x;
polyspawn->y = mthing->y;
polyspawn->angle = mthing->angle;
polyspawn->type = mthing->type;
polyspawns = polyspawn;
if (mthing->type != PO_ANCHOR_TYPE)
po_NumPolyobjs++;
return NULL; return NULL;
} }
// check for players specially // copy args to mapthing so that we have them in one place for the rest of this function
int pnum = -1; if (mentry->ArgsDefined)
if (mthing->type <= 4 && mthing->type > 0)
{ {
pnum = mthing->type - 1; if (mentry->Type!= NULL) mthing->special = mentry->Special;
memcpy(mthing->args, mentry->Args, sizeof(mthing->args));
} }
else
int pnum = -1;
if (mentry->Type == NULL)
{ {
if (mthing->type >= gameinfo.player5start && mthing->type < gameinfo.player5start + MAXPLAYERS - 4)
switch (mentry->Special)
{ {
pnum = mthing->type - gameinfo.player5start + 4; case SMT_DeathmatchStart:
{
// count deathmatch start positions
FPlayerStart start(mthing, 0);
deathmatchstarts.Push(start);
return NULL;
}
case SMT_PolyAnchor:
case SMT_PolySpawn:
case SMT_PolySpawnCrush:
case SMT_PolySpawnHurt:
{
polyspawns_t *polyspawn = new polyspawns_t;
polyspawn->next = polyspawns;
polyspawn->x = mthing->x;
polyspawn->y = mthing->y;
polyspawn->angle = mthing->angle;
polyspawn->type = mentry->Special;
polyspawns = polyspawn;
if (mentry->Special != SMT_PolyAnchor)
po_NumPolyobjs++;
return NULL;
}
case SMT_Player1Start:
case SMT_Player2Start:
case SMT_Player3Start:
case SMT_Player4Start:
case SMT_Player5Start:
case SMT_Player6Start:
case SMT_Player7Start:
case SMT_Player8Start:
pnum = mentry->Special - SMT_Player1Start;
break;
// Sound sequence override will be handled later
default:
break;
} }
} }
@ -4727,7 +4736,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
return NULL; return NULL;
// save spots for respawning in network games // save spots for respawning in network games
FPlayerStart start(mthing); FPlayerStart start(mthing, pnum+1);
playerstarts[pnum] = start; playerstarts[pnum] = start;
AllPlayerStarts.Push(start); AllPlayerStarts.Push(start);
if (!deathmatch && !(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS)) if (!deathmatch && !(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS))
@ -4738,20 +4747,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
} }
// [RH] sound sequence overriders // [RH] sound sequence overriders
if (mthing->type >= 1400 && mthing->type < 1410) if (mentry->Type == NULL && mentry->Special == SMT_SSeqOverride)
{ {
P_PointInSector (mthing->x, mthing->y)->seqType = mthing->type - 1400; int type = mentry->Args[0];
return NULL; if (type == 255) type = -1;
}
else if (mthing->type == 1411)
{
int type;
if (mthing->args[0] == 255)
type = -1;
else
type = mthing->args[0];
if (type > 63) if (type > 63)
{ {
Printf ("Sound sequence %d out of range\n", type); Printf ("Sound sequence %d out of range\n", type);
@ -4763,51 +4762,25 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
return NULL; return NULL;
} }
// [RH] Determine if it is an old ambient thing, and if so,
// map it to MT_AMBIENT with the proper parameter.
if (mthing->type >= 14001 && mthing->type <= 14064)
{
mthing->args[0] = mthing->type - 14000;
mthing->type = 14065;
}
else if (mthing->type >= 14101 && mthing->type <= 14164)
{
mthing->args[0] = mthing->type - 14100;
mthing->type = 14165;
}
// find which type to spawn
i = DoomEdMap.FindType (mthing->type);
if (i == NULL)
{
// [RH] Don't die if the map tries to spawn an unknown thing
Printf ("Unknown type %i at (%i, %i)\n",
mthing->type,
mthing->x>>FRACBITS, mthing->y>>FRACBITS);
i = PClass::FindClass("Unknown");
}
// [RH] If the thing's corresponding sprite has no frames, also map // [RH] If the thing's corresponding sprite has no frames, also map
// it to the unknown thing. // it to the unknown thing.
else // Handle decorate replacements explicitly here
// to check for missing frames in the replacement object.
i = mentry->Type->GetReplacement();
const AActor *defaults = GetDefaultByType (i);
if (defaults->SpawnState == NULL ||
sprites[defaults->SpawnState->sprite].numframes == 0)
{ {
// Handle decorate replacements explicitly here // We don't load mods for shareware games so we'll just ignore
// to check for missing frames in the replacement object. // missing actors. Heretic needs this since the shareware includes
i = i->GetReplacement(); // the retail weapons in Deathmatch.
if (gameinfo.flags & GI_SHAREWARE)
return NULL;
const AActor *defaults = GetDefaultByType (i); Printf ("%s at (%i, %i) has no frames\n",
if (defaults->SpawnState == NULL || i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS);
sprites[defaults->SpawnState->sprite].numframes == 0) i = PClass::FindClass("Unknown");
{
// We don't load mods for shareware games so we'll just ignore
// missing actors. Heretic needs this since the shareware includes
// the retail weapons in Deathmatch.
if (gameinfo.flags & GI_SHAREWARE)
return NULL;
Printf ("%s at (%i, %i) has no frames\n",
i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS);
i = PClass::FindClass("Unknown");
}
} }
const AActor *info = GetDefaultByType (i); const AActor *info = GetDefaultByType (i);
@ -4897,6 +4870,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT);
} }
// if the actor got args defined either in DECORATE or MAPINFO we must ignore the map's properties.
if (!(mobj->flags2 & MF2_ARGSDEFINED)) if (!(mobj->flags2 & MF2_ARGSDEFINED))
{ {
// [RH] Set the thing's special // [RH] Set the thing's special
@ -6158,11 +6132,6 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN
{ {
FState *death; FState *death;
if (flags5 & MF5_NODAMAGE)
{
return 0;
}
// If the actor does not have a corresponding death state, then it does not take damage. // If the actor does not have a corresponding death state, then it does not take damage.
// Note that DeathState matches every kind of damagetype, so an actor has that, it can // Note that DeathState matches every kind of damagetype, so an actor has that, it can
// be hurt with any type of damage. Exception: Massacre damage always succeeds, because // be hurt with any type of damage. Exception: Massacre damage always succeeds, because
@ -6240,11 +6209,11 @@ void AActor::Crash()
} }
} }
void AActor::SetIdle() void AActor::SetIdle(bool nofunction)
{ {
FState *idle = FindState (NAME_Idle); FState *idle = FindState (NAME_Idle);
if (idle == NULL) idle = SpawnState; if (idle == NULL) idle = SpawnState;
SetState(idle); SetState(idle, nofunction);
} }
int AActor::SpawnHealth() int AActor::SpawnHealth()
@ -6442,7 +6411,8 @@ void PrintMiscActorInfo(AActor *query)
} }
} }
static const char * renderstyles[]= {"None", "Normal", "Fuzzy", "SoulTrans", static const char * renderstyles[]= {"None", "Normal", "Fuzzy", "SoulTrans",
"OptFuzzy", "Stencil", "Translucent", "Add", "Shaded", "TranslucentStencil"}; "OptFuzzy", "Stencil", "Translucent", "Add", "Shaded", "TranslucentStencil",
"Shadow", "Subtract", "AddStencil", "AddShaded"};
Printf("%s @ %p has the following flags:\n flags: %x", query->GetTag(), query, query->flags); Printf("%s @ %p has the following flags:\n flags: %x", query->GetTag(), query, query->flags);
for (flagi = 0; flagi <= 31; flagi++) for (flagi = 0; flagi <= 31; flagi++)

View file

@ -220,20 +220,11 @@ bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
bool rtn = false; bool rtn = false;
// check if a manual trigger; if so do just the sector on the backside // check if a manual trigger; if so do just the sector on the backside
if (tag == 0) FSectorTagIterator itr(tag, line);
{ while ((secnum = itr.Next()) >= 0)
if (!line || !(sec = line->backsector))
return rtn;
secnum = (int)(sec-sectors);
goto manual_pillar;
}
secnum = -1;
while (tag && (secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
manual_pillar:
if (sec->PlaneMoving(sector_t::floor) || sec->PlaneMoving(sector_t::ceiling)) if (sec->PlaneMoving(sector_t::floor) || sec->PlaneMoving(sector_t::ceiling))
continue; continue;

View file

@ -233,42 +233,33 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height,
fixed_t newheight = 0; fixed_t newheight = 0;
vertex_t *spot; vertex_t *spot;
if (tag != 0)
{
// Activate all <type> plats that are in_stasis
switch (type)
{
case DPlat::platToggle:
rtn = true;
case DPlat::platPerpetualRaise:
P_ActivateInStasis (tag);
break;
default:
break;
}
}
// [RH] If tag is zero, use the sector on the back side // [RH] If tag is zero, use the sector on the back side
// of the activating line (if any). // of the activating line (if any).
if (!tag) FSectorTagIterator itr(tag, line);
{ while ((secnum = itr.Next()) >= 0)
if (!line || !(sec = line->backsector))
return false;
secnum = (int)(sec - sectors);
manual = true;
goto manual_plat;
}
// Activate all <type> plats that are in_stasis
switch (type)
{
case DPlat::platToggle:
rtn = true;
case DPlat::platPerpetualRaise:
P_ActivateInStasis (tag);
break;
default:
break;
}
secnum = -1;
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
manual_plat:
if (sec->PlaneMoving(sector_t::floor)) if (sec->PlaneMoving(sector_t::floor))
{ {
if (!manual) continue;
continue;
else
return false;
} }
// Find lowest & highest floors around sector // Find lowest & highest floors around sector
@ -406,8 +397,6 @@ manual_plat:
default: default:
break; break;
} }
if (manual)
return rtn;
} }
return rtn; return rtn;
} }

View file

@ -348,9 +348,13 @@ void P_SerializeWorld (FArchive &arc)
{ {
arc << sec->lightlevel; arc << sec->lightlevel;
} }
arc << sec->special arc << sec->special;
<< sec->tag if (SaveVersion < 4523)
<< sec->soundtraversed {
short tag;
arc << tag;
}
arc << sec->soundtraversed
<< sec->seqType << sec->seqType
<< sec->friction << sec->friction
<< sec->movefactor << sec->movefactor
@ -405,8 +409,13 @@ void P_SerializeWorld (FArchive &arc)
arc << li->flags arc << li->flags
<< li->activation << li->activation
<< li->special << li->special
<< li->Alpha << li->Alpha;
<< li->id;
if (SaveVersion < 4523)
{
int id;
arc << id;
}
if (P_IsACSSpecial(li->special)) if (P_IsACSSpecial(li->special))
{ {
P_SerializeACSScriptNumber(arc, li->args[0], false); P_SerializeACSScriptNumber(arc, li->args[0], false);

View file

@ -96,7 +96,6 @@ CVAR (Bool, gennodes, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG);
CVAR (Bool, genglnodes, false, CVAR_SERVERINFO); CVAR (Bool, genglnodes, false, CVAR_SERVERINFO);
CVAR (Bool, showloadtimes, false, 0); CVAR (Bool, showloadtimes, false, 0);
static void P_InitTagLists ();
static void P_Shutdown (); static void P_Shutdown ();
bool P_IsBuildMap(MapData *map); bool P_IsBuildMap(MapData *map);
@ -1514,7 +1513,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
else // [RH] Translate to new sector special else // [RH] Translate to new sector special
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special)); ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
ss->secretsector = !!(ss->special&SECRET_MASK); ss->secretsector = !!(ss->special&SECRET_MASK);
ss->tag = LittleShort(ms->tag); tagManager.AddSectorTag(i, LittleShort(ms->tag));
ss->thinglist = NULL; ss->thinglist = NULL;
ss->touching_thinglist = NULL; // phares 3/14/98 ss->touching_thinglist = NULL; // phares 3/14/98
ss->seqType = defSeqType; ss->seqType = defSeqType;
@ -1665,7 +1664,7 @@ AActor *SpawnMapThing(int index, FMapThing *mt, int position)
if (dumpspawnedthings) if (dumpspawnedthings)
{ {
Printf("%5d: (%5d, %5d, %5d), doomednum = %5d, flags = %04x, type = %s\n", Printf("%5d: (%5d, %5d, %5d), doomednum = %5d, flags = %04x, type = %s\n",
index, mt->x>>FRACBITS, mt->y>>FRACBITS, mt->z>>FRACBITS, mt->type, mt->flags, index, mt->x>>FRACBITS, mt->y>>FRACBITS, mt->z>>FRACBITS, mt->EdNum, mt->flags,
spawned? spawned->GetClass()->TypeName.GetChars() : "(none)"); spawned? spawned->GetClass()->TypeName.GetChars() : "(none)");
} }
T_AddSpawnedThing(spawned); T_AddSpawnedThing(spawned);
@ -1785,7 +1784,8 @@ void P_LoadThings (MapData * map)
mti[i].x = LittleShort(mt->x) << FRACBITS; mti[i].x = LittleShort(mt->x) << FRACBITS;
mti[i].y = LittleShort(mt->y) << FRACBITS; mti[i].y = LittleShort(mt->y) << FRACBITS;
mti[i].angle = LittleShort(mt->angle); mti[i].angle = LittleShort(mt->angle);
mti[i].type = LittleShort(mt->type); mti[i].EdNum = LittleShort(mt->type);
mti[i].info = DoomEdMap.CheckKey(mti[i].EdNum);
} }
delete [] mtp; delete [] mtp;
} }
@ -1825,7 +1825,8 @@ void P_LoadThings2 (MapData * map)
mti[i].y = LittleShort(mth[i].y)<<FRACBITS; mti[i].y = LittleShort(mth[i].y)<<FRACBITS;
mti[i].z = LittleShort(mth[i].z)<<FRACBITS; mti[i].z = LittleShort(mth[i].z)<<FRACBITS;
mti[i].angle = LittleShort(mth[i].angle); mti[i].angle = LittleShort(mth[i].angle);
mti[i].type = LittleShort(mth[i].type); mti[i].EdNum = LittleShort(mth[i].type);
mti[i].info = DoomEdMap.CheckKey(mti[i].EdNum);
mti[i].flags = LittleShort(mth[i].flags); mti[i].flags = LittleShort(mth[i].flags);
mti[i].special = mth[i].special; mti[i].special = mth[i].special;
for(int j=0;j<5;j++) mti[i].args[j] = mth[i].args[j]; for(int j=0;j<5;j++) mti[i].args[j] = mth[i].args[j];
@ -1906,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 // [RH] Set line id (as appropriate) here
// for Doom format maps this must be done in P_TranslateLineDef because // for Doom format maps this must be done in P_TranslateLineDef because
// the tag doesn't always go into the first arg. // the tag doesn't always go into the first arg.
if (level.maptype == MAPTYPE_HEXEN) if (level.maptype == MAPTYPE_HEXEN)
{ {
int setid = -1;
switch (ld->special) switch (ld->special)
{ {
case Line_SetIdentification: case Line_SetIdentification:
if (!(level.flags2 & LEVEL2_HEXENHACK)) if (!(level.flags2 & LEVEL2_HEXENHACK))
{ {
ld->id = ld->args[0] + 256 * ld->args[4]; setid = ld->args[0] + 256 * ld->args[4];
ld->flags |= ld->args[1]<<16; ld->flags |= ld->args[1]<<16;
} }
else else
{ {
ld->id = ld->args[0]; setid = ld->args[0];
} }
ld->special = 0; ld->special = 0;
break; break;
case TranslucentLine: case TranslucentLine:
ld->id = ld->args[0]; setid = ld->args[0];
ld->flags |= ld->args[3]<<16; ld->flags |= ld->args[3]<<16;
break; break;
case Teleport_Line: case Teleport_Line:
case Scroll_Texture_Model: case Scroll_Texture_Model:
ld->id = ld->args[0]; setid = ld->args[0];
break; break;
case Polyobj_StartLine: case Polyobj_StartLine:
ld->id = ld->args[3]; setid = ld->args[3];
break; break;
case Polyobj_ExplicitLine: case Polyobj_ExplicitLine:
ld->id = ld->args[4]; setid = ld->args[4];
break; break;
case Plane_Align: case Plane_Align:
ld->id = ld->args[2]; setid = ld->args[2];
break; break;
case Static_Init: case Static_Init:
if (ld->args[1] == Init_SectorLink) ld->id = ld->args[0]; if (ld->args[1] == Init_SectorLink) setid = ld->args[0];
break; break;
} }
if (setid != -1)
{
tagManager.AddLineID(i, setid);
}
} }
} }
@ -2036,7 +2042,7 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha)
{ {
for (j = 0; j < numlines; j++) for (j = 0; j < numlines; j++)
{ {
if (lines[j].id == ld->args[0]) if (tagManager.LineHasID(j, ld->args[0]))
{ {
lines[j].Alpha = alpha; lines[j].Alpha = alpha;
if (additive) if (additive)
@ -2138,17 +2144,16 @@ void P_LoadLineDefs (MapData * map)
mld = (maplinedef_t *)mldf; mld = (maplinedef_t *)mldf;
ld = lines; 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 ld->Alpha = FRACUNIT; // [RH] Opaque by default
// [RH] Translate old linedef special and flags to be // [RH] Translate old linedef special and flags to be
// compatible with the new format. // compatible with the new format.
P_TranslateLineDef (ld, mld); P_TranslateLineDef (ld, mld, i);
ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v1 = &vertexes[LittleShort(mld->v1)];
ld->v2 = &vertexes[LittleShort(mld->v2)]; ld->v2 = &vertexes[LittleShort(mld->v2)];
//ld->id = -1; ID has been assigned in P_TranslateLineDef
P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0])); P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0]));
P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1])); P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1]));
@ -2218,7 +2223,7 @@ void P_LoadLineDefs2 (MapData * map)
mld = (maplinedef2_t *)mldf; mld = (maplinedef2_t *)mldf;
ld = lines; ld = lines;
for (i = numlines; i > 0; i--, mld++, ld++) for (i = 0; i < numlines; i++, mld++, ld++)
{ {
int j; int j;
@ -2231,13 +2236,12 @@ void P_LoadLineDefs2 (MapData * map)
ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v1 = &vertexes[LittleShort(mld->v1)];
ld->v2 = &vertexes[LittleShort(mld->v2)]; ld->v2 = &vertexes[LittleShort(mld->v2)];
ld->Alpha = FRACUNIT; // [RH] Opaque by default ld->Alpha = FRACUNIT; // [RH] Opaque by default
ld->id = -1;
P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0])); P_SetSideNum (&ld->sidedef[0], LittleShort(mld->sidenum[0]));
P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1])); P_SetSideNum (&ld->sidedef[1], LittleShort(mld->sidenum[1]));
P_AdjustLine (ld); P_AdjustLine (ld);
P_SetLineID(ld); P_SetLineID(i, ld);
P_SaveLineSpecial (ld); P_SaveLineSpecial (ld);
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_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++) for (s = 0; s < numsectors; s++)
{ {
if (sectors[s].tag == tag) if (tagManager.SectorHasTag(s, tag))
{ {
if (!colorgood) color = sectors[s].ColorMap->Color; if (!colorgood) color = sectors[s].ColorMap->Color;
if (!foggood) fog = sectors[s].ColorMap->Fade; if (!foggood) fog = sectors[s].ColorMap->Fade;
@ -3129,9 +3133,9 @@ static void P_GroupLines (bool buildmap)
{ {
if (sector->linecount == 0) if (sector->linecount == 0)
{ {
Printf ("Sector %i (tag %i) has no lines\n", i, sector->tag); 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 // 0 the sector's tag so that no specials can use it
sector->tag = 0; tagManager.RemoveSectorTags(i);
} }
else else
{ {
@ -3207,7 +3211,8 @@ static void P_GroupLines (bool buildmap)
// [RH] Moved this here // [RH] Moved this here
times[4].Clock(); times[4].Clock();
P_InitTagLists(); // killough 1/30/98: Create xref tables for tags // killough 1/30/98: Create xref tables for tags
tagManager.HashTags();
times[4].Unclock(); times[4].Unclock();
times[5].Clock(); times[5].Clock();
@ -3304,62 +3309,20 @@ void P_LoadBehavior (MapData * map)
} }
} }
// Hash the sector tags across the sectors and linedefs.
static void P_InitTagLists ()
{
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;
}
// killough 4/17/98: same thing, only for linedefs
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;
}
}
void P_GetPolySpots (MapData * map, TArray<FNodeBuilder::FPolyStart> &spots, TArray<FNodeBuilder::FPolyStart> &anchors) void P_GetPolySpots (MapData * map, TArray<FNodeBuilder::FPolyStart> &spots, TArray<FNodeBuilder::FPolyStart> &anchors)
{ {
if (map->HasBehavior) if (map->HasBehavior)
{ {
int spot1, spot2, spot3, anchor;
if (gameinfo.gametype == GAME_Hexen)
{
spot1 = PO_HEX_SPAWN_TYPE;
spot2 = PO_HEX_SPAWNCRUSH_TYPE;
anchor = PO_HEX_ANCHOR_TYPE;
}
else
{
spot1 = PO_SPAWN_TYPE;
spot2 = PO_SPAWNCRUSH_TYPE;
anchor = PO_ANCHOR_TYPE;
}
spot3 = PO_SPAWNHURT_TYPE;
for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i) for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i)
{ {
if (MapThingsConverted[i].type == spot1 || MapThingsConverted[i].type == spot2 || FDoomEdEntry *mentry = MapThingsConverted[i].info;
MapThingsConverted[i].type == spot3 || MapThingsConverted[i].type == anchor) if (mentry != NULL && mentry->Type == NULL && mentry->Special >= SMT_PolyAnchor && mentry->Special <= SMT_PolySpawnHurt)
{ {
FNodeBuilder::FPolyStart newvert; FNodeBuilder::FPolyStart newvert;
newvert.x = MapThingsConverted[i].x; newvert.x = MapThingsConverted[i].x;
newvert.y = MapThingsConverted[i].y; newvert.y = MapThingsConverted[i].y;
newvert.polynum = MapThingsConverted[i].angle; newvert.polynum = MapThingsConverted[i].angle;
if (MapThingsConverted[i].type == anchor) if (mentry->Special == SMT_PolyAnchor)
{ {
anchors.Push (newvert); anchors.Push (newvert);
} }
@ -3380,6 +3343,7 @@ void P_FreeLevelData ()
FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process.
SN_StopAllSequences (); SN_StopAllSequences ();
DThinker::DestroyAllThinkers (); DThinker::DestroyAllThinkers ();
tagManager.Clear();
level.total_monsters = level.total_items = level.total_secrets = level.total_monsters = level.total_items = level.total_secrets =
level.killed_monsters = level.found_items = level.found_secrets = level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0; wminfo.maxfrags = 0;

View file

@ -115,7 +115,7 @@ struct line_t;
struct maplinedef_t; struct maplinedef_t;
void P_LoadTranslator(const char *lumpname); void P_LoadTranslator(const char *lumpname);
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld); void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1);
int P_TranslateSectorSpecial (int); int P_TranslateSectorSpecial (int);
int GetUDMFInt(int type, int index, const char *key); int GetUDMFInt(int type, int index, const char *key);

View file

@ -45,9 +45,10 @@
static void P_SlopeLineToPoint (int lineid, fixed_t x, fixed_t y, fixed_t z, bool slopeCeil) static void P_SlopeLineToPoint (int lineid, fixed_t x, fixed_t y, fixed_t z, bool slopeCeil)
{ {
int linenum = -1; int linenum;
while ((linenum = P_FindLineFromID (lineid, linenum)) != -1) FLineIdIterator itr(lineid);
while ((linenum = itr.Next()) >= 0)
{ {
const line_t *line = &lines[linenum]; const line_t *line = &lines[linenum];
sector_t *sec; sector_t *sec;
@ -123,7 +124,7 @@ static void P_CopyPlane (int tag, sector_t *dest, bool copyCeil)
int secnum; int secnum;
size_t planeofs; size_t planeofs;
secnum = P_FindSectorFromTag (tag, -1); secnum = P_FindFirstSectorFromTag (tag);
if (secnum == -1) if (secnum == -1)
{ {
return; return;
@ -266,20 +267,6 @@ void P_VavoomSlope(sector_t * sec, int id, fixed_t x, fixed_t y, fixed_t z, int
} }
} }
enum
{
THING_SlopeFloorPointLine = 9500,
THING_SlopeCeilingPointLine = 9501,
THING_SetFloorSlope = 9502,
THING_SetCeilingSlope = 9503,
THING_CopyFloorPlane = 9510,
THING_CopyCeilingPlane = 9511,
THING_VavoomFloor=1500,
THING_VavoomCeiling=1501,
THING_VertexFloorZ=1504,
THING_VertexCeilingZ=1505,
};
//========================================================================== //==========================================================================
// //
// P_SetSlopesFromVertexHeights // P_SetSlopesFromVertexHeights
@ -294,24 +281,27 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt,
for (mt = firstmt; mt < lastmt; ++mt) for (mt = firstmt; mt < lastmt; ++mt)
{ {
if (mt->type == THING_VertexFloorZ || mt->type == THING_VertexCeilingZ) if (mt->info != NULL && mt->info->Type == NULL)
{ {
for(int i=0; i<numvertexes; i++) if (mt->info->Special == SMT_VertexFloorZ || mt->info->Special == SMT_VertexCeilingZ)
{ {
if (vertexes[i].x == mt->x && vertexes[i].y == mt->y) for (int i = 0; i < numvertexes; i++)
{ {
if (mt->type == THING_VertexFloorZ) if (vertexes[i].x == mt->x && vertexes[i].y == mt->y)
{ {
vt_heights[0][i] = mt->z; if (mt->info->Special == SMT_VertexFloorZ)
{
vt_heights[0][i] = mt->z;
}
else
{
vt_heights[1][i] = mt->z;
}
vt_found = true;
} }
else
{
vt_heights[1][i] = mt->z;
}
vt_found = true;
} }
mt->EdNum = 0;
} }
mt->type = 0;
} }
} }
@ -427,49 +417,51 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt, const int *oldve
for (mt = firstmt; mt < lastmt; ++mt) for (mt = firstmt; mt < lastmt; ++mt)
{ {
if ((mt->type >= THING_SlopeFloorPointLine && if (mt->info != NULL && mt->info->Type == NULL &&
mt->type <= THING_SetCeilingSlope) || (mt->info->Special >= SMT_SlopeFloorPointLine && mt->info->Special <= SMT_VavoomCeiling))
mt->type == THING_VavoomFloor || mt->type == THING_VavoomCeiling)
{ {
fixed_t x, y, z; fixed_t x, y, z;
secplane_t *refplane; secplane_t *refplane;
sector_t *sec; sector_t *sec;
bool ceiling;
x = mt->x; x = mt->x;
y = mt->y; y = mt->y;
sec = P_PointInSector (x, y); sec = P_PointInSector (x, y);
if (mt->type & 1) if (mt->info->Special == SMT_SlopeCeilingPointLine || mt->info->Special == SMT_VavoomCeiling || mt->info->Special == SMT_SetCeilingSlope)
{ {
refplane = &sec->ceilingplane; refplane = &sec->ceilingplane;
ceiling = true;
} }
else else
{ {
refplane = &sec->floorplane; refplane = &sec->floorplane;
ceiling = false;
} }
z = refplane->ZatPoint (x, y) + (mt->z); z = refplane->ZatPoint (x, y) + (mt->z);
if (mt->type == THING_VavoomFloor || mt->type == THING_VavoomCeiling) if (mt->info->Special <= SMT_SlopeCeilingPointLine)
{ { // SlopeFloorPointLine and SlopCeilingPointLine
P_VavoomSlope(sec, mt->thingid, x, y, mt->z, mt->type & 1); P_SlopeLineToPoint (mt->args[0], x, y, z, ceiling);
} }
else if (mt->type <= THING_SlopeCeilingPointLine) else if (mt->info->Special <= SMT_SetCeilingSlope)
{ // THING_SlopeFloorPointLine and THING_SlopCeilingPointLine { // SetFloorSlope and SetCeilingSlope
P_SlopeLineToPoint (mt->args[0], x, y, z, mt->type & 1); P_SetSlope (refplane, ceiling, mt->angle, mt->args[0], x, y, z);
} }
else else
{ // THING_SetFloorSlope and THING_SetCeilingSlope { // VavoomFloor and VavoomCeiling
P_SetSlope (refplane, mt->type & 1, mt->angle, mt->args[0], x, y, z); P_VavoomSlope(sec, mt->thingid, x, y, mt->z, ceiling);
} }
mt->type = 0; mt->EdNum = 0;
} }
} }
for (mt = firstmt; mt < lastmt; ++mt) for (mt = firstmt; mt < lastmt; ++mt)
{ {
if (mt->type == THING_CopyFloorPlane || if (mt->info != NULL && mt->info->Type == NULL &&
mt->type == THING_CopyCeilingPlane) (mt->info->Special == SMT_CopyFloorPlane || mt->info->Special == SMT_CopyCeilingPlane))
{ {
P_CopyPlane (mt->args[0], mt->x, mt->y, mt->type & 1); P_CopyPlane (mt->args[0], mt->x, mt->y, mt->info->Special == SMT_CopyCeilingPlane);
mt->type = 0; mt->EdNum = 0;
} }
} }

View file

@ -186,38 +186,6 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info)
// UTILITIES // 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 P_FindSectorFromTag (int tag, int start)
{
start = start >= 0 ? sectors[start].nexttag :
sectors[(unsigned) tag % (unsigned) numsectors].firsttag;
while (start >= 0 && sectors[start].tag != tag)
start = sectors[start].nexttag;
return start;
}
// killough 4/16/98: Same thing, only for linedefs
int P_FindLineFromID (int id, int start)
{
start = start >= 0 ? lines[start].nextid :
lines[(unsigned) id % (unsigned) numlines].firstid;
while (start >= 0 && lines[start].id != id)
start = lines[start].nextid;
return start;
}
//============================================================================ //============================================================================
// //
// P_ActivateLine // P_ActivateLine
@ -260,13 +228,13 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
} }
// some old WADs use this method to create walls that change the texture when shot. // some old WADs use this method to create walls that change the texture when shot.
else if (activationType == SPAC_Impact && // only for shootable triggers else if (activationType == SPAC_Impact && // only for shootable triggers
(level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack! (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
!repeat && // only non-repeatable triggers !repeat && // only non-repeatable triggers
(special<Generic_Floor || special>Generic_Crusher) && // not for Boom's generalized linedefs (special<Generic_Floor || special>Generic_Crusher) && // not for Boom's generalized linedefs
special && // not for lines without a special special && // not for lines without a special
line->args[0] == line->id && // 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) line->args[0] && // only if there's a tag (which is stored in the first arg)
P_FindSectorFromTag (line->args[0], -1) == -1) // only if no sector is tagged to this linedef P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef
{ {
P_ChangeSwitchTexture (line->sidedef[0], repeat, special); P_ChangeSwitchTexture (line->sidedef[0], repeat, special);
line->special = 0; line->special = 0;
@ -657,9 +625,9 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type,
void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags) void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags)
{ {
int secnum = -1; FSectorTagIterator itr(tag);
int secnum;
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) while ((secnum = itr.Next()) >= 0)
{ {
AActor *actor, *next; AActor *actor, *next;
sector_t *sec = &sectors[secnum]; sector_t *sec = &sectors[secnum];
@ -884,12 +852,14 @@ DLightTransfer::DLightTransfer (sector_t *srcSec, int target, bool copyFloor)
if (copyFloor) if (copyFloor)
{ {
for (secnum = -1; (secnum = P_FindSectorFromTag (target, secnum)) >= 0; ) FSectorTagIterator itr(target);
while ((secnum = itr.Next()) >= 0)
sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING); sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
} }
else else
{ {
for (secnum = -1; (secnum = P_FindSectorFromTag (target, secnum)) >= 0; ) FSectorTagIterator itr(target);
while ((secnum = itr.Next()) >= 0)
sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING); sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
} }
ChangeStatNum (STAT_LIGHTTRANSFER); ChangeStatNum (STAT_LIGHTTRANSFER);
@ -912,12 +882,14 @@ void DLightTransfer::DoTransfer (int level, int target, bool floor)
if (floor) if (floor)
{ {
for (secnum = -1; (secnum = P_FindSectorFromTag (target, secnum)) >= 0; ) FSectorTagIterator itr(target);
while ((secnum = itr.Next()) >= 0)
sectors[secnum].SetPlaneLight(sector_t::floor, level); sectors[secnum].SetPlaneLight(sector_t::floor, level);
} }
else else
{ {
for (secnum = -1; (secnum = P_FindSectorFromTag (target, secnum)) >= 0; ) FSectorTagIterator itr(target);
while ((secnum = itr.Next()) >= 0)
sectors[secnum].SetPlaneLight(sector_t::ceiling, level); sectors[secnum].SetPlaneLight(sector_t::ceiling, level);
} }
} }
@ -985,7 +957,8 @@ DWallLightTransfer::DWallLightTransfer (sector_t *srcSec, int target, BYTE flags
wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST; wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST;
} }
for (linenum = -1; (linenum = P_FindLineFromID (target, linenum)) >= 0; ) FLineIdIterator itr(target);
while ((linenum = itr.Next()) >= 0)
{ {
if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL) if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL)
{ {
@ -1015,7 +988,8 @@ void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags)
{ {
int linenum; int linenum;
for (linenum = -1; (linenum = P_FindLineFromID (target, linenum)) >= 0; ) FLineIdIterator itr(target);
while ((linenum = itr.Next()) >= 0)
{ {
line_t *line = &lines[linenum]; line_t *line = &lines[linenum];
@ -1173,7 +1147,9 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
reference->flags |= MF_JUSTATTACKED; reference->flags |= MF_JUSTATTACKED;
anchor->flags |= MF_JUSTATTACKED; anchor->flags |= MF_JUSTATTACKED;
for (int s=-1; (s = P_FindSectorFromTag(sectortag,s)) >= 0;) int s;
FSectorTagIterator itr(sectortag);
while ((s = itr.Next()) >= 0)
{ {
SetPortal(&sectors[s], plane, reference, alpha); SetPortal(&sectors[s], plane, reference, alpha);
} }
@ -1193,7 +1169,8 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
} }
else else
{ {
for (int s=-1; (s = P_FindSectorFromTag(lines[j].args[0],s)) >= 0;) FSectorTagIterator itr(lines[j].args[0]);
while ((s = itr.Next()) >= 0)
{ {
SetPortal(&sectors[s], plane, reference, alpha); SetPortal(&sectors[s], plane, reference, alpha);
} }
@ -1374,38 +1351,41 @@ void P_SpawnSpecials (void)
// killough 3/7/98: // killough 3/7/98:
// support for drawn heights coming from different sector // support for drawn heights coming from different sector
case Transfer_Heights: case Transfer_Heights:
sec = lines[i].frontsector;
if (lines[i].args[1] & 2)
{ {
sec->MoreFlags |= SECF_FAKEFLOORONLY; sec = lines[i].frontsector;
if (lines[i].args[1] & 2)
{
sec->MoreFlags |= SECF_FAKEFLOORONLY;
}
if (lines[i].args[1] & 4)
{
sec->MoreFlags |= SECF_CLIPFAKEPLANES;
}
if (lines[i].args[1] & 8)
{
sec->MoreFlags |= SECF_UNDERWATER;
}
else if (forcewater)
{
sec->MoreFlags |= SECF_FORCEDUNDERWATER;
}
if (lines[i].args[1] & 16)
{
sec->MoreFlags |= SECF_IGNOREHEIGHTSEC;
}
if (lines[i].args[1] & 32)
{
sec->MoreFlags |= SECF_NOFAKELIGHT;
}
FSectorTagIterator itr(lines[i].args[0]);
while ((s = itr.Next()) >= 0)
{
sectors[s].heightsec = sec;
sec->e->FakeFloor.Sectors.Push(&sectors[s]);
sectors[s].AdjustFloorClip();
}
break;
} }
if (lines[i].args[1] & 4)
{
sec->MoreFlags |= SECF_CLIPFAKEPLANES;
}
if (lines[i].args[1] & 8)
{
sec->MoreFlags |= SECF_UNDERWATER;
}
else if (forcewater)
{
sec->MoreFlags |= SECF_FORCEDUNDERWATER;
}
if (lines[i].args[1] & 16)
{
sec->MoreFlags |= SECF_IGNOREHEIGHTSEC;
}
if (lines[i].args[1] & 32)
{
sec->MoreFlags |= SECF_NOFAKELIGHT;
}
for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0],s)) >= 0;)
{
sectors[s].heightsec = sec;
sec->e->FakeFloor.Sectors.Push(&sectors[s]);
sectors[s].AdjustFloorClip();
}
break;
// killough 3/16/98: Add support for setting // killough 3/16/98: Add support for setting
// floor lighting independently (e.g. lava) // floor lighting independently (e.g. lava)
@ -1458,9 +1438,10 @@ void P_SpawnSpecials (void)
{ {
case Init_Gravity: case Init_Gravity:
{ {
float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f); float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f);
for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0],s)) >= 0;) FSectorTagIterator itr(lines[i].args[0]);
sectors[s].gravity = grav; while ((s = itr.Next()) >= 0)
sectors[s].gravity = grav;
} }
break; break;
@ -1470,7 +1451,8 @@ void P_SpawnSpecials (void)
case Init_Damage: case Init_Damage:
{ {
int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS; int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS;
for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0],s)) >= 0;) FSectorTagIterator itr(lines[i].args[0]);
while ((s = itr.Next()) >= 0)
{ {
sectors[s].damage = damage; sectors[s].damage = damage;
sectors[s].mod = 0;//MOD_UNKNOWN; sectors[s].mod = 0;//MOD_UNKNOWN;
@ -1493,9 +1475,12 @@ void P_SpawnSpecials (void)
// or ceiling texture, to distinguish floor and ceiling sky. // or ceiling texture, to distinguish floor and ceiling sky.
case Init_TransferSky: case Init_TransferSky:
for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0],s)) >= 0;) {
sectors[s].sky = (i+1) | PL_SKYFLAT; FSectorTagIterator itr(lines[i].args[0]);
break; while ((s = itr.Next()) >= 0)
sectors[s].sky = (i + 1) | PL_SKYFLAT;
break;
}
} }
break; break;
} }
@ -1756,7 +1741,7 @@ static void P_SpawnScrollers(void)
if (lines[i].special == Sector_CopyScroller) 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. // don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (lines[i].args[0] != lines[i].frontsector->tag) if (tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0]))
{ {
copyscrollers.Push(i); copyscrollers.Push(i);
} }
@ -1832,25 +1817,29 @@ static void P_SpawnScrollers(void)
register int s; register int s;
case Scroll_Ceiling: case Scroll_Ceiling:
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) {
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{ {
new DScroller (DScroller::sc_ceiling, -dx, dy, control, s, accel); new DScroller(DScroller::sc_ceiling, -dx, dy, control, s, accel);
} }
for(unsigned j = 0;j < copyscrollers.Size(); j++) for (unsigned j = 0; j < copyscrollers.Size(); j++)
{ {
line_t *line = &lines[copyscrollers[j]]; line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 1)) if (line->args[0] == l->args[0] && (line->args[1] & 1))
{ {
new DScroller (DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector-sectors), accel); new DScroller(DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector - sectors), accel);
} }
} }
break; break;
}
case Scroll_Floor: case Scroll_Floor:
if (l->args[2] != 1) if (l->args[2] != 1)
{ // scroll the floor texture { // scroll the floor texture
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{ {
new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel); new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel);
} }
@ -1867,7 +1856,8 @@ static void P_SpawnScrollers(void)
if (l->args[2] > 0) if (l->args[2] > 0)
{ // carry objects on the floor { // carry objects on the floor
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{ {
new DScroller (DScroller::sc_carry, dx, dy, control, s, accel); new DScroller (DScroller::sc_carry, dx, dy, control, s, accel);
} }
@ -1886,10 +1876,15 @@ static void P_SpawnScrollers(void)
// killough 3/1/98: scroll wall according to linedef // killough 3/1/98: scroll wall according to linedef
// (same direction and speed as scrolling floors) // (same direction and speed as scrolling floors)
case Scroll_Texture_Model: case Scroll_Texture_Model:
for (s=-1; (s = P_FindLineFromID (l->args[0],s)) >= 0;) {
FLineIdIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
if (s != i) if (s != i)
new DScroller (dx, dy, lines+s, control, accel); new DScroller(dx, dy, lines + s, control, accel);
}
break; break;
}
case Scroll_Texture_Offsets: case Scroll_Texture_Offsets:
// killough 3/2/98: scroll according to sidedef offsets // killough 3/2/98: scroll according to sidedef offsets
@ -2041,7 +2036,8 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag)
// higher friction value actually means 'less friction'. // higher friction value actually means 'less friction'.
movefactor = FrictionToMoveFactor(friction); movefactor = FrictionToMoveFactor(friction);
for (s = -1; (s = P_FindSectorFromTag (tag,s)) >= 0; ) FSectorTagIterator itr(tag);
while ((s = itr.Next()) >= 0)
{ {
// killough 8/28/98: // killough 8/28/98:
// //
@ -2153,7 +2149,7 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
int DPusher::CheckForSectorMatch (EPusher type, int tag) int DPusher::CheckForSectorMatch (EPusher type, int tag)
{ {
if (m_Type == type && sectors[m_Affectee].tag == tag) if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
return m_Affectee; return m_Affectee;
else else
return -1; return -1;
@ -2356,20 +2352,27 @@ static void P_SpawnPushers ()
switch (l->special) switch (l->special)
{ {
case Sector_SetWind: // wind case Sector_SetWind: // wind
for (s = -1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0 ; ) {
new DPusher (DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
new DPusher(DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
l->special = 0; l->special = 0;
break; break;
}
case Sector_SetCurrent: // current case Sector_SetCurrent: // current
for (s = -1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0 ; ) {
new DPusher (DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s); FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
new DPusher(DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
l->special = 0; l->special = 0;
break; break;
}
case PointPush_SetForce: // push/pull case PointPush_SetForce: // push/pull
if (l->args[0]) { // [RH] Find thing by sector if (l->args[0]) { // [RH] Find thing by sector
for (s = -1; (s = P_FindSectorFromTag (l->args[0], s)) >= 0 ; ) FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{ {
AActor *thing = P_GetPushThing (s); AActor *thing = P_GetPushThing (s);
if (thing) { // No MT_P* means no effect if (thing) { // No MT_P* means no effect

View file

@ -243,9 +243,7 @@ inline sector_t *getNextSector (line_t *line, const sector_t *sec)
} }
int P_FindSectorFromTag (int tag, int start); #include "p_tags.h"
int P_FindLineFromID (int id, int start);
// //
// P_LIGHTS // 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; int count = 0;
while ( (searcher = iterator.Next ()) ) while ( (searcher = iterator.Next ()) )
{ {
if (tag == 0 || searcher->Sector->tag == tag) if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{ {
count++; count++;
} }
@ -289,7 +289,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
while (count > 0) while (count > 0)
{ {
searcher = iterator.Next (); searcher = iterator.Next ();
if (tag == 0 || searcher->Sector->tag == tag) if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{ {
count--; count--;
} }
@ -300,9 +300,10 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
if (tag != 0) if (tag != 0)
{ {
int secnum = -1; int secnum;
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator itr(tag);
while ((secnum = itr.Next()) >= 0)
{ {
// Scanning the snext links of things in the sector will not work, because // Scanning the snext links of things in the sector will not work, because
// TeleportDests have MF_NOSECTOR set. So you have to search *everything*. // TeleportDests have MF_NOSECTOR set. So you have to search *everything*.
@ -423,7 +424,8 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO
if (side || thing->flags2 & MF2_NOTELEPORT || !line || line->sidedef[1] == NULL) if (side || thing->flags2 & MF2_NOTELEPORT || !line || line->sidedef[1] == NULL)
return false; return false;
for (i = -1; (i = P_FindLineFromID (id, i)) >= 0; ) FLineIdIterator itr(id);
while ((i = itr.Next()) >= 0)
{ {
if (line-lines == i) if (line-lines == i)
continue; continue;
@ -726,7 +728,8 @@ bool EV_TeleportSector (int tag, int source_tid, int dest_tid, bool fog, int gro
int secnum; int secnum;
secnum = -1; secnum = -1;
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) FSectorTagIterator itr(tag);
while ((secnum = itr.Next()) >= 0)
{ {
msecnode_t *node; msecnode_t *node;
const sector_t * const sec = &sectors[secnum]; const sector_t * const sec = &sectors[secnum];

View file

@ -69,6 +69,12 @@ public:
} }
void Set(int index, int value) void Set(int index, int value)
{ {
if ((unsigned)index >= Types.Size())
{
int oldsize = Types.Size();
Resize(index + 1);
memset(&Types[oldsize], 0xff, (index + 1 - oldsize)*sizeof(WORD));
}
Types[index] = value; Types[index] = value;
} }
}; };

View file

@ -45,9 +45,11 @@
#include "gi.h" #include "gi.h"
#include "templates.h" #include "templates.h"
#include "g_level.h" #include "g_level.h"
#include "v_text.h"
#include "i_system.h"
// Set of spawnable things for the Thing_Spawn and Thing_Projectile specials. // Set of spawnable things for the Thing_Spawn and Thing_Projectile specials.
TMap<int, const PClass *> SpawnableThings; FClassMap SpawnableThings;
static FRandom pr_leadtarget ("LeadTarget"); static FRandom pr_leadtarget ("LeadTarget");
@ -530,22 +532,32 @@ const PClass *P_GetSpawnableType(int spawnnum)
return NULL; return NULL;
} }
typedef TMap<int, const PClass *>::Pair SpawnablePair; struct MapinfoSpawnItem
{
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
FString filename;
int linenum;
};
typedef TMap<int, MapinfoSpawnItem> SpawnMap;
static SpawnMap SpawnablesFromMapinfo;
static SpawnMap ConversationIDsFromMapinfo;
static int STACK_ARGS SpawnableSort(const void *a, const void *b) static int STACK_ARGS SpawnableSort(const void *a, const void *b)
{ {
return (*((SpawnablePair **)a))->Key - (*((SpawnablePair **)b))->Key; return (*((FClassMap::Pair **)a))->Key - (*((FClassMap::Pair **)b))->Key;
} }
CCMD (dumpspawnables) static void DumpClassMap(FClassMap &themap)
{ {
TMapIterator<int, const PClass *> it(SpawnableThings); FClassMap::Iterator it(themap);
SpawnablePair *pair, **allpairs; FClassMap::Pair *pair, **allpairs;
int i = 0; int i = 0;
// Sort into numerical order, since their arrangement in the map can // Sort into numerical order, since their arrangement in the map can
// be in an unspecified order. // be in an unspecified order.
allpairs = new TMap<int, const PClass *>::Pair *[SpawnableThings.CountUsed()]; allpairs = new FClassMap::Pair *[themap.CountUsed()];
while (it.NextPair(pair)) while (it.NextPair(pair))
{ {
allpairs[i++] = pair; allpairs[i++] = pair;
@ -559,3 +571,110 @@ CCMD (dumpspawnables)
delete[] allpairs; delete[] allpairs;
} }
CCMD(dumpspawnables)
{
DumpClassMap(SpawnableThings);
}
CCMD (dumpconversationids)
{
DumpClassMap(StrifeTypes);
}
static void ParseSpawnMap(FScanner &sc, SpawnMap & themap, const char *descript)
{
TMap<int, bool> defined;
int error = 0;
MapinfoSpawnItem editem;
editem.filename = sc.ScriptName;
while (true)
{
if (sc.CheckString("}")) return;
else if (sc.CheckNumber())
{
int ednum = sc.Number;
sc.MustGetStringName("=");
sc.MustGetString();
bool *def = defined.CheckKey(ednum);
if (def != NULL)
{
sc.ScriptMessage("%s %d defined more than once", descript, ednum);
error++;
}
else if (ednum < 0)
{
sc.ScriptMessage("%s must be positive, got %d", descript, ednum);
error++;
}
defined[ednum] = true;
editem.classname = sc.String;
themap.Insert(ednum, editem);
}
else
{
sc.ScriptError("Number expected");
}
}
if (error > 0)
{
sc.ScriptError("%d errors encountered in %s definition", error, descript);
}
}
void FMapInfoParser::ParseSpawnNums()
{
ParseOpenBrace();
ParseSpawnMap(sc, SpawnablesFromMapinfo, "Spawn number");
}
void FMapInfoParser::ParseConversationIDs()
{
ParseOpenBrace();
ParseSpawnMap(sc, ConversationIDsFromMapinfo, "Conversation ID");
}
void InitClassMap(FClassMap &themap, SpawnMap &thedata)
{
themap.Clear();
SpawnMap::Iterator it(thedata);
SpawnMap::Pair *pair;
int error = 0;
while (it.NextPair(pair))
{
const PClass *cls = NULL;
if (pair->Value.classname != NAME_None)
{
cls = PClass::FindClass(pair->Value.classname);
if (cls == NULL)
{
Printf(TEXTCOLOR_RED "Script error, \"%s\" line %d:\nUnknown actor class %s\n",
pair->Value.filename.GetChars(), pair->Value.linenum, pair->Value.classname.GetChars());
error++;
}
themap.Insert(pair->Key, cls);
}
else
{
themap.Remove(pair->Key);
}
}
if (error > 0)
{
I_Error("%d unknown actor classes found", error);
}
thedata.Clear(); // we do not need this any longer
}
void InitSpawnablesFromMapinfo()
{
InitClassMap(SpawnableThings, SpawnablesFromMapinfo);
InitClassMap(StrifeTypes, ConversationIDsFromMapinfo);
}

View file

@ -46,6 +46,7 @@
#include "r_state.h" #include "r_state.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "w_wad.h" #include "w_wad.h"
#include "p_tags.h"
//=========================================================================== //===========================================================================
// //
@ -500,7 +501,8 @@ public:
break; break;
case NAME_Type: case NAME_Type:
th->type = (short)CheckInt(key); th->EdNum = (short)CheckInt(key);
th->info = DoomEdMap.CheckKey(th->EdNum);
break; break;
case NAME_Conversation: case NAME_Conversation:
@ -721,6 +723,7 @@ public:
break; break;
default: default:
CHECK_N(Zd | Zdt)
if (0 == strnicmp("user_", key.GetChars(), 5)) if (0 == strnicmp("user_", key.GetChars(), 5))
{ // Custom user key - Sets an actor's user variable directly { // Custom user key - Sets an actor's user variable directly
FMapThingUserData ud; FMapThingUserData ud;
@ -776,10 +779,11 @@ public:
bool strifetrans = false; bool strifetrans = false;
bool strifetrans2 = false; bool strifetrans2 = false;
FString arg0str, arg1str; FString arg0str, arg1str;
int lineid; // forZDoomTranslated namespace
FString tagstring;
memset(ld, 0, sizeof(*ld)); memset(ld, 0, sizeof(*ld));
ld->Alpha = FRACUNIT; ld->Alpha = FRACUNIT;
ld->id = -1;
ld->sidedef[0] = ld->sidedef[1] = NULL; ld->sidedef[0] = ld->sidedef[1] = NULL;
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
@ -812,7 +816,8 @@ public:
continue; continue;
case NAME_Id: case NAME_Id:
ld->id = CheckInt(key); lineid = CheckInt(key);
tagManager.AddLineID(index, lineid);
continue; continue;
case NAME_Sidefront: case NAME_Sidefront:
@ -1035,16 +1040,35 @@ public:
Flag(ld->flags, ML_3DMIDTEX_IMPASS, key); Flag(ld->flags, ML_3DMIDTEX_IMPASS, key);
continue; 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: default:
break; break;
} }
if (!strnicmp("user_", key.GetChars(), 5))
if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
{ {
AddUserKey(key, UDMF_Line, index); AddUserKey(key, UDMF_Line, 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.AddLineID(index, sc.Number);
}
}
if (isTranslated) if (isTranslated)
{ {
int saved = ld->flags; int saved = ld->flags;
@ -1052,7 +1076,7 @@ public:
maplinedef_t mld; maplinedef_t mld;
memset(&mld, 0, sizeof(mld)); memset(&mld, 0, sizeof(mld));
mld.special = ld->special; mld.special = ld->special;
mld.tag = ld->id; mld.tag = lineid;
P_TranslateLineDef(ld, &mld); P_TranslateLineDef(ld, &mld);
ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY)); ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY));
} }
@ -1225,7 +1249,7 @@ public:
break; break;
} }
if (!strnicmp("user_", key.GetChars(), 5)) if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
{ {
AddUserKey(key, UDMF_Side, index); AddUserKey(key, UDMF_Side, index);
} }
@ -1252,6 +1276,7 @@ public:
int desaturation = -1; int desaturation = -1;
int fplaneflags = 0, cplaneflags = 0; int fplaneflags = 0, cplaneflags = 0;
double fp[4] = { 0 }, cp[4] = { 0 }; double fp[4] = { 0 }, cp[4] = { 0 };
FString tagstring;
memset(sec, 0, sizeof(*sec)); memset(sec, 0, sizeof(*sec));
sec->lightlevel = 160; sec->lightlevel = 160;
@ -1315,7 +1340,7 @@ public:
continue; continue;
case NAME_Id: case NAME_Id:
sec->tag = (short)CheckInt(key); tagManager.AddSectorTag(index, CheckInt(key));
continue; continue;
default: default:
@ -1493,16 +1518,32 @@ public:
cp[3] = CheckFloat(key); cp[3] = CheckFloat(key);
break; 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: default:
break; break;
} }
if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
if (!strnicmp("user_", key.GetChars(), 5))
{ {
AddUserKey(key, UDMF_Sector, index); 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); sec->secretsector = !!(sec->special&SECRET_MASK);
// Reset the planes to their defaults if not all of the plane equation's parameters were found. // Reset the planes to their defaults if not all of the plane equation's parameters were found.

View file

@ -295,14 +295,16 @@ player_t::player_t()
respawn_time(0), respawn_time(0),
camera(0), camera(0),
air_finished(0), air_finished(0),
MUSINFOactor(0),
MUSINFOtics(-1),
crouching(0),
crouchdir(0),
Bot(0), Bot(0),
BlendR(0), BlendR(0),
BlendG(0), BlendG(0),
BlendB(0), BlendB(0),
BlendA(0), BlendA(0),
LogText(), LogText(),
crouching(0),
crouchdir(0),
crouchfactor(0), crouchfactor(0),
crouchoffset(0), crouchoffset(0),
crouchviewdelta(0), crouchviewdelta(0),
@ -400,6 +402,8 @@ player_t &player_t::operator=(const player_t &p)
ConversationPC = p.ConversationPC; ConversationPC = p.ConversationPC;
ConversationNPCAngle = p.ConversationNPCAngle; ConversationNPCAngle = p.ConversationNPCAngle;
ConversationFaceTalker = p.ConversationFaceTalker; ConversationFaceTalker = p.ConversationFaceTalker;
MUSINFOactor = p.MUSINFOactor;
MUSINFOtics = p.MUSINFOtics;
return *this; return *this;
} }
@ -430,6 +434,7 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep)
if (*&PremorphWeapon == old) PremorphWeapon = static_cast<AWeapon *>(rep), changed++; if (*&PremorphWeapon == old) PremorphWeapon = static_cast<AWeapon *>(rep), changed++;
if (*&ConversationNPC == old) ConversationNPC = replacement, changed++; if (*&ConversationNPC == old) ConversationNPC = replacement, changed++;
if (*&ConversationPC == old) ConversationPC = replacement, changed++; if (*&ConversationPC == old) ConversationPC = replacement, changed++;
if (*&MUSINFOactor == old) MUSINFOactor = replacement, changed++;
return changed; return changed;
} }
@ -443,6 +448,7 @@ size_t player_t::PropagateMark()
GC::Mark(ReadyWeapon); GC::Mark(ReadyWeapon);
GC::Mark(ConversationNPC); GC::Mark(ConversationNPC);
GC::Mark(ConversationPC); GC::Mark(ConversationPC);
GC::Mark(MUSINFOactor);
GC::Mark(PremorphWeapon); GC::Mark(PremorphWeapon);
if (PendingWeapon != WP_NOCHANGE) if (PendingWeapon != WP_NOCHANGE)
{ {
@ -2331,6 +2337,30 @@ void P_PlayerThink (player_t *player)
player->crouchoffset = -FixedMul(player->mo->ViewHeight, (FRACUNIT - player->crouchfactor)); player->crouchoffset = -FixedMul(player->mo->ViewHeight, (FRACUNIT - player->crouchfactor));
// MUSINFO stuff
if (player->MUSINFOtics >= 0 && player->MUSINFOactor != NULL)
{
if (--player->MUSINFOtics < 0)
{
if (player - players == consoleplayer)
{
if (player->MUSINFOactor->args[0] != 0)
{
FName *music = level.info->MusicMap.CheckKey(player->MUSINFOactor->args[0]);
if (music != NULL)
{
S_ChangeMusic(music->GetChars(), player->MUSINFOactor->args[1]);
}
}
else
{
S_ChangeMusic("*");
}
}
DPrintf("MUSINFO change for player %d to %d\n", (int)(player - players), player->MUSINFOactor->args[0]);
}
}
if (player->playerstate == PST_DEAD) if (player->playerstate == PST_DEAD)
{ {
@ -3105,6 +3135,10 @@ void player_t::Serialize (FArchive &arc)
{ {
userinfo.SkinChanged(skinname, CurrentPlayerClass); userinfo.SkinChanged(skinname, CurrentPlayerClass);
} }
if (SaveVersion >= 4522)
{
arc << MUSINFOactor << MUSINFOtics;
}
} }

View file

@ -262,7 +262,7 @@ static int WriteSECTORS (FILE *file)
uppercopy (ms.ceilingpic, GetTextureName (sectors[i].GetTexture(sector_t::ceiling))); uppercopy (ms.ceilingpic, GetTextureName (sectors[i].GetTexture(sector_t::ceiling)));
ms.lightlevel = LittleShort((short)sectors[i].lightlevel); ms.lightlevel = LittleShort((short)sectors[i].lightlevel);
ms.special = LittleShort(sectors[i].special); ms.special = LittleShort(sectors[i].special);
ms.tag = LittleShort(sectors[i].tag); ms.tag = LittleShort(tagManager.GetFirstSectorTag(&sectors[i]));
fwrite (&ms, sizeof(ms), 1, file); fwrite (&ms, sizeof(ms), 1, file);
} }
return numsectors * sizeof(ms); return numsectors * sizeof(ms);

View file

@ -60,7 +60,7 @@ typedef enum
PushMany, PushMany,
} triggertype_e; } triggertype_e;
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld) void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid)
{ {
unsigned short special = (unsigned short) LittleShort(mld->special); unsigned short special = (unsigned short) LittleShort(mld->special);
short tag = LittleShort(mld->tag); short tag = LittleShort(mld->tag);
@ -100,11 +100,14 @@ void P_TranslateLineDef (line_t *ld, maplinedef_t *mld)
} }
flags = newflags; flags = newflags;
// For purposes of maintaining BOOM compatibility, each if (lineindexforid >= 0)
// line also needs to have its ID set to the same as its tag. {
// An external conversion program would need to do this more // For purposes of maintaining BOOM compatibility, each
// intelligently. // line also needs to have its ID set to the same as its tag.
ld->id = tag; // An external conversion program would need to do this more
// intelligently.
tagManager.AddLineID(lineindexforid, tag);
}
// 0 specials are never translated. // 0 specials are never translated.
if (special == 0) if (special == 0)
@ -304,7 +307,7 @@ void P_TranslateTeleportThings ()
while ( (dest = iterator.Next()) ) while ( (dest = iterator.Next()) )
{ {
if (dest->Sector->tag == 0) if (!tagManager.SectorHasTags(dest->Sector))
{ {
dest->tid = 1; dest->tid = 1;
dest->AddToHash (); dest->AddToHash ();

View file

@ -1561,8 +1561,8 @@ static void SpawnPolyobj (int index, int tag, int type)
sd->linedef->args[0] = 0; sd->linedef->args[0] = 0;
IterFindPolySides(&polyobjs[index], sd); IterFindPolySides(&polyobjs[index], sd);
po->MirrorNum = sd->linedef->args[1]; po->MirrorNum = sd->linedef->args[1];
po->crush = (type != PO_SPAWN_TYPE) ? 3 : 0; po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag; po->tag = tag;
po->seqType = sd->linedef->args[2]; po->seqType = sd->linedef->args[2];
if (po->seqType < 0 || po->seqType > 63) if (po->seqType < 0 || po->seqType > 63)
@ -1632,8 +1632,8 @@ static void SpawnPolyobj (int index, int tag, int type)
} }
if (po->Sidedefs.Size() > 0) if (po->Sidedefs.Size() > 0)
{ {
po->crush = (type != PO_SPAWN_TYPE) ? 3 : 0; po->crush = (type != SMT_PolySpawn) ? 3 : 0;
po->bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); po->bHurtOnTouch = (type == SMT_PolySpawnHurt);
po->tag = tag; po->tag = tag;
po->seqType = po->Sidedefs[0]->linedef->args[3]; po->seqType = po->Sidedefs[0]->linedef->args[3];
po->MirrorNum = po->Sidedefs[0]->linedef->args[2]; po->MirrorNum = po->Sidedefs[0]->linedef->args[2];
@ -1756,9 +1756,7 @@ void PO_Init (void)
for (polyspawn = polyspawns, prev = &polyspawns; polyspawn;) for (polyspawn = polyspawns, prev = &polyspawns; polyspawn;)
{ {
// 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch // 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch
if (polyspawn->type == PO_SPAWN_TYPE || if (polyspawn->type >= SMT_PolySpawn && polyspawn->type <= SMT_PolySpawnHurt)
polyspawn->type == PO_SPAWNCRUSH_TYPE ||
polyspawn->type == PO_SPAWNHURT_TYPE)
{ {
// Polyobj StartSpot Pt. // Polyobj StartSpot Pt.
polyobjs[polyIndex].StartSpot.x = polyspawn->x; polyobjs[polyIndex].StartSpot.x = polyspawn->x;
@ -1778,7 +1776,7 @@ void PO_Init (void)
for (polyspawn = polyspawns; polyspawn;) for (polyspawn = polyspawns; polyspawn;)
{ {
polyspawns_t *next = polyspawn->next; polyspawns_t *next = polyspawn->next;
if (polyspawn->type == PO_ANCHOR_TYPE) if (polyspawn->type == SMT_PolyAnchor)
{ {
// Polyobj Anchor Pt. // Polyobj Anchor Pt.
TranslateToStartSpot (polyspawn->angle, polyspawn->x, polyspawn->y); TranslateToStartSpot (polyspawn->angle, polyspawn->x, polyspawn->y);

View file

@ -128,6 +128,8 @@ enum
kVK_UpArrow = 0x7E kVK_UpArrow = 0x7E
}; };
static const NSOpenGLPixelFormatAttribute NSOpenGLPFAAllowOfflineRenderers = NSOpenGLPixelFormatAttribute(96);
#endif // prior to 10.5 #endif // prior to 10.5

View file

@ -72,6 +72,11 @@ CUSTOM_CVAR(Bool, fullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
setmodeneeded = true; setmodeneeded = true;
} }
CUSTOM_CVAR(Bool, vid_autoswitch, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("You must restart " GAMENAME " to apply graphics switching mode\n");
}
RenderBufferOptions rbOpts; RenderBufferOptions rbOpts;
@ -399,6 +404,11 @@ CocoaVideo::CocoaVideo(const int multisample)
attributes[i++] = NSOpenGLPFAStencilSize; attributes[i++] = NSOpenGLPFAStencilSize;
attributes[i++] = NSOpenGLPixelFormatAttribute(8); attributes[i++] = NSOpenGLPixelFormatAttribute(8);
if (!vid_autoswitch)
{
attributes[i++] = NSOpenGLPFAAllowOfflineRenderers;
}
if (multisample) if (multisample)
{ {
attributes[i++] = NSOpenGLPFAMultisample; attributes[i++] = NSOpenGLPFAMultisample;

View file

@ -331,7 +331,7 @@ int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
gtk_container_add (GTK_CONTAINER(window), vbox); gtk_container_add (GTK_CONTAINER(window), vbox);
// Create the top label. // Create the top label.
widget = gtk_label_new ("ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"); widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:");
gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0);
gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); gtk_misc_set_alignment (GTK_MISC(widget), 0, 0);
@ -450,7 +450,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{ {
FString cmd("kdialog --title \"" GAMESIG " "); FString cmd("kdialog --title \"" GAMESIG " ");
cmd << GetVersionString() << ": Select an IWAD to use\"" cmd << GetVersionString() << ": Select an IWAD to use\""
" --menu \"ZDoom found more than one IWAD\n" " --menu \"" GAMENAME " found more than one IWAD\n"
"Select from the list below to determine which one to use:\""; "Select from the list below to determine which one to use:\"";
for(i = 0; i < numwads; ++i) for(i = 0; i < numwads; ++i)
@ -603,6 +603,15 @@ int I_FindAttr (findstate_t *fileinfo)
#ifdef __APPLE__ #ifdef __APPLE__
static PasteboardRef s_clipboard; static PasteboardRef s_clipboard;
static CFDataRef GetPasteboardData(const PasteboardItemID itemID, const CFStringRef flavorType)
{
CFDataRef data = NULL;
const OSStatus result = PasteboardCopyItemFlavorData(s_clipboard, itemID, flavorType, &data);
return noErr == result ? data : NULL;
}
#endif // __APPLE__ #endif // __APPLE__
// Clipboard support requires GTK+ // Clipboard support requires GTK+
@ -688,35 +697,41 @@ FString I_GetFromClipboard (bool use_primary_selection)
return FString(); return FString();
} }
CFArrayRef flavorTypeArray; if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF8PlainText))
if (0 != PasteboardCopyItemFlavors(s_clipboard, itemID, &flavorTypeArray))
{ {
return FString(); const CFIndex bufferLength = CFDataGetLength(data);
char* const buffer = result.LockNewBuffer(bufferLength);
memcpy(buffer, CFDataGetBytePtr(data), bufferLength);
result.UnlockBuffer();
} }
else if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF16PlainText))
const CFIndex flavorCount = CFArrayGetCount(flavorTypeArray);
for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; ++flavorIndex)
{ {
const CFStringRef flavorType = static_cast<const CFStringRef>( #ifdef __LITTLE_ENDIAN__
CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex)); static const CFStringEncoding ENCODING = kCFStringEncodingUTF16LE;
#else // __BIG_ENDIAN__
static const CFStringEncoding ENCODING = kCFStringEncodingUTF16BE;
#endif // __LITTLE_ENDIAN__
if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) if (const CFStringRef utf16 = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, ENCODING))
{ {
CFDataRef flavorData; const CFRange range = { 0, CFStringGetLength(utf16) };
CFIndex bufferLength = 0;
if (0 == PasteboardCopyItemFlavorData(s_clipboard, itemID, flavorType, &flavorData)) if (CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &bufferLength) > 0)
{ {
result += reinterpret_cast<const char*>(CFDataGetBytePtr(flavorData)); UInt8* const buffer = reinterpret_cast<UInt8*>(result.LockNewBuffer(bufferLength));
CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, buffer, bufferLength, NULL);
result.UnlockBuffer();
} }
CFRelease(flavorData); CFRelease(utf16);
} }
} }
CFRelease(flavorTypeArray);
return result; return result;
#endif #endif
return ""; return "";

View file

@ -43,5 +43,7 @@
</array> </array>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>NSApplication</string> <string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<string>YES</string>
</dict> </dict>
</plist> </plist>

View file

@ -37,7 +37,7 @@ static struct {
pid_t pid; pid_t pid;
int has_siginfo; int has_siginfo;
siginfo_t siginfo; siginfo_t siginfo;
char buf[1024]; char buf[4096];
} crash_info; } crash_info;

View file

@ -18,8 +18,6 @@
#include "templates.h" #include "templates.h"
#include "s_sound.h" #include "s_sound.h"
void ScaleWithAspect (int &w, int &h, int Width, int Height);
static void I_CheckGUICapture (); static void I_CheckGUICapture ();
static void I_CheckNativeMouse (); static void I_CheckNativeMouse ();
@ -320,35 +318,11 @@ void MessagePump (const SDL_Event &sev)
int x, y; int x, y;
SDL_GetMouseState (&x, &y); SDL_GetMouseState (&x, &y);
// Detect if we're doing scaling in the Window and adjust the mouse
// coordinates accordingly. This could be more efficent, but I
// don't think performance is an issue in the menus.
SDL_Window *focus;
if (screen->IsFullscreen() && (focus = SDL_GetMouseFocus ()))
{
int w, h;
SDL_GetWindowSize (focus, &w, &h);
int realw = w, realh = h;
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
{
double xratio = (double)SCREENWIDTH/realw;
double yratio = (double)SCREENHEIGHT/realh;
if (realw < w)
{
x = (x - (w - realw)/2)*xratio;
y *= yratio;
}
else
{
y = (y - (h - realh)/2)*yratio;
x *= xratio;
}
}
}
event.data1 = x; event.data1 = x;
event.data2 = y; event.data2 = y;
screen->ScaleCoordsFromWindow(event.data1, event.data2);
event.type = EV_GUI_Event; event.type = EV_GUI_Event;
if(sev.type == SDL_MOUSEMOTION) if(sev.type == SDL_MOUSEMOTION)
event.subtype = EV_GUI_MouseMove; event.subtype = EV_GUI_MouseMove;

View file

@ -240,7 +240,7 @@ int main (int argc, char **argv)
#if !defined (__APPLE__) #if !defined (__APPLE__)
{ {
int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS };
cc_install_handlers(argc, argv, 4, s, "zdoom-crash.log", DoomSpecificInfo); cc_install_handlers(argc, argv, 4, s, GAMENAMELOWERCASE "-crash.log", DoomSpecificInfo);
} }
#endif // !__APPLE__ #endif // !__APPLE__

View file

@ -50,6 +50,7 @@ public:
friend class SDLVideo; friend class SDLVideo;
virtual void SetVSync (bool vsync); virtual void SetVSync (bool vsync);
virtual void ScaleCoordsFromWindow(SWORD &x, SWORD &y);
private: private:
PalEntry SourcePalette[256]; PalEntry SourcePalette[256];
@ -723,6 +724,35 @@ void SDLFB::SetVSync (bool vsync)
#endif // __APPLE__ #endif // __APPLE__
} }
void SDLFB::ScaleCoordsFromWindow(SWORD &x, SWORD &y)
{
// Detect if we're doing scaling in the Window and adjust the mouse
// coordinates accordingly. This could be more efficent, but I
// don't think performance is an issue in the menus.
if(IsFullscreen())
{
int w, h;
SDL_GetWindowSize (Screen, &w, &h);
int realw = w, realh = h;
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
{
double xratio = (double)SCREENWIDTH/realw;
double yratio = (double)SCREENHEIGHT/realh;
if (realw < w)
{
x = (x - (w - realw)/2)*xratio;
y *= yratio;
}
else
{
y = (y - (h - realh)/2)*yratio;
x *= xratio;
}
}
}
}
ADD_STAT (blit) ADD_STAT (blit)
{ {
FString out; FString out;

View file

@ -633,6 +633,7 @@ struct sector_t
return pos == floor? floorplane:ceilingplane; return pos == floor? floorplane:ceilingplane;
} }
bool PlaneMoving(int pos); bool PlaneMoving(int pos);
@ -650,12 +651,9 @@ struct sector_t
TObjPtr<AActor> SoundTarget; TObjPtr<AActor> SoundTarget;
short special; short special;
short tag;
short lightlevel; short lightlevel;
short seqType; // this sector's sound sequence short seqType; // this sector's sound sequence
int nexttag,firsttag; // killough 1/30/98: improves searches for tags.
int sky; int sky;
FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this.
@ -890,11 +888,8 @@ struct line_t
DWORD activation; // activation type DWORD activation; // activation type
int special; int special;
fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) 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 args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
int firstid, nextid;
side_t *sidedef[2]; 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. fixed_t bbox[4]; // bounding box, for the extent of the LineDef.
sector_t *frontsector, *backsector; sector_t *frontsector, *backsector;
int validcount; // if == validcount, already checked int validcount; // if == validcount, already checked

View file

@ -84,7 +84,7 @@ void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache)
{ {
if (tex != NULL) if (tex != NULL)
{ {
if (cache & 1) if (cache & FTextureManager::HIT_Columnmode)
{ {
const FTexture::Span *spanp; const FTexture::Span *spanp;
tex->GetColumn(0, &spanp); tex->GetColumn(0, &spanp);

Some files were not shown because too many files have changed in this diff Show more