- Sync scriptbranch with trunk.

SVN r2269 (scripting)
This commit is contained in:
Randy Heit 2010-04-04 04:09:24 +00:00
commit 42ac75e894
127 changed files with 2567 additions and 994 deletions

View file

@ -1,5 +1,7 @@
cmake_minimum_required( VERSION 2.4 ) cmake_minimum_required( VERSION 2.4 )
include( CheckFunctionExists )
# DUMB is much slower in a Debug build than a Release build, so we force a Release # DUMB is much slower in a Debug build than a Release build, so we force a Release
# build here, since we're not maintaining DUMB, only using it. # build here, since we're not maintaining DUMB, only using it.
# Comment out the below line to allow Debug builds. # Comment out the below line to allow Debug builds.
@ -13,6 +15,11 @@ if( CMAKE_COMPILER_IS_GNUC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" )
endif( CMAKE_COMPILER_IS_GNUC ) endif( CMAKE_COMPILER_IS_GNUC )
CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS )
if( NOT ITOA_EXISTS )
add_definitions( -DNEED_ITOA=1 )
endif( NOT ITOA_EXISTS )
include_directories( include ) include_directories( include )
add_library( dumb add_library( dumb

View file

@ -58,7 +58,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
done = 0; done = 0;
dt = (int)(delta * 65536.0 + 0.5); dt = (int)(delta * 65536.0 + 0.5);
if (dt == 0) return 0; if (dt == 0 || dt == 0x80000000) return 0;
SET_VOLUME_VARIABLES; SET_VOLUME_VARIABLES;
if (VOLUMES_ARE_ZERO) dst = NULL; if (VOLUMES_ARE_ZERO) dst = NULL;

View file

@ -24,9 +24,6 @@
#include "internal/it.h" #include "internal/it.h"
#include "internal/riff.h" #include "internal/riff.h"
DUH *dumb_read_riff_amff( struct riff * stream );
DUH *dumb_read_riff_am( struct riff * stream );
static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver ) static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver )
{ {
int header_length; int header_length;

View file

@ -291,7 +291,7 @@ static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num,
if (channel >= chans) if (channel >= chans)
{ {
//channel = 0; //channel = 0;
goto error_fb; //goto error_fb;
} }
if (flags & 0x80) { if (flags & 0x80) {
if ((*ptr < 60) && (channel < pchans)) { if ((*ptr < 60) && (channel < pchans)) {

View file

@ -1271,7 +1271,11 @@ DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong)
if ( ver ) if ( ver )
{ {
tag[2][0] = "FORMATVERSION"; tag[2][0] = "FORMATVERSION";
#if NEED_ITOA
sprintf(version, "%d", ver); sprintf(version, "%d", ver);
#else
itoa(ver, version, 10);
#endif
tag[2][1] = (const char *) &version; tag[2][1] = (const char *) &version;
++n_tags; ++n_tags;
} }

1
specs/fmod_version.txt Normal file
View file

@ -0,0 +1 @@
This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive.

View file

@ -12,7 +12,7 @@ DEFINE_SPECIAL(Door_Close, 10, 2, 3, 3)
DEFINE_SPECIAL(Door_Open, 11, 2, 3, 3) DEFINE_SPECIAL(Door_Open, 11, 2, 3, 3)
DEFINE_SPECIAL(Door_Raise, 12, 3, 4, 4) DEFINE_SPECIAL(Door_Raise, 12, 3, 4, 4)
DEFINE_SPECIAL(Door_LockedRaise, 13, 4, 5, 5) DEFINE_SPECIAL(Door_LockedRaise, 13, 4, 5, 5)
DEFINE_SPECIAL(Door_Animated, 14, 3, 3, 3) DEFINE_SPECIAL(Door_Animated, 14, 4, 4, 4)
DEFINE_SPECIAL(Autosave, 15, 0, 0, 0) // [RH] Save the game *now* DEFINE_SPECIAL(Autosave, 15, 0, 0, 0) // [RH] Save the game *now*
DEFINE_SPECIAL(Transfer_WallLight, 16, -1, -1, 2) DEFINE_SPECIAL(Transfer_WallLight, 16, -1, -1, 2)
DEFINE_SPECIAL(Thing_Raise, 17, 1, 1, 1) DEFINE_SPECIAL(Thing_Raise, 17, 1, 1, 1)

View file

@ -552,9 +552,6 @@ public:
virtual void Tick (); virtual void Tick ();
// Smallest yaw interval for a mapthing to be spawned with
virtual angle_t AngleIncrements ();
// Called when actor dies // Called when actor dies
virtual void Die (AActor *source, AActor *inflictor); virtual void Die (AActor *source, AActor *inflictor);
@ -691,6 +688,31 @@ public:
return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist);
} }
PalEntry GetBloodColor() const
{
return GetClass()->BloodColor;
}
PClassActor *GetBloodType(int type = 0) const
{
if (type == 0)
{
return PClass::FindActor(GetClass()->BloodType);
}
else if (type == 1)
{
return PClass::FindActor(GetClass()->BloodType2);
}
else if (type == 2)
{
return PClass::FindActor(GetClass()->BloodType3);
}
else
{
return NULL;
}
}
// Calculate amount of missile damage // Calculate amount of missile damage
virtual int GetMissileDamage(int mask, int add); virtual int GetMissileDamage(int mask, int add);
@ -821,6 +843,7 @@ public:
FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used.
FSoundIDNoInit BounceSound; FSoundIDNoInit BounceSound;
FSoundIDNoInit WallBounceSound; FSoundIDNoInit WallBounceSound;
FSoundIDNoInit CrushPainSound;
fixed_t Speed; fixed_t Speed;
fixed_t FloatSpeed; fixed_t FloatSpeed;

View file

@ -1850,7 +1850,7 @@ void AM_drawPlayers ()
{ {
float h, s, v, r, g, b; float h, s, v, r, g, b;
D_GetPlayerColor (i, &h, &s, &v); D_GetPlayerColor (i, &h, &s, &v, NULL);
HSVtoRGB (&r, &g, &b, h, s, v); HSVtoRGB (&r, &g, &b, h, s, v);
color.FromRGB(clamp (int(r*255.f),0,255), clamp (int(g*255.f),0,255), clamp (int(b*255.f),0,255)); color.FromRGB(clamp (int(r*255.f),0,255), clamp (int(g*255.f),0,255), clamp (int(b*255.f),0,255));

View file

@ -118,7 +118,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
//in doom is 90 degrees infront. //in doom is 90 degrees infront.
bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle) bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle)
{ {
if (!P_CheckSight (from, to, 2)) if (!P_CheckSight (from, to, SF_SEEPASTBLOCKEVERYTHING))
return false; // out of sight return false; // out of sight
if (vangle == ANGLE_MAX) if (vangle == ANGLE_MAX)
return true; return true;
@ -339,7 +339,7 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
&& !p_leader[count]) //taken? && !p_leader[count]) //taken?
{ {
if (P_CheckSight (bot, client->mo, 1)) if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY))
{ {
test = P_AproxDistance (client->mo->x - bot->x, test = P_AproxDistance (client->mo->x - bot->x,
client->mo->y - bot->y); client->mo->y - bot->y);
@ -525,7 +525,7 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y); dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y);
//try the predicted location //try the predicted location
if (P_CheckSight (actor, bglobal.body1, 1)) //See the predicted location, so give a test missile if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
{ {
FCheckPosition tm; FCheckPosition tm;
if (SafeCheckPosition (bot, actor->x, actor->y, tm)) if (SafeCheckPosition (bot, actor->x, actor->y, tm))

View file

@ -788,8 +788,8 @@ CCMD(info)
AActor *linetarget; AActor *linetarget;
if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; if (CheckCheatmode () || players[consoleplayer].mo == NULL) return;
P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &linetarget, 0, P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE,
false, false, true); &linetarget, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART);
if (linetarget) if (linetarget)
{ {
Printf("Target=%s, Health=%d, Spawnhealth=%d\n", Printf("Target=%s, Health=%d, Spawnhealth=%d\n",
@ -924,6 +924,19 @@ CCMD(nextsecret)
} }
} }
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
CCMD(currentpos)
{
AActor *mo = players[consoleplayer].mo;
Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n",
FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// //

View file

@ -1035,6 +1035,32 @@ FString BuildString (int argc, char **argv)
} }
} }
FString BuildString (int argc, FString *argv)
{
if (argc == 1)
{
return *argv;
}
else
{
FString buf;
int arg;
for (arg = 0; arg < argc; arg++)
{
if (strchr (argv[arg], ' '))
{
buf << '"' << argv[arg] << "\" ";
}
else
{
buf << argv[arg] << ' ';
}
}
return buf;
}
}
//=========================================================================== //===========================================================================
// //
// SubstituteAliasParams // SubstituteAliasParams

View file

@ -59,6 +59,7 @@ void C_SetAlias (const char *name, const char *cmd);
// build a single string out of multiple strings // build a single string out of multiple strings
FString BuildString (int argc, char **argv); FString BuildString (int argc, char **argv);
FString BuildString (int argc, FString *argv);
// Class that can parse command lines // Class that can parse command lines
class FCommandLine class FCommandLine

View file

@ -148,17 +148,13 @@ int Q_filelength (FILE *f)
bool FileExists (const char *filename) bool FileExists (const char *filename)
{ {
FILE *f; struct stat buff;
// [RH] Empty filenames are never there // [RH] Empty filenames are never there
if (filename == NULL || *filename == 0) if (filename == NULL || *filename == 0)
return false; return false;
f = fopen (filename, "r"); return stat(filename, &buff) == 0 && !(buff.st_mode & S_IFDIR);
if (!f)
return false;
fclose (f);
return true;
} }
//========================================================================== //==========================================================================

View file

@ -2135,20 +2135,7 @@ static int PatchText (int oldSize)
if (!good) if (!good)
{ {
// search cluster text background flats (only if no user-defined MAPINFO is used!) DPrintf (" (Unmatched)\n");
if (strlen(newStr) <= 8 && Wads.CheckNumForName("MAPINFO") >= 0)
{
for (unsigned int i = 0; i < wadclusterinfos.Size(); i++)
{
if (!strcmp(wadclusterinfos[i].finaleflat, oldStr))
{
strcpy(wadclusterinfos[i].finaleflat, newStr);
good = true;
}
}
}
if (!good) DPrintf (" (Unmatched)\n");
} }
} }
@ -2904,6 +2891,12 @@ bool ADehackedPickup::TryPickup (AActor *&toucher)
RealPickup = static_cast<AInventory *>(Spawn (type, x, y, z, NO_REPLACE)); RealPickup = static_cast<AInventory *>(Spawn (type, x, y, z, NO_REPLACE));
if (RealPickup != NULL) if (RealPickup != NULL)
{ {
// The internally spawned item should never count towards statistics.
if (RealPickup->flags & MF_COUNTITEM)
{
RealPickup->flags &= ~MF_COUNTITEM;
level.total_items--;
}
if (!(flags & MF_DROPPED)) if (!(flags & MF_DROPPED))
{ {
RealPickup->flags &= ~MF_DROPPED; RealPickup->flags &= ~MF_DROPPED;

View file

@ -129,7 +129,7 @@ void D_CheckNetGame ();
void D_ProcessEvents (); void D_ProcessEvents ();
void G_BuildTiccmd (ticcmd_t* cmd); void G_BuildTiccmd (ticcmd_t* cmd);
void D_DoAdvanceDemo (); void D_DoAdvanceDemo ();
void D_AddWildFile (const char *pattern); void D_AddWildFile (TArray<FString> &wadfiles, const char *pattern);
// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
@ -657,6 +657,7 @@ void D_Display ()
switch (gamestate) switch (gamestate)
{ {
case GS_FULLCONSOLE: case GS_FULLCONSOLE:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0); screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false); hw2d = screen->Begin2D(false);
C_DrawConsole (false); C_DrawConsole (false);
@ -721,6 +722,7 @@ void D_Display ()
break; break;
case GS_INTERMISSION: case GS_INTERMISSION:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0); screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false); hw2d = screen->Begin2D(false);
WI_Drawer (); WI_Drawer ();
@ -728,6 +730,7 @@ void D_Display ()
break; break;
case GS_FINALE: case GS_FINALE:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0); screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false); hw2d = screen->Begin2D(false);
F_Drawer (); F_Drawer ();
@ -735,6 +738,7 @@ void D_Display ()
break; break;
case GS_DEMOSCREEN: case GS_DEMOSCREEN:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0); screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false); hw2d = screen->Begin2D(false);
D_PageDrawer (); D_PageDrawer ();
@ -1478,27 +1482,22 @@ static const char *BaseFileSearch (const char *file, const char *ext, bool lookf
// //
//========================================================================== //==========================================================================
bool ConsiderPatches (const char *arg, const char *ext) bool ConsiderPatches (const char *arg)
{ {
bool noDef = false; int i, argc;
DArgs *files = Args->GatherFiles (arg, ext, false); FString *args;
if (files->NumArgs() > 0)
{
int i;
const char *f; const char *f;
for (i = 0; i < files->NumArgs(); ++i) argc = Args->CheckParmList(arg, &args);
for (i = 0; i < argc; ++i)
{
if ( (f = BaseFileSearch(args[i], ".deh")) ||
(f = BaseFileSearch(args[i], ".bex")) )
{ {
if ( (f = BaseFileSearch (files->GetArg (i), ".deh")) )
D_LoadDehFile(f);
else if ( (f = BaseFileSearch (files->GetArg (i), ".bex")) )
D_LoadDehFile(f); D_LoadDehFile(f);
} }
noDef = true;
} }
files->Destroy(); return argc > 0;
return noDef;
} }
//========================================================================== //==========================================================================
@ -1591,40 +1590,18 @@ void D_MultiExec (DArgs *list, bool usePullin)
static void GetCmdLineFiles(TArray<FString> &wadfiles) static void GetCmdLineFiles(TArray<FString> &wadfiles)
{ {
DArgs *files = Args->GatherFiles ("-file", ".wad", true); FString *args;
DArgs *files1 = Args->GatherFiles (NULL, ".zip", false); int i, argc;
DArgs *files2 = Args->GatherFiles (NULL, ".pk3", false);
DArgs *files3 = Args->GatherFiles (NULL, ".txt", false); argc = Args->CheckParmList("-file", &args);
if (files->NumArgs() > 0 || files1->NumArgs() > 0 || files2->NumArgs() > 0 || files3->NumArgs() > 0) if ((gameinfo.flags & GI_SHAREWARE) && argc > 0)
{
// Check for -file in shareware
if (gameinfo.flags & GI_SHAREWARE)
{ {
I_FatalError ("You cannot -file with the shareware version. Register!"); I_FatalError ("You cannot -file with the shareware version. Register!");
} }
for (i = 0; i < argc; ++i)
// the files gathered are wadfile/lump names
for (int i = 0; i < files->NumArgs(); i++)
{ {
D_AddWildFile (wadfiles, files->GetArg (i)); D_AddWildFile(wadfiles, args[i]);
} }
for (int i = 0; i < files1->NumArgs(); i++)
{
D_AddWildFile (wadfiles, files1->GetArg (i));
}
for (int i = 0; i < files2->NumArgs(); i++)
{
D_AddWildFile (wadfiles, files2->GetArg (i));
}
for (int i = 0; i < files3->NumArgs(); i++)
{
D_AddWildFile (wadfiles, files3->GetArg (i));
}
}
files->Destroy();
files1->Destroy();
files2->Destroy();
files3->Destroy();
} }
static void CopyFiles(TArray<FString> &to, TArray<FString> &from) static void CopyFiles(TArray<FString> &to, TArray<FString> &from)
@ -1753,10 +1730,12 @@ static FString CheckGameInfo(TArray<FString> & pwads)
void D_DoomMain (void) void D_DoomMain (void)
{ {
int p, flags; int p, flags;
char *v; const char *v;
const char *wad; const char *wad;
DArgs *execFiles; DArgs *execFiles;
TArray<FString> pwads; TArray<FString> pwads;
FString *args;
int argcount;
// Set the FPU precision to 53 significant bits. This is the default // Set the FPU precision to 53 significant bits. This is the default
// for Visual C++, but not for GCC, so some slight math variances // for Visual C++, but not for GCC, so some slight math variances
@ -1775,6 +1754,13 @@ void D_DoomMain (void)
#endif #endif
#endif #endif
// Combine different file parameters with their pre-switch bits.
Args->CollectFiles("-deh", ".deh");
Args->CollectFiles("-bex", ".bex");
Args->CollectFiles("-exec", ".cfg");
Args->CollectFiles("-playdemo", ".lmp");
Args->CollectFiles("-file", NULL); // anythnig left goes after -file
PClass::StaticInit (); PClass::StaticInit ();
atterm (C_DeinitConsole); atterm (C_DeinitConsole);
@ -1861,16 +1847,21 @@ void D_DoomMain (void)
D_MultiExec (execFiles, true); D_MultiExec (execFiles, true);
// Run .cfg files at the start of the command line. // Run .cfg files at the start of the command line.
execFiles = Args->GatherFiles (NULL, ".cfg", false); execFiles = Args->GatherFiles ("-exec");
D_MultiExec (execFiles, true); D_MultiExec (execFiles, true);
C_ExecCmdLineParams (); // [RH] do all +set commands on the command line C_ExecCmdLineParams (); // [RH] do all +set commands on the command line
CopyFiles(allwads, pwads); CopyFiles(allwads, pwads);
// Since this function will never leave we must delete this array here manually.
pwads.Clear();
pwads.ShrinkToFit();
Printf ("W_Init: Init WADfiles.\n"); Printf ("W_Init: Init WADfiles.\n");
Wads.InitMultipleFiles (allwads); Wads.InitMultipleFiles (allwads);
allwads.Clear(); allwads.Clear();
allwads.ShrinkToFit();
// [RH] Initialize localizable strings. // [RH] Initialize localizable strings.
GStrings.LoadStrings (false); GStrings.LoadStrings (false);
@ -1963,21 +1954,23 @@ void D_DoomMain (void)
autostart = true; autostart = true;
} }
// [RH] Hack to handle +map // [RH] Hack to handle +map. The standard console command line handler
p = Args->CheckParm ("+map"); // won't be able to handle it, so we take it out of the command line and set
if (p && p < Args->NumArgs()-1) // it up like -warp.
FString mapvalue = Args->TakeValue("+map");
if (mapvalue.IsNotEmpty())
{ {
if (!P_CheckMapData(Args->GetArg (p+1))) if (!P_CheckMapData(mapvalue))
{ {
Printf ("Can't find map %s\n", Args->GetArg (p+1)); Printf ("Can't find map %s\n", mapvalue.GetChars());
} }
else else
{ {
startmap = Args->GetArg (p + 1); startmap = mapvalue;
Args->GetArg (p)[0] = '-';
autostart = true; autostart = true;
} }
} }
if (devparm) if (devparm)
{ {
Printf ("%s", GStrings("D_DEVSTR")); Printf ("%s", GStrings("D_DEVSTR"));
@ -1995,17 +1988,12 @@ void D_DoomMain (void)
#endif #endif
// turbo option // [RH] (now a cvar) // turbo option // [RH] (now a cvar)
v = Args->CheckValue("-turbo");
if (v != NULL)
{ {
UCVarValue value; double amt = atof(v);
static char one_hundred[] = "100"; Printf ("turbo scale: %.0f%%\n", amt);
turbo = (float)amt;
value.String = Args->CheckValue ("-turbo");
if (value.String == NULL)
value.String = one_hundred;
else
Printf ("turbo scale: %s%%\n", value.String);
turbo.SetGenericRepDefault (value, CVAR_String);
} }
v = Args->CheckValue ("-timer"); v = Args->CheckValue ("-timer");
@ -2039,6 +2027,9 @@ void D_DoomMain (void)
StartScreen->AppendStatusLine(temp); StartScreen->AppendStatusLine(temp);
} }
// [RH] Load sound environments
S_ParseReverbDef ();
// [RH] Parse through all loaded mapinfo lumps // [RH] Parse through all loaded mapinfo lumps
Printf ("G_ParseMapInfo: Load map definitions.\n"); Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo (iwad_info->MapInfo); G_ParseMapInfo (iwad_info->MapInfo);
@ -2047,7 +2038,6 @@ void D_DoomMain (void)
Printf ("S_InitData: Load sound definitions.\n"); Printf ("S_InitData: Load sound definitions.\n");
S_InitData (); S_InitData ();
Printf ("Texman.Init: Init texture manager.\n"); Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init(); TexMan.Init();
@ -2083,7 +2073,7 @@ void D_DoomMain (void)
// If there are none, try adding any in the config file. // If there are none, try adding any in the config file.
// Note that the command line overrides defaults from the config. // Note that the command line overrides defaults from the config.
if ((ConsiderPatches("-deh", ".deh") | ConsiderPatches("-bex", ".bex")) == 0 && if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 &&
gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked"))
{ {
const char *key; const char *key;
@ -2121,10 +2111,10 @@ void D_DoomMain (void)
} }
//Added by MC: //Added by MC:
DArgs *bots = Args->GatherFiles("-bots", "", false); argcount = Args->CheckParmList("-bots", &args);
for (p = 0; p < bots->NumArgs(); ++p) for (p = 0; p < argcount; ++p)
{ {
bglobal.getspawned.Push(bots->GetArg(p)); bglobal.getspawned.Push(args[p]);
} }
bglobal.spawn_tries = 0; bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size(); bglobal.wanted_botnum = bglobal.getspawned.Size();
@ -2174,14 +2164,13 @@ void D_DoomMain (void)
V_Init2(); V_Init2();
DArgs *files = Args->GatherFiles ("-playdemo", ".lmp", false); v = Args->CheckValue("-playdemo");
if (files->NumArgs() > 0) if (v != NULL)
{ {
singledemo = true; // quit after one demo singledemo = true; // quit after one demo
G_DeferedPlayDemo (files->GetArg (0)); G_DeferedPlayDemo (v);
D_DoomLoop (); // never returns D_DoomLoop (); // never returns
} }
files->Destroy();
v = Args->CheckValue ("-timedemo"); v = Args->CheckValue ("-timedemo");
if (v) if (v)

View file

@ -54,7 +54,8 @@ void D_DoServerInfoChange (BYTE **stream, bool singlebit);
void D_WriteUserInfoStrings (int player, BYTE **stream, bool compact=false); void D_WriteUserInfoStrings (int player, BYTE **stream, bool compact=false);
void D_ReadUserInfoStrings (int player, BYTE **stream, bool update); void D_ReadUserInfoStrings (int player, BYTE **stream, bool update);
void D_GetPlayerColor (int player, float *h, float *s, float *v); struct FPlayerColorSet;
void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **colorset);
void D_PickRandomTeam (int player); void D_PickRandomTeam (int player);
int D_PickRandomTeam (); int D_PickRandomTeam ();
class player_t; class player_t;

View file

@ -65,6 +65,7 @@ EXTERN_CVAR (Bool, teamplay)
CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Int, colorset, 0, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, skin, "base", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, skin, "base", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE);
@ -85,6 +86,7 @@ enum
INFO_MoveBob, INFO_MoveBob,
INFO_StillBob, INFO_StillBob,
INFO_PlayerClass, INFO_PlayerClass,
INFO_ColorSet,
}; };
const char *GenderNames[3] = { "male", "female", "other" }; const char *GenderNames[3] = { "male", "female", "other" };
@ -101,6 +103,7 @@ static const char *UserInfoStrings[] =
"movebob", "movebob",
"stillbob", "stillbob",
"playerclass", "playerclass",
"colorset",
NULL NULL
}; };
@ -184,10 +187,24 @@ int D_PlayerClassToInt (const char *classname)
} }
} }
void D_GetPlayerColor (int player, float *h, float *s, float *v) void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **set)
{ {
userinfo_t *info = &players[player].userinfo; userinfo_t *info = &players[player].userinfo;
int color = info->color; FPlayerColorSet *colorset = NULL;
int color;
if (players[player].mo != NULL)
{
colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->colorset);
}
if (colorset != NULL)
{
color = GPalette.BaseColors[GPalette.Remap[colorset->RepresentativeColor]];
}
else
{
color = info->color;
}
RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f,
h, s, v); h, s, v);
@ -206,6 +223,10 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v)
*s = clamp(ts + *s * 0.15f - 0.075f, 0.f, 1.f); *s = clamp(ts + *s * 0.15f - 0.075f, 0.f, 1.f);
*v = clamp(tv + *v * 0.5f - 0.25f, 0.f, 1.f); *v = clamp(tv + *v * 0.5f - 0.25f, 0.f, 1.f);
} }
if (set != NULL)
{
*set = colorset;
}
} }
// Find out which teams are present. If there is only one, // Find out which teams are present. If there is only one,
@ -379,6 +400,7 @@ void D_SetupUserInfo ()
coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1)); coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1));
} }
coninfo->color = color; coninfo->color = color;
coninfo->colorset = colorset;
coninfo->skin = R_FindSkin (skin, 0); coninfo->skin = R_FindSkin (skin, 0);
coninfo->gender = D_GenderToInt (gender); coninfo->gender = D_GenderToInt (gender);
coninfo->neverswitch = neverswitchonpickup; coninfo->neverswitch = neverswitchonpickup;
@ -564,6 +586,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
"\\name\\%s" "\\name\\%s"
"\\autoaim\\%g" "\\autoaim\\%g"
"\\color\\%x %x %x" "\\color\\%x %x %x"
"\\colorset\\%d"
"\\skin\\%s" "\\skin\\%s"
"\\team\\%d" "\\team\\%d"
"\\gender\\%s" "\\gender\\%s"
@ -574,6 +597,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
, ,
D_EscapeUserInfo(info->netname).GetChars(), D_EscapeUserInfo(info->netname).GetChars(),
(double)info->aimdist / (float)ANGLE_1, (double)info->aimdist / (float)ANGLE_1,
info->colorset,
RPART(info->color), GPART(info->color), BPART(info->color), RPART(info->color), GPART(info->color), BPART(info->color),
D_EscapeUserInfo(skins[info->skin].name).GetChars(), D_EscapeUserInfo(skins[info->skin].name).GetChars(),
info->team, info->team,
@ -599,6 +623,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
"\\%g" // movebob "\\%g" // movebob
"\\%g" // stillbob "\\%g" // stillbob
"\\%s" // playerclass "\\%s" // playerclass
"\\%d" // colorset
, ,
D_EscapeUserInfo(info->netname).GetChars(), D_EscapeUserInfo(info->netname).GetChars(),
(double)info->aimdist / (float)ANGLE_1, (double)info->aimdist / (float)ANGLE_1,
@ -610,7 +635,8 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
info->neverswitch, info->neverswitch,
(float)(info->MoveBob) / 65536.f, (float)(info->MoveBob) / 65536.f,
(float)(info->StillBob) / 65536.f, (float)(info->StillBob) / 65536.f,
info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars() info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars(),
info->colorset
); );
} }
} }
@ -714,7 +740,15 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
break; break;
case INFO_Color: case INFO_Color:
case INFO_ColorSet:
if (infotype == INFO_Color)
{
info->color = V_GetColorFromString (NULL, value); info->color = V_GetColorFromString (NULL, value);
}
else
{
info->colorset = atoi(value);
}
R_BuildPlayerTranslation (i); R_BuildPlayerTranslation (i);
if (StatusBar != NULL && i == StatusBar->GetPlayer()) if (StatusBar != NULL && i == StatusBar->GetPlayer())
{ {
@ -804,6 +838,10 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info)
arc.Read (&info.netname, sizeof(info.netname)); arc.Read (&info.netname, sizeof(info.netname));
} }
arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch; arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch;
if (SaveVersion >= 2193)
{
arc << info.colorset;
}
return arc; return arc;
} }
@ -829,6 +867,7 @@ CCMD (playerinfo)
Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team); Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team);
Printf ("Aimdist: %d\n", ui->aimdist); Printf ("Aimdist: %d\n", ui->aimdist);
Printf ("Color: %06x\n", ui->color); Printf ("Color: %06x\n", ui->color);
Printf ("ColorSet: %d\n", ui->colorset);
Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin); Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin);
Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender); Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender);
Printf ("NeverSwitch: %d\n", ui->neverswitch); Printf ("NeverSwitch: %d\n", ui->neverswitch);

View file

@ -65,6 +65,11 @@ public:
BYTE ColorRangeEnd; BYTE ColorRangeEnd;
}; };
FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum);
void P_EnumPlayerColorSets(FName classname, TArray<int> *out);
class player_t;
class APlayerPawn : public AActor class APlayerPawn : public AActor
{ {
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
@ -215,6 +220,7 @@ struct userinfo_t
BYTE team; BYTE team;
int aimdist; int aimdist;
int color; int color;
int colorset;
int skin; int skin;
int gender; int gender;
bool neverswitch; bool neverswitch;

View file

@ -227,10 +227,10 @@ struct mapseg_t
{ {
WORD v1; WORD v1;
WORD v2; WORD v2;
short angle; SWORD angle;
WORD linedef; WORD linedef;
short side; SWORD side;
short offset; SWORD offset;
}; };
@ -242,11 +242,11 @@ struct mapseg_t
struct mapnode_t struct mapnode_t
{ {
short x,y,dx,dy; // partition line SWORD x,y,dx,dy; // partition line
short bbox[2][4]; // bounding box for each child SWORD bbox[2][4]; // bounding box for each child
// If NF_SUBSECTOR is or'ed in, it's a subsector, // If NF_SUBSECTOR is or'ed in, it's a subsector,
// else it's a node of another subtree. // else it's a node of another subtree.
unsigned short children[2]; WORD children[2];
}; };
@ -256,23 +256,23 @@ struct mapnode_t
// plus skill/visibility flags and attributes. // plus skill/visibility flags and attributes.
struct mapthing_t struct mapthing_t
{ {
short x; SWORD x;
short y; SWORD y;
short angle; SWORD angle;
short type; SWORD type;
short options; SWORD options;
}; };
// [RH] Hexen-compatible MapThing. // [RH] Hexen-compatible MapThing.
struct mapthinghexen_t struct mapthinghexen_t
{ {
unsigned short thingid; SWORD thingid;
short x; SWORD x;
short y; SWORD y;
short z; SWORD z;
short angle; SWORD angle;
short type; SWORD type;
short flags; SWORD flags;
BYTE special; BYTE special;
BYTE args[5]; BYTE args[5];
}; };

View file

@ -117,6 +117,10 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int
} }
FinaleFlat = (flat != NULL && *flat != 0) ? flat : gameinfo.finaleFlat; FinaleFlat = (flat != NULL && *flat != 0) ? flat : gameinfo.finaleFlat;
if (FinaleFlat != NULL && FinaleFlat[0] == '$')
{
FinaleFlat = GStrings(FinaleFlat + 1);
}
if (textInLump) if (textInLump)
{ {
@ -758,7 +762,7 @@ void F_CastDrawer (void)
FTexture* pic; FTexture* pic;
// erase the entire screen to a background // erase the entire screen to a background
screen->DrawTexture (TexMan["BOSSBACK"], 0, 0, screen->DrawTexture (TexMan[GStrings("bgcastcall")], 0, 0,
DTA_DestWidth, screen->GetWidth(), DTA_DestWidth, screen->GetWidth(),
DTA_DestHeight, screen->GetHeight(), DTA_DestHeight, screen->GetHeight(),
TAG_DONE); TAG_DONE);

View file

@ -126,7 +126,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire)
if (!self->target if (!self->target
|| P_HitFriend (self) || P_HitFriend (self)
|| self->target->health <= 0 || self->target->health <= 0
|| !P_CheckSight (self, self->target, 0) ) || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
{ {
self->SetState (self->SeeState); self->SetState (self->SeeState);
} }

View file

@ -24,7 +24,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire)
if (!self->target if (!self->target
|| P_HitFriend (self) || P_HitFriend (self)
|| self->target->health <= 0 || self->target->health <= 0
|| !P_CheckSight (self, self->target, 0) ) || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
{ {
self->SetState (self->SeeState); self->SetState (self->SeeState);
} }

View file

@ -2192,18 +2192,14 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf)
// //
// G_RecordDemo // G_RecordDemo
// //
void G_RecordDemo (char* name) void G_RecordDemo (const char* name)
{ {
char *v;
usergame = false; usergame = false;
strcpy (demoname, name); strcpy (demoname, name);
FixPathSeperator (demoname); FixPathSeperator (demoname);
DefaultExtension (demoname, ".lmp"); DefaultExtension (demoname, ".lmp");
v = Args->CheckValue ("-maxdemo");
maxdemosize = 0x20000; maxdemosize = 0x20000;
demobuffer = (BYTE *)M_Malloc (maxdemosize); demobuffer = (BYTE *)M_Malloc (maxdemosize);
demorecording = true; demorecording = true;
} }
@ -2288,7 +2284,7 @@ void G_BeginRecording (const char *startmap)
FString defdemoname; FString defdemoname;
void G_DeferedPlayDemo (char *name) void G_DeferedPlayDemo (const char *name)
{ {
defdemoname = name; defdemoname = name;
gameaction = ga_playdemo; gameaction = ga_playdemo;
@ -2516,7 +2512,7 @@ void G_DoPlayDemo (void)
// //
// G_TimeDemo // G_TimeDemo
// //
void G_TimeDemo (char* name) void G_TimeDemo (const char* name)
{ {
nodrawers = !!Args->CheckParm ("-nodraw"); nodrawers = !!Args->CheckParm ("-nodraw");
noblit = !!Args->CheckParm ("-noblit"); noblit = !!Args->CheckParm ("-noblit");

View file

@ -32,7 +32,7 @@ struct PNGHandle;
// //
void G_DeathMatchSpawnPlayer (int playernum); void G_DeathMatchSpawnPlayer (int playernum);
void G_DeferedPlayDemo (char* demo); void G_DeferedPlayDemo (const char* demo);
// Can be called by the startup code or M_Responder, // Can be called by the startup code or M_Responder,
// calls P_SetupLevel or W_EnterWorld. // calls P_SetupLevel or W_EnterWorld.
@ -44,12 +44,12 @@ void G_DoLoadGame (void);
void G_SaveGame (const char *filename, const char *description); void G_SaveGame (const char *filename, const char *description);
// Only called by startup code. // Only called by startup code.
void G_RecordDemo (char* name); void G_RecordDemo (const char* name);
void G_BeginRecording (const char *startmap); void G_BeginRecording (const char *startmap);
void G_PlayDemo (char* name); void G_PlayDemo (char* name);
void G_TimeDemo (char* name); void G_TimeDemo (const char* name);
bool G_CheckDemoStatus (void); bool G_CheckDemoStatus (void);
void G_WorldDone (void); void G_WorldDone (void);

View file

@ -69,7 +69,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
angle = pmo->angle+i*(ANG45/16); angle = pmo->angle+i*(ANG45/16);
slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff"));
@ -93,7 +93,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
break; break;
} }
angle = pmo->angle-i*(ANG45/16); angle = pmo->angle-i*(ANG45/16);
slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff"));

View file

@ -50,7 +50,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
angle = pmo->angle + i*(ANG45/32); angle = pmo->angle + i*(ANG45/32);
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true);
@ -63,7 +63,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
goto hammerdone; goto hammerdone;
} }
angle = pmo->angle-i*(ANG45/32); angle = pmo->angle-i*(ANG45/32);
slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
if(linetarget) if(linetarget)
{ {
P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true);
@ -78,7 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
} }
// didn't find any targets in meleerange, so set to throw out a hammer // didn't find any targets in meleerange, so set to throw out a hammer
angle = pmo->angle; angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL)
{ {
pmo->special1 = false; pmo->special1 = false;

View file

@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1)
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
angle = self->angle+i*(ANG45/16); angle = self->angle+i*(ANG45/16);
slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, false, true); slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, ALF_CHECK3D);
if (linetarget) if (linetarget)
{ {
P_DamageMobj (linetarget, self, self, damage, NAME_Ice); P_DamageMobj (linetarget, self, self, damage, NAME_Ice);

View file

@ -572,7 +572,7 @@ void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nex
if (strncmp(levelname, "enDSeQ", 6) != 0) if (strncmp(levelname, "enDSeQ", 6) != 0)
{ {
nextinfo = FindLevelInfo (nextlevel); nextinfo = FindLevelInfo (levelname);
if (nextinfo != NULL) if (nextinfo != NULL)
{ {
level_info_t *nextredir = nextinfo->CheckLevelRedirect(); level_info_t *nextredir = nextinfo->CheckLevelRedirect();
@ -1039,7 +1039,7 @@ void G_WorldDone (void)
{ {
F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder, F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder,
thiscluster->cdtrack, thiscluster->cdid, thiscluster->cdtrack, thiscluster->cdid,
thiscluster->finaleflat, thiscluster->ExitText, thiscluster->FinaleFlat, thiscluster->ExitText,
thiscluster->flags & CLUSTER_EXITTEXTINLUMP, thiscluster->flags & CLUSTER_EXITTEXTINLUMP,
thiscluster->flags & CLUSTER_FINALEPIC, thiscluster->flags & CLUSTER_FINALEPIC,
thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, thiscluster->flags & CLUSTER_LOOKUPEXITTEXT,
@ -1057,7 +1057,7 @@ void G_WorldDone (void)
{ {
F_StartFinale (nextcluster->MessageMusic, nextcluster->musicorder, F_StartFinale (nextcluster->MessageMusic, nextcluster->musicorder,
nextcluster->cdtrack, nextcluster->cdid, nextcluster->cdtrack, nextcluster->cdid,
nextcluster->finaleflat, nextcluster->EnterText, nextcluster->FinaleFlat, nextcluster->EnterText,
nextcluster->flags & CLUSTER_ENTERTEXTINLUMP, nextcluster->flags & CLUSTER_ENTERTEXTINLUMP,
nextcluster->flags & CLUSTER_FINALEPIC, nextcluster->flags & CLUSTER_FINALEPIC,
nextcluster->flags & CLUSTER_LOOKUPENTERTEXT, nextcluster->flags & CLUSTER_LOOKUPENTERTEXT,
@ -1067,7 +1067,7 @@ void G_WorldDone (void)
{ {
F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder, F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder,
thiscluster->cdtrack, nextcluster->cdid, thiscluster->cdtrack, nextcluster->cdid,
thiscluster->finaleflat, thiscluster->ExitText, thiscluster->FinaleFlat, thiscluster->ExitText,
thiscluster->flags & CLUSTER_EXITTEXTINLUMP, thiscluster->flags & CLUSTER_EXITTEXTINLUMP,
thiscluster->flags & CLUSTER_FINALEPIC, thiscluster->flags & CLUSTER_FINALEPIC,
thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, thiscluster->flags & CLUSTER_LOOKUPEXITTEXT,
@ -1319,6 +1319,8 @@ void G_InitLevelLocals ()
compatflags.Callback(); compatflags.Callback();
NormalLight.ChangeFade (level.fadeto); NormalLight.ChangeFade (level.fadeto);
level.DefaultEnvironment = info->DefaultEnvironment;
} }
//========================================================================== //==========================================================================

View file

@ -66,15 +66,16 @@ struct FMapInfoParser
int format_type; int format_type;
bool HexenHack; bool HexenHack;
FMapInfoParser() FMapInfoParser(int format = FMT_Unknown)
{ {
format_type = FMT_Unknown; format_type = format;
HexenHack = false; HexenHack = false;
} }
bool ParseLookupName(FString &dest); bool ParseLookupName(FString &dest);
void ParseMusic(FString &name, int &order); void ParseMusic(FString &name, int &order);
void ParseLumpOrTextureName(char *name); void ParseLumpOrTextureName(char *name);
void ParseLumpOrTextureName(FString &name);
void ParseCluster(); void ParseCluster();
void ParseNextMap(char *mapname); void ParseNextMap(char *mapname);
@ -276,6 +277,7 @@ struct level_info_t
DWORD compatflags; DWORD compatflags;
DWORD compatmask; DWORD compatmask;
FString Translator; // for converting Doom-format linedef and sector types. FString Translator; // for converting Doom-format linedef and sector types.
int DefaultEnvironment; // Default sound environment for the map.
// Redirection: If any player is carrying the specified item, then // Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one. // you go to the RedirectMap instead of this one.
@ -388,6 +390,7 @@ struct FLevelLocals
fixed_t aircontrol; fixed_t aircontrol;
fixed_t airfriction; fixed_t airfriction;
int airsupply; int airsupply;
int DefaultEnvironment; // Default sound environment.
FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level
@ -437,7 +440,7 @@ extern TArray<EndSequence> EndSequences;
struct cluster_info_t struct cluster_info_t
{ {
int cluster; int cluster;
char finaleflat[9]; FString FinaleFlat;
FString ExitText; FString ExitText;
FString EnterText; FString EnterText;
FString MessageMusic; FString MessageMusic;

View file

@ -265,6 +265,7 @@ void level_info_t::Reset()
bordertexture[0] = 0; bordertexture[0] = 0;
teamdamage = 0.f; teamdamage = 0.f;
specialactions.Clear(); specialactions.Clear();
DefaultEnvironment = 0;
} }
@ -389,7 +390,7 @@ bool level_info_t::isValid()
void cluster_info_t::Reset() void cluster_info_t::Reset()
{ {
cluster = 0; cluster = 0;
finaleflat[0] = 0; FinaleFlat = "";
ExitText = ""; ExitText = "";
EnterText = ""; EnterText = "";
MessageMusic = ""; MessageMusic = "";
@ -615,6 +616,12 @@ void FMapInfoParser::ParseLumpOrTextureName(char *name)
name[8]=0; name[8]=0;
} }
void FMapInfoParser::ParseLumpOrTextureName(FString &name)
{
sc.MustGetString();
name = sc.String;
}
//========================================================================== //==========================================================================
// //
@ -691,12 +698,12 @@ void FMapInfoParser::ParseCluster()
else if (sc.Compare("flat")) else if (sc.Compare("flat"))
{ {
ParseAssign(); ParseAssign();
ParseLumpOrTextureName(clusterinfo->finaleflat); ParseLumpOrTextureName(clusterinfo->FinaleFlat);
} }
else if (sc.Compare("pic")) else if (sc.Compare("pic"))
{ {
ParseAssign(); ParseAssign();
ParseLumpOrTextureName(clusterinfo->finaleflat); ParseLumpOrTextureName(clusterinfo->FinaleFlat);
clusterinfo->flags |= CLUSTER_FINALEPIC; clusterinfo->flags |= CLUSTER_FINALEPIC;
} }
else if (sc.Compare("hub")) else if (sc.Compare("hub"))
@ -1244,6 +1251,36 @@ DEFINE_MAP_OPTION(mapbackground, true)
parse.ParseLumpOrTextureName(info->mapbg); parse.ParseLumpOrTextureName(info->mapbg);
} }
DEFINE_MAP_OPTION(defaultenvironment, false)
{
int id;
parse.ParseAssign();
if (parse.sc.CheckNumber())
{ // Numeric ID XXX [, YYY]
id = parse.sc.Number << 8;
if (parse.CheckNumber())
{
id |= parse.sc.Number;
}
}
else
{ // Named environment
parse.sc.MustGetString();
ReverbContainer *reverb = S_FindEnvironment(parse.sc.String);
if (reverb == NULL)
{
parse.sc.ScriptMessage("Unknown sound environment '%s'\n", parse.sc.String);
id = 0;
}
else
{
id = reverb->ID;
}
}
info->DefaultEnvironment = id;
}
//========================================================================== //==========================================================================
// //
@ -1923,10 +1960,23 @@ void G_ParseMapInfo (const char *basemapinfo)
parse.ParseMapInfo(Wads.GetNumForFullName(basemapinfo), gamedefaults, defaultinfo); parse.ParseMapInfo(Wads.GetNumForFullName(basemapinfo), gamedefaults, defaultinfo);
} }
static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", NULL };
int nindex;
// Parse any extra MAPINFOs. // Parse any extra MAPINFOs.
while ((lump = Wads.FindLump ("MAPINFO", &lastlump)) != -1) while ((lump = Wads.FindLumpMulti (mapinfonames, &lastlump, false, &nindex)) != -1)
{ {
FMapInfoParser parse; if (nindex == 0)
{
// If this lump is named MAPINFO we need to check if the same WAD contains a ZMAPINFO lump.
// If that exists we need to skip this one.
int wad = Wads.GetLumpFile(lump);
int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true);
if (altlump >= 0) continue;
}
FMapInfoParser parse(nindex == 1? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown);
level_info_t defaultinfo; level_info_t defaultinfo;
parse.ParseMapInfo(lump, gamedefaults, defaultinfo); parse.ParseMapInfo(lump, gamedefaults, defaultinfo);
} }

View file

@ -193,6 +193,12 @@ void APowerup::DoEffect ()
void APowerup::EndEffect () void APowerup::EndEffect ()
{ {
int colormap = GetSpecialColormap(BlendColor);
if (colormap != NOFIXEDCOLORMAP && Owner && Owner->player && Owner->player->fixedcolormap == colormap)
{ // only unset if the fixed colormap comes from this item
Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
}
} }
//=========================================================================== //===========================================================================
@ -347,6 +353,7 @@ IMPLEMENT_CLASS (APowerInvulnerable)
void APowerInvulnerable::InitEffect () void APowerInvulnerable::InitEffect ()
{ {
Super::InitEffect();
Owner->effects &= ~FX_RESPAWNINVUL; Owner->effects &= ~FX_RESPAWNINVUL;
Owner->flags2 |= MF2_INVULNERABLE; Owner->flags2 |= MF2_INVULNERABLE;
if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
@ -421,6 +428,8 @@ void APowerInvulnerable::DoEffect ()
void APowerInvulnerable::EndEffect () void APowerInvulnerable::EndEffect ()
{ {
Super::EndEffect();
if (Owner == NULL) if (Owner == NULL)
{ {
return; return;
@ -498,6 +507,7 @@ bool APowerStrength::HandlePickup (AInventory *item)
void APowerStrength::InitEffect () void APowerStrength::InitEffect ()
{ {
Super::InitEffect();
} }
//=========================================================================== //===========================================================================
@ -537,7 +547,6 @@ PalEntry APowerStrength::GetBlend ()
// Invisibility Powerup ------------------------------------------------------ // Invisibility Powerup ------------------------------------------------------
IMPLEMENT_CLASS (APowerInvisibility) IMPLEMENT_CLASS (APowerInvisibility)
IMPLEMENT_CLASS (APowerShadow)
// Invisibility flag combos // Invisibility flag combos
#define INVISIBILITY_FLAGS1 (MF_SHADOW) #define INVISIBILITY_FLAGS1 (MF_SHADOW)
@ -552,6 +561,7 @@ IMPLEMENT_CLASS (APowerShadow)
void APowerInvisibility::InitEffect () void APowerInvisibility::InitEffect ()
{ {
Super::InitEffect();
// This used to call CommonInit(), which used to contain all the code that's repeated every // This used to call CommonInit(), which used to contain all the code that's repeated every
// tic, plus the following code that needs to happen once and only once. // tic, plus the following code that needs to happen once and only once.
// The CommonInit() code has been moved to DoEffect(), so this now ends with a call to DoEffect(), // The CommonInit() code has been moved to DoEffect(), so this now ends with a call to DoEffect(),
@ -615,6 +625,7 @@ void APowerInvisibility::DoEffect ()
void APowerInvisibility::EndEffect () void APowerInvisibility::EndEffect ()
{ {
Super::EndEffect();
if (Owner != NULL) if (Owner != NULL)
{ {
Owner->flags &= ~(flags & INVISIBILITY_FLAGS1); Owner->flags &= ~(flags & INVISIBILITY_FLAGS1);
@ -822,6 +833,7 @@ void APowerLightAmp::DoEffect ()
void APowerLightAmp::EndEffect () void APowerLightAmp::EndEffect ()
{ {
Super::EndEffect();
if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS)
{ {
Owner->player->fixedlightlevel = -1; Owner->player->fixedlightlevel = -1;
@ -914,6 +926,7 @@ void APowerFlight::Serialize (FArchive &arc)
void APowerFlight::InitEffect () void APowerFlight::InitEffect ()
{ {
Super::InitEffect();
Owner->flags2 |= MF2_FLY; Owner->flags2 |= MF2_FLY;
Owner->flags |= MF_NOGRAVITY; Owner->flags |= MF_NOGRAVITY;
if (Owner->z <= Owner->floorz) if (Owner->z <= Owner->floorz)
@ -955,6 +968,7 @@ void APowerFlight::Tick ()
void APowerFlight::EndEffect () void APowerFlight::EndEffect ()
{ {
Super::EndEffect();
if (Owner == NULL || Owner->player == NULL) if (Owner == NULL || Owner->player == NULL)
{ {
return; return;
@ -1035,6 +1049,8 @@ void APowerWeaponLevel2::InitEffect ()
{ {
AWeapon *weapon, *sister; AWeapon *weapon, *sister;
Super::InitEffect();
if (Owner->player == NULL) if (Owner->player == NULL)
return; return;
@ -1071,6 +1087,7 @@ void APowerWeaponLevel2::EndEffect ()
{ {
player_t *player = Owner != NULL ? Owner->player : NULL; player_t *player = Owner != NULL ? Owner->player : NULL;
Super::EndEffect();
if (player != NULL) if (player != NULL)
{ {
@ -1199,6 +1216,8 @@ void APowerTargeter::InitEffect ()
{ {
player_t *player; player_t *player;
Super::InitEffect();
if ((player = Owner->player) == NULL) if ((player = Owner->player) == NULL)
return; return;
@ -1250,6 +1269,7 @@ void APowerTargeter::DoEffect ()
void APowerTargeter::EndEffect () void APowerTargeter::EndEffect ()
{ {
Super::EndEffect();
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
P_SetPsprite (Owner->player, ps_targetcenter, NULL); P_SetPsprite (Owner->player, ps_targetcenter, NULL);
@ -1281,6 +1301,8 @@ IMPLEMENT_CLASS (APowerFrightener)
void APowerFrightener::InitEffect () void APowerFrightener::InitEffect ()
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1295,6 +1317,8 @@ void APowerFrightener::InitEffect ()
void APowerFrightener::EndEffect () void APowerFrightener::EndEffect ()
{ {
Super::EndEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1319,6 +1343,8 @@ void APowerTimeFreezer::InitEffect( )
{ {
int ulIdx; int ulIdx;
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1394,6 +1420,8 @@ void APowerTimeFreezer::EndEffect( )
{ {
int ulIdx; int ulIdx;
Super::EndEffect();
// Allow other actors to move about freely once again. // Allow other actors to move about freely once again.
level.flags2 &= ~LEVEL2_FROZEN; level.flags2 &= ~LEVEL2_FROZEN;
@ -1432,6 +1460,8 @@ IMPLEMENT_CLASS( APowerDamage)
void APowerDamage::InitEffect( ) void APowerDamage::InitEffect( )
{ {
Super::InitEffect();
// Use sound channel 5 to avoid interference with other actions. // Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_Sound(Owner, 5, SeeSound, 1.0f, ATTN_NONE); if (Owner != NULL) S_Sound(Owner, 5, SeeSound, 1.0f, ATTN_NONE);
} }
@ -1444,6 +1474,7 @@ void APowerDamage::InitEffect( )
void APowerDamage::EndEffect( ) void APowerDamage::EndEffect( )
{ {
Super::EndEffect();
// Use sound channel 5 to avoid interference with other actions. // Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_Sound(Owner, 5, DeathSound, 1.0f, ATTN_NONE); if (Owner != NULL) S_Sound(Owner, 5, DeathSound, 1.0f, ATTN_NONE);
} }
@ -1495,6 +1526,8 @@ IMPLEMENT_CLASS(APowerProtection)
void APowerProtection::InitEffect( ) void APowerProtection::InitEffect( )
{ {
Super::InitEffect();
if (Owner != NULL) if (Owner != NULL)
{ {
S_Sound(Owner, CHAN_AUTO, SeeSound, 1.0f, ATTN_NONE); S_Sound(Owner, CHAN_AUTO, SeeSound, 1.0f, ATTN_NONE);
@ -1518,6 +1551,7 @@ void APowerProtection::InitEffect( )
void APowerProtection::EndEffect( ) void APowerProtection::EndEffect( )
{ {
Super::EndEffect();
if (Owner != NULL) if (Owner != NULL)
{ {
S_Sound(Owner, CHAN_AUTO, DeathSound, 1.0f, ATTN_NONE); S_Sound(Owner, CHAN_AUTO, DeathSound, 1.0f, ATTN_NONE);
@ -1570,6 +1604,8 @@ IMPLEMENT_CLASS(APowerDrain)
void APowerDrain::InitEffect( ) void APowerDrain::InitEffect( )
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1585,6 +1621,8 @@ void APowerDrain::InitEffect( )
void APowerDrain::EndEffect( ) void APowerDrain::EndEffect( )
{ {
Super::EndEffect();
// Nothing to do if there's no owner. // Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
@ -1606,6 +1644,8 @@ IMPLEMENT_CLASS(APowerRegeneration)
void APowerRegeneration::InitEffect( ) void APowerRegeneration::InitEffect( )
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1621,6 +1661,7 @@ void APowerRegeneration::InitEffect( )
void APowerRegeneration::EndEffect( ) void APowerRegeneration::EndEffect( )
{ {
Super::EndEffect();
// Nothing to do if there's no owner. // Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
@ -1641,6 +1682,8 @@ IMPLEMENT_CLASS(APowerHighJump)
void APowerHighJump::InitEffect( ) void APowerHighJump::InitEffect( )
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1656,6 +1699,7 @@ void APowerHighJump::InitEffect( )
void APowerHighJump::EndEffect( ) void APowerHighJump::EndEffect( )
{ {
Super::EndEffect();
// Nothing to do if there's no owner. // Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
@ -1676,6 +1720,8 @@ IMPLEMENT_CLASS(APowerDoubleFiringSpeed)
void APowerDoubleFiringSpeed::InitEffect( ) void APowerDoubleFiringSpeed::InitEffect( )
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1691,6 +1737,7 @@ void APowerDoubleFiringSpeed::InitEffect( )
void APowerDoubleFiringSpeed::EndEffect( ) void APowerDoubleFiringSpeed::EndEffect( )
{ {
Super::EndEffect();
// Nothing to do if there's no owner. // Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
@ -1724,6 +1771,8 @@ void APowerMorph::Serialize (FArchive &arc)
void APowerMorph::InitEffect( ) void APowerMorph::InitEffect( )
{ {
Super::InitEffect();
if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None)
{ {
player_t *realplayer = Owner->player; // Remember the identity of the player player_t *realplayer = Owner->player; // Remember the identity of the player
@ -1751,6 +1800,8 @@ void APowerMorph::InitEffect( )
void APowerMorph::EndEffect( ) void APowerMorph::EndEffect( )
{ {
Super::EndEffect();
// Abort if owner already destroyed // Abort if owner already destroyed
if (Owner == NULL) if (Owner == NULL)
{ {
@ -1806,6 +1857,8 @@ IMPLEMENT_CLASS(APowerInfiniteAmmo)
void APowerInfiniteAmmo::InitEffect( ) void APowerInfiniteAmmo::InitEffect( )
{ {
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL) if (Owner== NULL || Owner->player == NULL)
return; return;
@ -1821,6 +1874,8 @@ void APowerInfiniteAmmo::InitEffect( )
void APowerInfiniteAmmo::EndEffect( ) void APowerInfiniteAmmo::EndEffect( )
{ {
Super::EndEffect();
// Nothing to do if there's no owner. // Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {

View file

@ -81,12 +81,6 @@ protected:
// fixed_t OwnersNormalAlpha; // fixed_t OwnersNormalAlpha;
}; };
// Needed only for m_cheat.cpp now
class APowerShadow : public APowerInvisibility
{
DECLARE_CLASS (APowerShadow, APowerInvisibility)
};
class APowerIronFeet : public APowerup class APowerIronFeet : public APowerup
{ {
DECLARE_CLASS (APowerIronFeet, APowerup) DECLARE_CLASS (APowerIronFeet, APowerup)

View file

@ -53,7 +53,6 @@ class ASecurityCamera : public AActor
public: public:
void PostBeginPlay (); void PostBeginPlay ();
void Tick (); void Tick ();
angle_t AngleIncrements ();
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
protected: protected:
@ -71,11 +70,6 @@ void ASecurityCamera::Serialize (FArchive &arc)
arc << Center << Acc << Delta << Range; arc << Center << Acc << Delta << Range;
} }
angle_t ASecurityCamera::AngleIncrements ()
{
return ANGLE_1;
}
void ASecurityCamera::PostBeginPlay () void ASecurityCamera::PostBeginPlay ()
{ {
Super::PostBeginPlay (); Super::PostBeginPlay ();

View file

@ -43,7 +43,6 @@ class AHateTarget : public AActor
DECLARE_CLASS (AHateTarget, AActor) DECLARE_CLASS (AHateTarget, AActor)
public: public:
void BeginPlay (); void BeginPlay ();
angle_t AngleIncrements (void);
int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype);
}; };
@ -77,7 +76,3 @@ int AHateTarget::TakeSpecialDamage (AActor *inflictor, AActor *source, int damag
} }
} }
angle_t AHateTarget::AngleIncrements (void)
{
return ANGLE_1;
}

View file

@ -68,6 +68,7 @@ struct Lock
return true; return true;
} }
} }
return false;
} }
else for(unsigned int i=0;i<keylist.Size();i++) else for(unsigned int i=0;i<keylist.Size();i++)
{ {

View file

@ -42,17 +42,11 @@ class ASpark : public AActor
{ {
DECLARE_CLASS (ASpark, AActor) DECLARE_CLASS (ASpark, AActor)
public: public:
angle_t AngleIncrements ();
void Activate (AActor *activator); void Activate (AActor *activator);
}; };
IMPLEMENT_CLASS (ASpark) IMPLEMENT_CLASS (ASpark)
angle_t ASpark::AngleIncrements ()
{
return ANGLE_1;
}
void ASpark::Activate (AActor *activator) void ASpark::Activate (AActor *activator)
{ {
Super::Activate (activator); Super::Activate (activator);

View file

@ -542,6 +542,10 @@ void SBarInfo::ParseSBarInfo(int lump)
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
barNum = sc.MustMatchString(StatusBars); barNum = sc.MustMatchString(StatusBars);
} }
if (this->huds[barNum] != NULL)
{
delete this->huds[barNum];
}
this->huds[barNum] = new SBarInfoMainBlock(this); this->huds[barNum] = new SBarInfoMainBlock(this);
if(barNum == STBAR_AUTOMAP) if(barNum == STBAR_AUTOMAP)
{ {

View file

@ -166,12 +166,15 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, int t
{ {
int width; int width;
FTexture *texc = font->GetChar(text[i], &width); FTexture *texc = font->GetChar(text[i], &width);
if (texc != NULL)
{
int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight(); int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight();
screen->DrawChar(font, color, x, y, text[i], screen->DrawChar(font, color, x, y, text[i],
DTA_KeepRatio, true, DTA_KeepRatio, true,
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans,
DTA_LeftOffset, width/2, DTA_TopOffset, offset, DTA_LeftOffset, width/2, DTA_TopOffset, offset,
/*DTA_CenterBottomOffset, 1,*/ TAG_DONE); /*DTA_CenterBottomOffset, 1,*/ TAG_DONE);
}
x += zerowidth; x += zerowidth;
} }
} }
@ -179,7 +182,7 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, int t
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Draws a numberses a fixed widh for all characters // Draws a number with a fixed width for all digits
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -9,7 +9,7 @@
#include "thingdef/thingdef.h" #include "thingdef/thingdef.h"
*/ */
bool Sys_1ed64 (AActor *self) static bool CrusaderCheckRange (AActor *self)
{ {
if (P_CheckSight (self, self->target) && self->reactiontime == 0) if (P_CheckSight (self, self->target) && self->reactiontime == 0)
{ {
@ -25,7 +25,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose)
if (self->target == NULL) if (self->target == NULL)
return 0; return 0;
if (Sys_1ed64 (self)) if (CrusaderCheckRange (self))
{ {
A_FaceTarget (self); A_FaceTarget (self);
self->angle -= ANGLE_180/16; self->angle -= ANGLE_180/16;

View file

@ -87,7 +87,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire)
{ {
if (self->target == NULL || if (self->target == NULL ||
self->target->health <= 0 || self->target->health <= 0 ||
!P_CheckSight (self, self->target) || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ||
P_HitFriend(self) || P_HitFriend(self) ||
pr_sentinelrefire() < 40) pr_sentinelrefire() < 40)
{ {

View file

@ -536,13 +536,14 @@ void FGameConfigFile::ArchiveGlobalData ()
FString FGameConfigFile::GetConfigPath (bool tryProg) FString FGameConfigFile::GetConfigPath (bool tryProg)
{ {
char *pathval; const char *pathval;
FString path; FString path;
pathval = Args->CheckValue ("-config"); pathval = Args->CheckValue ("-config");
if (pathval != NULL) if (pathval != NULL)
{
return FString(pathval); return FString(pathval);
}
#ifdef _WIN32 #ifdef _WIN32
path = NULL; path = NULL;
HRESULT hr; HRESULT hr;

View file

@ -418,7 +418,7 @@ void HU_DrawColorBar(int x, int y, int height, int playernum)
{ {
float h, s, v, r, g, b; float h, s, v, r, g, b;
D_GetPlayerColor (playernum, &h, &s, &v); D_GetPlayerColor (playernum, &h, &s, &v, NULL);
HSVtoRGB (&r, &g, &b, h, s, v); HSVtoRGB (&r, &g, &b, h, s, v);
screen->Clear (x, y, x + 24*CleanXfac, y + height, -1, screen->Clear (x, y, x + 24*CleanXfac, y + height, -1,

View file

@ -338,20 +338,21 @@ void PreSend (const void *buffer, int bufferlen, const sockaddr_in *to)
sendto (mysocket, (const char *)buffer, bufferlen, 0, (const sockaddr *)to, sizeof(*to)); sendto (mysocket, (const char *)buffer, bufferlen, 0, (const sockaddr *)to, sizeof(*to));
} }
void BuildAddress (sockaddr_in *address, char *name) void BuildAddress (sockaddr_in *address, const char *name)
{ {
hostent *hostentry; // host information entry hostent *hostentry; // host information entry
u_short port; u_short port;
char *portpart; const char *portpart;
bool isnamed = false; bool isnamed = false;
int curchar; int curchar;
char c; char c;
FString target;
address->sin_family = AF_INET; address->sin_family = AF_INET;
if ( (portpart = strchr (name, ':')) ) if ( (portpart = strchr (name, ':')) )
{ {
*portpart = 0; target = FString(name, portpart - name);
port = atoi (portpart + 1); port = atoi (portpart + 1);
if (!port) if (!port)
{ {
@ -361,11 +362,12 @@ void BuildAddress (sockaddr_in *address, char *name)
} }
else else
{ {
target = name;
port = DOOMPORT; port = DOOMPORT;
} }
address->sin_port = htons(port); address->sin_port = htons(port);
for (curchar = 0; (c = name[curchar]) ; curchar++) for (curchar = 0; (c = target[curchar]) ; curchar++)
{ {
if ((c < '0' || c > '9') && c != '.') if ((c < '0' || c > '9') && c != '.')
{ {
@ -376,21 +378,18 @@ void BuildAddress (sockaddr_in *address, char *name)
if (!isnamed) if (!isnamed)
{ {
address->sin_addr.s_addr = inet_addr (name); address->sin_addr.s_addr = inet_addr (target);
Printf ("Node number %d, address %s\n", doomcom.numnodes, name); Printf ("Node number %d, address %s\n", doomcom.numnodes, target.GetChars());
} }
else else
{ {
hostentry = gethostbyname (name); hostentry = gethostbyname (target);
if (!hostentry) if (!hostentry)
I_FatalError ("gethostbyname: couldn't find %s\n%s", name, neterror()); I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror());
address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
Printf ("Node number %d, hostname %s\n", Printf ("Node number %d, hostname %s\n",
doomcom.numnodes, hostentry->h_name); doomcom.numnodes, hostentry->h_name);
} }
if (portpart)
*portpart = ':';
} }
void CloseNetwork (void) void CloseNetwork (void)
@ -910,7 +909,7 @@ static bool NodesOnSameNetwork()
bool I_InitNetwork (void) bool I_InitNetwork (void)
{ {
int i; int i;
char *v; const char *v;
memset (&doomcom, 0, sizeof(doomcom)); memset (&doomcom, 0, sizeof(doomcom));

View file

@ -459,8 +459,6 @@ PClassActor *PClassActor::GetReplacee(bool lookskill)
//========================================================================== //==========================================================================
void PClassActor::SetDamageFactor(FName type, fixed_t factor) void PClassActor::SetDamageFactor(FName type, fixed_t factor)
{
if (factor != FRACUNIT)
{ {
if (DamageFactors == NULL) if (DamageFactors == NULL)
{ {
@ -468,11 +466,6 @@ void PClassActor::SetDamageFactor(FName type, fixed_t factor)
} }
DamageFactors->Insert(type, factor); DamageFactors->Insert(type, factor);
} }
else if (DamageFactors != NULL)
{
DamageFactors->Remove(type);
}
}
//========================================================================== //==========================================================================
// //
@ -488,7 +481,7 @@ void PClassActor::SetPainChance(FName type, int chance)
{ {
PainChances = new PainChanceList; PainChances = new PainChanceList;
} }
PainChances->Insert(type, MIN(chance, 255)); PainChances->Insert(type, MIN(chance, 256));
} }
else if (PainChances != NULL) else if (PainChances != NULL)
{ {
@ -501,6 +494,25 @@ void PClassActor::SetPainChance(FName type, int chance)
// //
//========================================================================== //==========================================================================
void PClassActor::SetColorSet(int index, const FPlayerColorSet *set)
{
if (set != NULL)
{
if (ColorSets == NULL) ColorSets = new FPlayerColorSetMap;
ColorSets->Insert(index, *set);
}
else
{
if (ColorSets != NULL)
ColorSets->Remove(index);
}
}
//==========================================================================
//
//
//==========================================================================
FDoomEdMap DoomEdMap; FDoomEdMap DoomEdMap;
FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE]; FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE];

View file

@ -123,8 +123,21 @@ FArchive &operator<< (FArchive &arc, FState *&state);
#include "gametype.h" #include "gametype.h"
// Standard pre-defined skin colors
struct FPlayerColorSet
{
FName Name; // Name of this color
int Lump; // Lump to read the translation from, otherwise use next 2 fields
BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation
BYTE RepresentativeColor; // A palette entry representative of this translation,
// for map arrows and status bar backgrounds and such
};
typedef TMap<FName, fixed_t> DmgFactors; typedef TMap<FName, fixed_t> DmgFactors;
typedef TMap<FName, BYTE> PainChanceList; typedef TMap<FName, int> PainChanceList;
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
class DDropItem; class DDropItem;
class PClassActor : public PClass class PClassActor : public PClass
@ -145,6 +158,7 @@ public:
void RegisterIDs(); void RegisterIDs();
void SetDamageFactor(FName type, fixed_t factor); void SetDamageFactor(FName type, fixed_t factor);
void SetPainChance(FName type, int chance); void SetPainChance(FName type, int chance);
void SetColorSet(int index, const FPlayerColorSet *set);
size_t PropagateMark(); size_t PropagateMark();
void InitializeNativeDefaults(); void InitializeNativeDefaults();
@ -168,6 +182,7 @@ public:
FStateLabels *StateList; FStateLabels *StateList;
DmgFactors *DamageFactors; DmgFactors *DamageFactors;
PainChanceList *PainChances; PainChanceList *PainChances;
FPlayerColorSetMap *ColorSets;
FString Obituary; // Player was killed by this actor FString Obituary; // Player was killed by this actor
FString HitObituary; // Player was killed by this actor in melee FString HitObituary; // Player was killed by this actor in melee
fixed_t DeathHeight; // Height on normal death fixed_t DeathHeight; // Height on normal death

View file

@ -38,161 +38,348 @@
IMPLEMENT_CLASS (DArgs) IMPLEMENT_CLASS (DArgs)
//===========================================================================
//
// DArgs Default Constructor
//
//===========================================================================
DArgs::DArgs() DArgs::DArgs()
{ {
m_ArgC = 0;
m_ArgV = NULL;
} }
DArgs::DArgs (int argc, char **argv) //===========================================================================
{ //
CopyArgs (argc, argv); // DArgs Copy Constructor
} //
//===========================================================================
DArgs::DArgs(const DArgs &other) DArgs::DArgs(const DArgs &other)
{ {
CopyArgs (other.m_ArgC, other.m_ArgV); Argv = other.Argv;
} }
//===========================================================================
//
// DArgs Argv Constructor
//
//===========================================================================
DArgs::~DArgs () DArgs::DArgs(int argc, char **argv)
{ {
FlushArgs (); SetArgs(argc, argv);
} }
//===========================================================================
//
// DArgs String Argv Constructor
//
//===========================================================================
DArgs::DArgs(int argc, FString *argv)
{
AppendArgs(argc, argv);
}
//===========================================================================
//
// DArgs Copy Operator
//
//===========================================================================
DArgs &DArgs::operator=(const DArgs &other) DArgs &DArgs::operator=(const DArgs &other)
{ {
FlushArgs (); Argv = other.Argv;
CopyArgs (other.m_ArgC, other.m_ArgV);
return *this; return *this;
} }
//===========================================================================
//
// DArgs :: SetArgs
//
//===========================================================================
void DArgs::SetArgs(int argc, char **argv) void DArgs::SetArgs(int argc, char **argv)
{ {
FlushArgs (); Argv.Resize(argc);
CopyArgs (argc, argv); for (int i = 0; i < argc; ++i)
}
void DArgs::CopyArgs (int argc, char **argv)
{ {
int i; Argv[i] = argv[i];
m_ArgC = argc;
m_ArgV = new char *[argc];
for (i = 0; i < argc; i++)
m_ArgV[i] = copystring (argv[i]);
} }
}
//===========================================================================
//
// DArgs :: FlushArgs
//
//===========================================================================
void DArgs::FlushArgs() void DArgs::FlushArgs()
{ {
int i; Argv.Clear();
for (i = 0; i < m_ArgC; i++)
delete[] m_ArgV[i];
delete[] m_ArgV;
m_ArgC = 0;
m_ArgV = NULL;
} }
//===========================================================================
//
// DArgs :: CheckParm
// //
// CheckParm
// Checks for the given parameter in the program's command line arguments. // Checks for the given parameter in the program's command line arguments.
// Returns the argument number (1 to argc-1) or 0 if not present // Returns the argument number (1 to argc-1) or 0 if not present
// //
//===========================================================================
int DArgs::CheckParm(const char *check, int start) const int DArgs::CheckParm(const char *check, int start) const
{ {
for (int i = start; i < m_ArgC; ++i) for (unsigned i = start; i < Argv.Size(); ++i)
if (!stricmp (check, m_ArgV[i])) {
if (0 == stricmp(check, Argv[i]))
{
return i; return i;
}
}
return 0; return 0;
} }
char *DArgs::CheckValue (const char *check) const //===========================================================================
//
// DArgs :: CheckParmList
//
// Returns the number of arguments after the parameter (if found) and also
// returns a pointer to the first argument.
//
//===========================================================================
int DArgs::CheckParmList(const char *check, FString **strings, int start) const
{
unsigned int i, parmat = CheckParm(check, start);
if (parmat == 0)
{
if (strings != NULL)
{
*strings = NULL;
}
return 0;
}
for (i = ++parmat; i < Argv.Size(); ++i)
{
if (Argv[i][0] == '-' || Argv[i][1] == '+')
{
break;
}
}
if (strings != NULL)
{
*strings = &Argv[parmat];
}
return i - parmat;
}
//===========================================================================
//
// DArgs :: CheckValue
//
// Like CheckParm, but it also checks that the parameter has a value after
// it and returns that or NULL if not present.
//
//===========================================================================
const char *DArgs::CheckValue(const char *check) const
{ {
int i = CheckParm(check); int i = CheckParm(check);
if (i > 0 && i < m_ArgC - 1) if (i > 0 && i < (int)Argv.Size() - 1)
return m_ArgV[i+1][0] != '+' && m_ArgV[i+1][0] != '-' ? m_ArgV[i+1] : NULL; {
i++;
return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].GetChars() : NULL;
}
else else
{
return NULL; return NULL;
} }
}
char *DArgs::GetArg (int arg) const //===========================================================================
//
// DArgs :: TakeValue
//
// Like CheckValue, except it also removes the parameter and its argument
// (if present) from argv.
//
//===========================================================================
FString DArgs::TakeValue(const char *check)
{ {
if (arg >= 0 && arg < m_ArgC) int i = CheckParm(check);
return m_ArgV[arg]; FString out;
if (i > 0 && i < (int)Argv.Size())
{
if (i < (int)Argv.Size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-')
{
out = Argv[i+1];
Argv.Delete(i, 2); // Delete the parm and its value.
}
else else
return NULL;
}
char **DArgs::GetArgList (int arg) const
{ {
if (arg >= 0 && arg < m_ArgC) Argv.Delete(i); // Just delete the parm, since it has no value.
return &m_ArgV[arg];
else
return NULL;
}
int DArgs::NumArgs () const
{
return m_ArgC;
}
void DArgs::AppendArg (const char *arg)
{
char **temp = new char *[m_ArgC + 1];
if (m_ArgV)
{
memcpy (temp, m_ArgV, sizeof(*m_ArgV) * m_ArgC);
delete[] m_ArgV;
}
temp[m_ArgC] = copystring (arg);
m_ArgV = temp;
m_ArgC++;
}
DArgs *DArgs::GatherFiles (const char *param, const char *extension, bool acceptNoExt) const
{
DArgs *out = new DArgs;
int i;
size_t extlen = strlen (extension);
if (extlen > 0)
{
for (i = 1; i < m_ArgC && *m_ArgV[i] != '-' && *m_ArgV[i] != '+'; i++)
{
size_t len = strlen (m_ArgV[i]);
if (len >= extlen && stricmp (m_ArgV[i] + len - extlen, extension) == 0)
out->AppendArg (m_ArgV[i]);
else if (acceptNoExt)
{
const char *src = m_ArgV[i] + len - 1;
while (src != m_ArgV[i] && *src != '/'
#ifdef _WIN32
&& *src != '\\'
#endif
)
{
if (*src == '.')
goto morefor; // it has an extension
src--;
}
out->AppendArg (m_ArgV[i]);
morefor:
;
}
}
}
if (param != NULL)
{
i = 1;
while (0 != (i = CheckParm (param, i)))
{
for (++i; i < m_ArgC && *m_ArgV[i] != '-' && *m_ArgV[i] != '+'; ++i)
out->AppendArg (m_ArgV[i]);
} }
} }
return out; return out;
} }
//===========================================================================
//
// DArgs :: GetArg
//
// Gets the argument at a particular position.
//
//===========================================================================
const char *DArgs::GetArg(int arg) const
{
return ((unsigned)arg < Argv.Size()) ? Argv[arg].GetChars() : NULL;
return Argv[arg];
}
//===========================================================================
//
// DArgs :: GetArgList
//
// Returns a pointer to the FString at a particular position.
//
//===========================================================================
FString *DArgs::GetArgList(int arg) const
{
return ((unsigned)arg < Argv.Size()) ? &Argv[arg] : NULL;
}
//===========================================================================
//
// DArgs :: NumArgs
//
//===========================================================================
int DArgs::NumArgs() const
{
return (int)Argv.Size();
}
//===========================================================================
//
// DArgs :: AppendArg
//
// Adds another argument to argv. Invalidates any previous results from
// GetArgList().
//
//===========================================================================
void DArgs::AppendArg(FString arg)
{
Argv.Push(arg);
}
//===========================================================================
//
// DArgs :: AppendArgs
//
// Adds an array of FStrings to argv.
//
//===========================================================================
void DArgs::AppendArgs(int argc, const FString *argv)
{
if (argv != NULL && argc > 0)
{
Argv.Grow(argc);
for (int i = 0; i < argc; ++i)
{
Argv.Push(argv[i]);
}
}
}
//===========================================================================
//
// DArgs :: CollectFiles
//
// Takes all arguments after any instance of -param and any arguments before
// all switches that end in .extension and combines them into a single
// -switch block at the end of the arguments. If extension is NULL, then
// every parameter before the first switch is added after this -param.
//
//===========================================================================
void DArgs::CollectFiles(const char *param, const char *extension)
{
TArray<FString> work;
DArgs *out = new DArgs;
unsigned int i;
size_t extlen = extension == NULL ? 0 : strlen(extension);
// Step 1: Find suitable arguments before the first switch.
i = 1;
while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+')
{
bool useit;
if (extlen > 0)
{ // Argument's extension must match.
size_t len = Argv[i].Len();
useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0);
}
else
{ // Anything will do so long as it's before the first switch.
useit = true;
}
if (useit)
{
work.Push(Argv[i]);
Argv.Delete(i);
}
else
{
i++;
}
}
// Step 2: Find each occurence of -param and add its arguments to work.
while ((i = CheckParm(param, i)) > 0)
{
Argv.Delete(i);
while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+')
{
work.Push(Argv[i]);
Argv.Delete(i);
}
}
// Step 3: Add work back to Argv, as long as it's non-empty.
if (work.Size() > 0)
{
Argv.Push(param);
AppendArgs(work.Size(), &work[0]);
}
}
//===========================================================================
//
// DArgs :: GatherFiles
//
// Returns all the arguments after the first instance of -param. If you want
// to combine more than one or get switchless stuff included, you need to
// call CollectFiles first.
//
//===========================================================================
DArgs *DArgs::GatherFiles(const char *param) const
{
FString *files;
int filecount;
filecount = CheckParmList(param, &files);
return new DArgs(filecount, files);
}

View file

@ -35,6 +35,7 @@
#define __M_ARGV_H__ #define __M_ARGV_H__
#include "dobject.h" #include "dobject.h"
#include "zstring.h"
// //
// MISC // MISC
@ -46,29 +47,28 @@ public:
DArgs(); DArgs();
DArgs(const DArgs &args); DArgs(const DArgs &args);
DArgs(int argc, char **argv); DArgs(int argc, char **argv);
~DArgs (); DArgs(int argc, FString *argv);
DArgs &operator=(const DArgs &other); DArgs &operator=(const DArgs &other);
void AppendArg (const char *arg); void AppendArg(FString arg);
void AppendArgs(int argc, const FString *argv);
void SetArgs(int argc, char **argv); void SetArgs(int argc, char **argv);
DArgs *GatherFiles (const char *param, const char *extension, bool acceptNoExt) const; void CollectFiles(const char *param, const char *extension);
DArgs *GatherFiles(const char *param) const;
void SetArg(int argnum, const char *arg); void SetArg(int argnum, const char *arg);
// Returns the position of the given parameter int CheckParm(const char *check, int start=1) const; // Returns the position of the given parameter in the arg list (0 if not found).
// in the arg list (0 if not found). int CheckParmList(const char *check, FString **strings, int start=1) const;
int CheckParm (const char *check, int start=1) const; const char *CheckValue(const char *check) const;
char *CheckValue (const char *check) const; const char *GetArg(int arg) const;
char *GetArg (int arg) const; FString *GetArgList(int arg) const;
char **GetArgList (int arg) const; FString TakeValue(const char *check);
int NumArgs() const; int NumArgs() const;
void FlushArgs(); void FlushArgs();
private: private:
int m_ArgC; TArray<FString> Argv;
char **m_ArgV;
void CopyArgs (int argc, char **argv);
}; };
extern DArgs *Args; extern DArgs *Args;

View file

@ -52,17 +52,17 @@
void cht_DoCheat (player_t *player, int cheat) void cht_DoCheat (player_t *player, int cheat)
{ {
static PClass *const *BeholdPowers[9] = static const char * const BeholdPowers[9] =
{ {
&RUNTIME_CLASS_CASTLESS(APowerInvulnerable), "PowerInvulnerable",
&RUNTIME_CLASS_CASTLESS(APowerStrength), "PowerStrength",
&RUNTIME_CLASS_CASTLESS(APowerInvisibility), "PowerInvisibility",
&RUNTIME_CLASS_CASTLESS(APowerIronFeet), "PowerIronFeet",
NULL, // MapRevealer "MapRevealer",
&RUNTIME_CLASS_CASTLESS(APowerLightAmp), "PowerLightAmp",
&RUNTIME_CLASS_CASTLESS(APowerShadow), "PowerShadow",
&RUNTIME_CLASS_CASTLESS(APowerMask), "PowerMask",
&RUNTIME_CLASS_CASTLESS(APowerTargeter) "PowerTargeter",
}; };
PClassActor *type; PClassActor *type;
AInventory *item; AInventory *item;
@ -245,12 +245,12 @@ void cht_DoCheat (player_t *player, int cheat)
} }
else if (player->mo != NULL && player->health >= 0) else if (player->mo != NULL && player->health >= 0)
{ {
item = player->mo->FindInventory(static_cast<PClassActor *>(*BeholdPowers[i])); item = player->mo->FindInventory(PClass::FindActor(BeholdPowers[i]));
if (item == NULL) if (item == NULL)
{ {
if (i != 0) if (i != 0)
{ {
player->mo->GiveInventoryType(static_cast<PClassActor *>(*BeholdPowers[i])); cht_Give(player, BeholdPowers[i]);
if (cheat == CHT_BEHOLDS) if (cheat == CHT_BEHOLDS)
{ {
P_GiveBody (player->mo, -100); P_GiveBody (player->mo, -100);
@ -259,7 +259,7 @@ void cht_DoCheat (player_t *player, int cheat)
else else
{ {
// Let's give the item here so that the power doesn't need colormap information. // Let's give the item here so that the power doesn't need colormap information.
player->mo->GiveInventoryType(PClass::FindActor("InvulnerabilitySphere")); cht_Give(player, "InvulnerabilitySphere");
} }
} }
else else
@ -316,7 +316,10 @@ void cht_DoCheat (player_t *player, int cheat)
player->mo->special1 = 0; // required for the Hexen fighter's fist attack. player->mo->special1 = 0; // required for the Hexen fighter's fist attack.
// This gets set by AActor::Die as flag for the wimpy death and must be reset here. // This gets set by AActor::Die as flag for the wimpy death and must be reset here.
player->mo->SetState (player->mo->SpawnState); player->mo->SetState (player->mo->SpawnState);
if (!(player->mo->flags2 & MF2_DONTTRANSLATE))
{
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
}
player->mo->DamageType = NAME_None; player->mo->DamageType = NAME_None;
// player->mo->GiveDefaultInventory(); // player->mo->GiveDefaultInventory();
if (player->ReadyWeapon != NULL) if (player->ReadyWeapon != NULL)

View file

@ -118,7 +118,7 @@ protected:
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table); void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayerSkin *skin, FRemapTable *table);
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -188,6 +188,7 @@ static void M_EditPlayerName (int choice);
static void M_ChangePlayerTeam (int choice); static void M_ChangePlayerTeam (int choice);
static void M_PlayerNameChanged (FSaveGameNode *dummy); static void M_PlayerNameChanged (FSaveGameNode *dummy);
static void M_PlayerNameNotChanged (); static void M_PlayerNameNotChanged ();
static void M_ChangeColorSet (int choice);
static void M_SlidePlayerRed (int choice); static void M_SlidePlayerRed (int choice);
static void M_SlidePlayerGreen (int choice); static void M_SlidePlayerGreen (int choice);
static void M_SlidePlayerBlue (int choice); static void M_SlidePlayerBlue (int choice);
@ -246,17 +247,10 @@ static char savegamestring[SAVESTRINGSIZE];
static FString EndString; static FString EndString;
static short itemOn; // menu item skull is on static short itemOn; // menu item skull is on
static short whichSkull; // which skull to draw
static int MenuTime; static int MenuTime;
static int InfoType; static int InfoType;
static int InfoTic; static int InfoTic;
static const char skullName[2][9] = {"M_SKULL1", "M_SKULL2"}; // graphic name of skulls
static const char cursName[8][8] = // graphic names of Strife menu selector
{
"M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4", "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8"
};
static oldmenu_t *currentMenu; // current menudef static oldmenu_t *currentMenu; // current menudef
static oldmenu_t *TopLevelMenu; // The main menu everything hangs off of static oldmenu_t *TopLevelMenu; // The main menu everything hangs off of
@ -269,6 +263,7 @@ static int PlayerSkin;
static FState *PlayerState; static FState *PlayerState;
static int PlayerTics; static int PlayerTics;
static int PlayerRotation; static int PlayerRotation;
static TArray<int> PlayerColorSets;
static FTexture *SavePic; static FTexture *SavePic;
static FBrokenLines *SaveComment; static FBrokenLines *SaveComment;
@ -536,15 +531,24 @@ static oldmenuitem_t PlayerSetupMenu[] =
{ {
{ 1,0,'n',NULL,M_EditPlayerName, CR_UNTRANSLATED}, { 1,0,'n',NULL,M_EditPlayerName, CR_UNTRANSLATED},
{ 2,0,'t',NULL,M_ChangePlayerTeam, CR_UNTRANSLATED}, { 2,0,'t',NULL,M_ChangePlayerTeam, CR_UNTRANSLATED},
{ 2,0,'c',NULL,M_ChangeColorSet, CR_UNTRANSLATED},
{ 2,0,'r',NULL,M_SlidePlayerRed, CR_UNTRANSLATED}, { 2,0,'r',NULL,M_SlidePlayerRed, CR_UNTRANSLATED},
{ 2,0,'g',NULL,M_SlidePlayerGreen, CR_UNTRANSLATED}, { 2,0,'g',NULL,M_SlidePlayerGreen, CR_UNTRANSLATED},
{ 2,0,'b',NULL,M_SlidePlayerBlue, CR_UNTRANSLATED}, { 2,0,'b',NULL,M_SlidePlayerBlue, CR_UNTRANSLATED},
{ 2,0,'c',NULL,M_ChangeClass, CR_UNTRANSLATED}, { 2,0,'t',NULL,M_ChangeClass, CR_UNTRANSLATED},
{ 2,0,'s',NULL,M_ChangeSkin, CR_UNTRANSLATED}, { 2,0,'s',NULL,M_ChangeSkin, CR_UNTRANSLATED},
{ 2,0,'e',NULL,M_ChangeGender, CR_UNTRANSLATED}, { 2,0,'e',NULL,M_ChangeGender, CR_UNTRANSLATED},
{ 2,0,'a',NULL,M_ChangeAutoAim, CR_UNTRANSLATED} { 2,0,'a',NULL,M_ChangeAutoAim, CR_UNTRANSLATED}
}; };
enum
{
// These must be changed if the menu definition is altered
PSM_RED = 3,
PSM_GREEN = 4,
PSM_BLUE = 5,
};
static oldmenu_t PSetupDef = static oldmenu_t PSetupDef =
{ {
countof(PlayerSetupMenu), countof(PlayerSetupMenu),
@ -2088,13 +2092,16 @@ void M_PlayerSetup (void)
PlayerClass = &PlayerClasses[players[consoleplayer].CurrentPlayerClass]; PlayerClass = &PlayerClasses[players[consoleplayer].CurrentPlayerClass];
} }
PlayerSkin = players[consoleplayer].userinfo.skin; PlayerSkin = players[consoleplayer].userinfo.skin;
R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); R_GetPlayerTranslation (players[consoleplayer].userinfo.color,
P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState; PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState;
PlayerTics = PlayerState->GetTics(); PlayerTics = PlayerState->GetTics();
if (FireTexture == NULL) if (FireTexture == NULL)
{ {
FireTexture = new FBackdropTexture; FireTexture = new FBackdropTexture;
} }
P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets);
} }
static void M_PlayerSetupTicker (void) static void M_PlayerSetupTicker (void)
@ -2112,6 +2119,7 @@ static void M_PlayerSetupTicker (void)
item = (MenuTime>>2) % (ClassMenuDef.numitems-1); item = (MenuTime>>2) % (ClassMenuDef.numitems-1);
PlayerClass = &PlayerClasses[D_PlayerClassToInt (ClassMenuItems[item].name)]; PlayerClass = &PlayerClasses[D_PlayerClassToInt (ClassMenuItems[item].name)];
P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets);
} }
else else
{ {
@ -2125,6 +2133,7 @@ static void M_PlayerSetupTicker (void)
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0]));
R_GetPlayerTranslation (players[consoleplayer].userinfo.color, R_GetPlayerTranslation (players[consoleplayer].userinfo.color,
P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
} }
@ -2280,19 +2289,27 @@ static void M_PlayerSetupDrawer ()
DTA_Clean, true, TAG_DONE); DTA_Clean, true, TAG_DONE);
} }
// Draw player color sliders // Draw player color selection and sliders
//V_DrawTextCleanMove (CR_GREY, PSetupDef.x, PSetupDef.y + LINEHEIGHT, "Color"); FPlayerColorSet *colorset = P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset);
x = SmallFont->StringWidth("Color") + 8 + PSetupDef.x;
screen->DrawText(SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*2+yo, "Color", DTA_Clean, true, TAG_DONE);
screen->DrawText(SmallFont, value, x, PSetupDef.y + LINEHEIGHT*2+yo,
colorset != NULL ? colorset->Name.GetChars() : "Custom", DTA_Clean, true, TAG_DONE);
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*2+yo, "Red", DTA_Clean, true, TAG_DONE); // Only show the sliders for a custom color set.
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*3+yo, "Green", DTA_Clean, true, TAG_DONE); if (colorset == NULL)
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*4+yo, "Blue", DTA_Clean, true, TAG_DONE); {
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*2.875)+yo, "Red", DTA_Clean, true, TAG_DONE);
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*3.5)+yo, "Green", DTA_Clean, true, TAG_DONE);
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*4.125)+yo, "Blue", DTA_Clean, true, TAG_DONE);
x = SmallFont->StringWidth ("Green") + 8 + PSetupDef.x; x = SmallFont->StringWidth ("Green") + 8 + PSetupDef.x;
color = players[consoleplayer].userinfo.color; color = players[consoleplayer].userinfo.color;
M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*2+yo, RPART(color)); M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*2.875)+yo, RPART(color));
M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*3+yo, GPART(color)); M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*3.5)+yo, GPART(color));
M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*4+yo, BPART(color)); M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*4.125)+yo, BPART(color));
}
// [GRB] Draw class setting // [GRB] Draw class setting
int pclass = players[consoleplayer].userinfo.PlayerClass; int pclass = players[consoleplayer].userinfo.PlayerClass;
@ -2586,7 +2603,9 @@ static void M_ChangeSkin (int choice)
PlayerSkin = (PlayerSkin < (int)numskins - 1) ? PlayerSkin + 1 : 0; PlayerSkin = (PlayerSkin < (int)numskins - 1) ? PlayerSkin + 1 : 0;
} while (!PlayerClass->CheckSkin (PlayerSkin)); } while (!PlayerClass->CheckSkin (PlayerSkin));
R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); R_GetPlayerTranslation (players[consoleplayer].userinfo.color,
P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
cvar_set ("skin", skins[PlayerSkin].name); cvar_set ("skin", skins[PlayerSkin].name);
} }
@ -2707,13 +2726,55 @@ static void M_ChangePlayerTeam (int choice)
} }
} }
static void M_ChangeColorSet (int choice)
{
int curpos = (int)PlayerColorSets.Size();
int mycolorset = players[consoleplayer].userinfo.colorset;
while (--curpos >= 0)
{
if (PlayerColorSets[curpos] == mycolorset)
break;
}
if (choice == 0)
{
curpos--;
}
else
{
curpos++;
}
if (curpos < -1)
{
curpos = (int)PlayerColorSets.Size() - 1;
}
else if (curpos >= (int)PlayerColorSets.Size())
{
curpos = -1;
}
mycolorset = (curpos >= 0) ? PlayerColorSets[curpos] : -1;
// disable the sliders if a valid colorset is selected
PlayerSetupMenu[PSM_RED].status =
PlayerSetupMenu[PSM_GREEN].status =
PlayerSetupMenu[PSM_BLUE].status = (mycolorset == -1? 2:-1);
char command[24];
mysnprintf(command, countof(command), "colorset %d", mycolorset);
C_DoCommand(command);
R_GetPlayerTranslation(players[consoleplayer].userinfo.color,
P_GetPlayerColorSet(PlayerClass->Type->TypeName, mycolorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
}
static void SendNewColor (int red, int green, int blue) static void SendNewColor (int red, int green, int blue)
{ {
char command[24]; char command[24];
mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue); mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue);
C_DoCommand (command); C_DoCommand (command);
R_GetPlayerTranslation (MAKERGB (red, green, blue), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); R_GetPlayerTranslation(MAKERGB (red, green, blue),
P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
} }
static void M_SlidePlayerRed (int choice) static void M_SlidePlayerRed (int choice)
@ -3645,27 +3706,50 @@ void M_Drawer ()
// [RH] Use options menu cursor for the player setup menu. // [RH] Use options menu cursor for the player setup menu.
if (skullAnimCounter < 6) if (skullAnimCounter < 6)
{ {
double item;
// The green slider is halfway between lines, and the red and
// blue ones are offset slightly to make room for it.
if (itemOn < 3)
{
item = itemOn;
}
else if (itemOn > 5)
{
item = itemOn - 1;
}
else if (itemOn == 3)
{
item = 2.875;
}
else if (itemOn == 4)
{
item = 3.5;
}
else
{
item = 4.125;
}
screen->DrawText (ConFont, CR_RED, x - 16, screen->DrawText (ConFont, CR_RED, x - 16,
currentMenu->y + itemOn*PLAYERSETUP_LINEHEIGHT + currentMenu->y + int(item*PLAYERSETUP_LINEHEIGHT) +
(!(gameinfo.gametype & (GAME_DoomStrifeChex)) ? 6 : -1), "\xd", (!(gameinfo.gametype & (GAME_DoomStrifeChex)) ? 6 : -1), "\xd",
DTA_Clean, true, TAG_DONE); DTA_Clean, true, TAG_DONE);
} }
} }
else if (gameinfo.gametype & GAME_DoomChex) else if (gameinfo.gametype & GAME_DoomChex)
{ {
screen->DrawTexture (TexMan[skullName[whichSkull]], screen->DrawTexture (TexMan("M_SKULL1"),
x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,
DTA_Clean, true, TAG_DONE); DTA_Clean, true, TAG_DONE);
} }
else if (gameinfo.gametype == GAME_Strife) else if (gameinfo.gametype == GAME_Strife)
{ {
screen->DrawTexture (TexMan[cursName[(MenuTime >> 2) & 7]], screen->DrawTexture (TexMan("M_CURS1"),
x - 28, currentMenu->y - 5 + itemOn*LINEHEIGHT, x - 28, currentMenu->y - 5 + itemOn*LINEHEIGHT,
DTA_Clean, true, TAG_DONE); DTA_Clean, true, TAG_DONE);
} }
else else
{ {
screen->DrawTexture (TexMan[MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"], screen->DrawTexture (TexMan("M_SLCTR1"),
x + SELECTOR_XOFFSET, x + SELECTOR_XOFFSET,
currentMenu->y + itemOn*LINEHEIGHT + SELECTOR_YOFFSET, currentMenu->y + itemOn*LINEHEIGHT + SELECTOR_YOFFSET,
DTA_Clean, true, TAG_DONE); DTA_Clean, true, TAG_DONE);
@ -3859,7 +3943,6 @@ void M_Ticker (void)
MenuTime++; MenuTime++;
if (--skullAnimCounter <= 0) if (--skullAnimCounter <= 0)
{ {
whichSkull ^= 1;
skullAnimCounter = 8; skullAnimCounter = 8;
} }
if (currentMenu == &PSetupDef || currentMenu == &ClassMenuDef) if (currentMenu == &PSetupDef || currentMenu == &ClassMenuDef)
@ -3913,7 +3996,6 @@ void M_Init (void)
menuactive = MENU_Off; menuactive = MENU_Off;
InfoType = 0; InfoType = 0;
itemOn = currentMenu->lastOn; itemOn = currentMenu->lastOn;
whichSkull = 0;
skullAnimCounter = 10; skullAnimCounter = 10;
drawSkull = true; drawSkull = true;
messageToPrint = 0; messageToPrint = 0;
@ -4034,4 +4116,5 @@ static void PickPlayerClass ()
} }
PlayerClass = &PlayerClasses[pclass]; PlayerClass = &PlayerClasses[pclass];
P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets);
} }

View file

@ -159,7 +159,6 @@ void M_FindResponseFile (void)
char **argv; char **argv;
char *file; char *file;
int argc; int argc;
int argcinresp;
FILE *handle; FILE *handle;
int size; int size;
long argsize; long argsize;
@ -183,23 +182,32 @@ void M_FindResponseFile (void)
file[size] = 0; file[size] = 0;
fclose (handle); fclose (handle);
argsize = ParseCommandLine (file, &argcinresp, NULL); argsize = ParseCommandLine (file, &argc, NULL);
argc = argcinresp + Args->NumArgs() - 1; argc = Args->NumArgs() - 1;
if (argc != 0) if (argc != 0)
{ {
argv = (char **)M_Malloc (argc*sizeof(char *) + argsize); argv = (char **)M_Malloc (argc*sizeof(char *) + argsize);
argv[i] = (char *)argv + argc*sizeof(char *); argv[0] = (char *)argv + argc*sizeof(char *);
ParseCommandLine (file, NULL, argv+i); ParseCommandLine (file, NULL, argv);
// Create a new argument vector
DArgs *newargs = new DArgs;
// Copy parameters before response file.
for (index = 0; index < i; ++index) for (index = 0; index < i; ++index)
argv[index] = Args->GetArg (index); newargs->AppendArg(Args->GetArg(index));
for (index = i + 1, i += argcinresp; index < Args->NumArgs (); ++index) // Copy parameters from response file.
argv[i++] = Args->GetArg (index); for (index = 0; index < argc; ++i)
newargs->AppendArg(argv[index]);
Args->Destroy(); // Copy parameters after response file.
Args = new DArgs(i, argv); for (index = i + 1, i = newargs->NumArgs(); index < Args->NumArgs(); ++index)
newargs->AppendArg(Args->GetArg(index));
// Use the new argument vector as the global Args object.
Args = newargs;
} }
delete[] file; delete[] file;

View file

@ -789,7 +789,7 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y)); newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y));
vertnum = VertexMap->SelectVertexClose (newvert); vertnum = VertexMap->SelectVertexClose (newvert);
if (vertnum == seg->v1 || vertnum == seg->v2) if (vertnum == (unsigned int)seg->v1 || vertnum == (unsigned int)seg->v2)
{ {
Printf("SelectVertexClose selected endpoint of seg %u\n", set); Printf("SelectVertexClose selected endpoint of seg %u\n", set);
} }

View file

@ -3280,7 +3280,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
case ACSF_CheckActorClass: case ACSF_CheckActorClass:
{ {
AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL);
return a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1])); return a == NULL ? false : a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1]));
} }
case ACSF_SoundSequenceOnActor: case ACSF_SoundSequenceOnActor:
@ -5360,13 +5360,13 @@ int DLevelScript::RunScript ()
break; break;
case PCD_CLEARACTORINVENTORY: case PCD_CLEARACTORINVENTORY:
if (STACK(3) == 0) if (STACK(1) == 0)
{ {
ClearInventory(NULL); ClearInventory(NULL);
} }
else else
{ {
FActorIterator it(STACK(3)); FActorIterator it(STACK(1));
AActor *actor; AActor *actor;
for (actor = it.Next(); actor != NULL; actor = it.Next()) for (actor = it.Next(); actor != NULL; actor = it.Next())
{ {

View file

@ -109,6 +109,21 @@ struct spritetype
SWORD lotag, hitag, extra; SWORD lotag, hitag, extra;
}; };
// I used to have all the Xobjects mapped out. Not anymore.
// (Thanks for the great firmware, Seagate!)
struct Xsprite
{
BYTE NotReallyPadding[16];
WORD Data1;
WORD Data2;
WORD Data3;
WORD ThisIsntPaddingEither;
DWORD NorThis:2;
DWORD Data4:16;
DWORD WhatIsThisIDontEven:14;
BYTE ThisNeedsToBe56Bytes[28];
};
struct SlopeWork struct SlopeWork
{ {
walltype *wal; walltype *wal;
@ -128,7 +143,7 @@ void P_AdjustLine (line_t *line);
static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **sprites, int *numsprites); static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **sprites, int *numsprites);
static void LoadSectors (sectortype *bsectors); static void LoadSectors (sectortype *bsectors);
static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors); static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors);
static int LoadSprites (spritetype *sprites, int numsprites, sectortype *bsectors, FMapThing *mapthings); static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings);
static vertex_t *FindVertex (fixed_t x, fixed_t y); static 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);
static void CalcPlane (SlopeWork &slope, secplane_t &plane); static void CalcPlane (SlopeWork &slope, secplane_t &plane);
@ -145,8 +160,10 @@ static void Decrypt (void *to, const void *from, int len, int key);
bool P_IsBuildMap(MapData *map) bool P_IsBuildMap(MapData *map)
{ {
DWORD len = map->Size(ML_LABEL); DWORD len = map->Size(ML_LABEL);
if (len < 4) return false; if (len < 4)
{
return false;
}
BYTE *data = new BYTE[len]; BYTE *data = new BYTE[len];
map->Seek(ML_LABEL); map->Seek(ML_LABEL);
@ -215,7 +232,7 @@ bool P_LoadBuildMap (BYTE *data, size_t len, FMapThing **sprites, int *numspr)
*sprites = new FMapThing[numsprites + 1]; *sprites = new FMapThing[numsprites + 1];
CreateStartSpot ((fixed_t *)(data + 4), *sprites); CreateStartSpot ((fixed_t *)(data + 4), *sprites);
*numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)), *numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)),
numsprites, (sectortype *)(data + 22), *sprites + 1); NULL, numsprites, (sectortype *)(data + 22), *sprites + 1);
return true; return true;
} }
@ -251,11 +268,11 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int *
{ {
memcpy (infoBlock, data + 6, 37); memcpy (infoBlock, data + 6, 37);
} }
numRevisions = *(DWORD *)(infoBlock + 27); numRevisions = LittleLong(*(DWORD *)(infoBlock + 27));
numsectors = *(WORD *)(infoBlock + 31); numsectors = LittleShort(*(WORD *)(infoBlock + 31));
numWalls = *(WORD *)(infoBlock + 33); numWalls = LittleShort(*(WORD *)(infoBlock + 33));
numsprites = *(WORD *)(infoBlock + 35); numsprites = LittleShort(*(WORD *)(infoBlock + 35));
skyLen = 2 << *(WORD *)(infoBlock + 16); skyLen = 2 << LittleShort(*(WORD *)(infoBlock + 16));
if (mapver == 7) if (mapver == 7)
{ {
@ -275,6 +292,7 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int *
sectortype *bsec = new sectortype[numsectors]; sectortype *bsec = new sectortype[numsectors];
walltype *bwal = new walltype[numWalls]; walltype *bwal = new walltype[numWalls];
spritetype *bspr = new spritetype[numsprites]; spritetype *bspr = new spritetype[numsprites];
Xsprite *xspr = new Xsprite[numsprites];
// Read sectors // Read sectors
k = numRevisions * sizeof(sectortype); k = numRevisions * sizeof(sectortype);
@ -327,9 +345,15 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int *
memcpy (&bspr[i], data, sizeof(spritetype)); memcpy (&bspr[i], data, sizeof(spritetype));
} }
data += sizeof(spritetype); data += sizeof(spritetype);
if (bspr[i].extra > 0) // skip Xsprite if (bspr[i].extra > 0) // copy Xsprite
{ {
data += 56; assert(sizeof(Xsprite) == 56);
memcpy(&xspr[i], data, sizeof(Xsprite));
data += sizeof(Xsprite);
}
else
{
memset(&xspr[i], 0, sizeof(Xsprite));
} }
} }
@ -339,11 +363,12 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int *
LoadWalls (bwal, numWalls, bsec); LoadWalls (bwal, numWalls, bsec);
*mapthings = new FMapThing[numsprites + 1]; *mapthings = new FMapThing[numsprites + 1];
CreateStartSpot ((fixed_t *)infoBlock, *mapthings); CreateStartSpot ((fixed_t *)infoBlock, *mapthings);
*numspr = 1 + LoadSprites (bspr, numsprites, bsec, *mapthings + 1); *numspr = 1 + LoadSprites (bspr, xspr, numsprites, bsec, *mapthings + 1);
delete[] bsec; delete[] bsec;
delete[] bwal; delete[] bwal;
delete[] bspr; delete[] bspr;
delete[] xspr;
return true; return true;
} }
@ -363,6 +388,8 @@ static void LoadSectors (sectortype *bsec)
sec = sectors = new sector_t[numsectors]; sec = sectors = new sector_t[numsectors];
memset (sectors, 0, sizeof(sector_t)*numsectors); memset (sectors, 0, sizeof(sector_t)*numsectors);
sectors[0].e = new extsector_t[numsectors];
for (int i = 0; i < numsectors; ++i, ++bsec, ++sec) for (int i = 0; i < numsectors; ++i, ++bsec, ++sec)
{ {
bsec->wallptr = WORD(bsec->wallptr); bsec->wallptr = WORD(bsec->wallptr);
@ -370,6 +397,7 @@ static void LoadSectors (sectortype *bsec)
bsec->ceilingstat = WORD(bsec->ceilingstat); bsec->ceilingstat = WORD(bsec->ceilingstat);
bsec->floorstat = WORD(bsec->floorstat); bsec->floorstat = WORD(bsec->floorstat);
sec->e = &sectors[0].e[i];
sec->SetPlaneTexZ(sector_t::floor, -(LittleLong(bsec->floorz) << 8)); sec->SetPlaneTexZ(sector_t::floor, -(LittleLong(bsec->floorz) << 8));
sec->floorplane.d = -sec->GetPlaneTexZ(sector_t::floor); sec->floorplane.d = -sec->GetPlaneTexZ(sector_t::floor);
sec->floorplane.c = FRACUNIT; sec->floorplane.c = FRACUNIT;
@ -512,6 +540,8 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
} }
sides[i].TexelLength = walls[i].xrepeat * 8; sides[i].TexelLength = walls[i].xrepeat * 8;
sides[i].SetTextureYScale(walls[i].yrepeat << (FRACBITS - 3));
sides[i].SetTextureXScale(FRACUNIT);
sides[i].SetLight(SHADE2LIGHT(walls[i].shade)); sides[i].SetLight(SHADE2LIGHT(walls[i].shade));
sides[i].Flags = WALLF_ABSLIGHTING; sides[i].Flags = WALLF_ABSLIGHTING;
sides[i].RightSide = walls[i].point2; sides[i].RightSide = walls[i].point2;
@ -631,14 +661,17 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
R_AlignFlat (linenum, sidenum == bsec->wallptr, 0); R_AlignFlat (linenum, sidenum == bsec->wallptr, 0);
} }
} }
for(i = 0; i < numsides; i++)
{
sides[i].linedef = &lines[intptr_t(sides[i].linedef)];
}
for (i = 0; i < numlines; i++) for (i = 0; i < numlines; i++)
{ {
lines[i].sidedef[0] = &sides[intptr_t(lines[i].sidedef[0])]; intptr_t front = intptr_t(lines[i].sidedef[0]);
lines[i].sidedef[1] = &sides[intptr_t(lines[i].sidedef[1])]; intptr_t back = intptr_t(lines[i].sidedef[1]);
lines[i].sidedef[0] = front >= 0 ? &sides[front] : NULL;
lines[i].sidedef[1] = back >= 0 ? &sides[back] : NULL;
}
for (i = 0; i < numsides; i++)
{
assert(sides[i].sector != NULL);
sides[i].linedef = &lines[intptr_t(sides[i].linedef)];
} }
} }
@ -648,32 +681,46 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
// //
//========================================================================== //==========================================================================
static int LoadSprites (spritetype *sprites, int numsprites, sectortype *bsectors, static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites,
FMapThing *mapthings) sectortype *bsectors, FMapThing *mapthings)
{ {
int count = 0; int count = 0;
for (int i = 0; i < numsprites; ++i) for (int i = 0; i < numsprites; ++i)
{ {
if (sprites[i].cstat & (16|32|32768)) continue;
if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue;
mapthings[count].thingid = 0; mapthings[count].thingid = 0;
mapthings[count].x = (sprites[i].x << 12); mapthings[count].x = (sprites[i].x << 12);
mapthings[count].y = -(sprites[i].y << 12); mapthings[count].y = -(sprites[i].y << 12);
mapthings[count].z = (bsectors[sprites[i].sectnum].floorz - sprites[i].z) << 8; mapthings[count].z = (bsectors[sprites[i].sectnum].floorz - sprites[i].z) << 8;
mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11; mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11;
mapthings[count].type = 9988;
mapthings[count].ClassFilter = 0xffff; mapthings[count].ClassFilter = 0xffff;
mapthings[count].SkillFilter = 0xffff; mapthings[count].SkillFilter = 0xffff;
mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH; mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH;
mapthings[count].special = 0; mapthings[count].special = 0;
if (xsprites != NULL && sprites[i].lotag == 710)
{ // Blood ambient sound
mapthings[count].args[0] = xsprites[i].Data3;
// I am totally guessing abount the volume level. 50 seems to be a pretty
// typical value for Blood's standard maps, so I assume it's 100-based.
mapthings[count].args[1] = xsprites[i].Data4;
mapthings[count].args[2] = xsprites[i].Data1;
mapthings[count].args[3] = xsprites[i].Data2;
mapthings[count].args[4] = 0;
mapthings[count].type = 14065;
}
else
{
if (sprites[i].cstat & (16|32|32768)) continue;
if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue;
mapthings[count].type = 9988;
mapthings[count].args[0] = sprites[i].picnum & 255; mapthings[count].args[0] = sprites[i].picnum & 255;
mapthings[count].args[1] = sprites[i].picnum >> 8; mapthings[count].args[1] = sprites[i].picnum >> 8;
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 & 14) | ((sprites[i].cstat >> 9) & 1); mapthings[count].args[4] = (sprites[i].cstat & 14) | ((sprites[i].cstat >> 9) & 1);
}
count++; count++;
} }
return count; return count;

View file

@ -198,16 +198,16 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash) void P_NoiseAlert (AActor *target, AActor *emitter, bool splash)
{ {
if (emmiter == NULL) if (emitter == NULL)
return; return;
if (target != NULL && target->player && (target->player->cheats & CF_NOTARGET)) if (target != NULL && target->player && (target->player->cheats & CF_NOTARGET))
return; return;
validcount++; validcount++;
P_RecursiveSound (emmiter->Sector, target, splash, 0); P_RecursiveSound (emitter->Sector, target, splash, 0);
} }
@ -308,7 +308,7 @@ bool P_CheckMissileRange (AActor *actor)
{ {
fixed_t dist; fixed_t dist;
if (!P_CheckSight (actor, actor->target, 4)) if (!P_CheckSight (actor, actor->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
return false; return false;
if (actor->flags & MF_JUSTHIT) if (actor->flags & MF_JUSTHIT)
@ -1136,7 +1136,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams
} }
// P_CheckSight is by far the most expensive operation in here so let's do it last. // P_CheckSight is by far the most expensive operation in here so let's do it last.
return P_CheckSight(lookee, other, 2); return P_CheckSight(lookee, other, SF_SEEPASTBLOCKEVERYTHING);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -1154,7 +1154,7 @@ bool P_LookForMonsters (AActor *actor)
AActor *mo; AActor *mo;
TThinkerIterator<AActor> iterator; TThinkerIterator<AActor> iterator;
if (!P_CheckSight (players[0].mo, actor, 2)) if (!P_CheckSight (players[0].mo, actor, SF_SEEPASTBLOCKEVERYTHING))
{ // Player can't see monster { // Player can't see monster
return false; return false;
} }
@ -1178,11 +1178,11 @@ bool P_LookForMonsters (AActor *actor)
{ // Stop searching { // Stop searching
return false; return false;
} }
if (mo->IsKindOf (actor->GetClass()) || actor->IsKindOf (mo->GetClass())) if (mo->GetSpecies() == actor->GetSpecies())
{ // [RH] Don't go after same species { // [RH] Don't go after same species
continue; continue;
} }
if (!P_CheckSight (actor, mo, 2)) if (!P_CheckSight (actor, mo, SF_SEEPASTBLOCKEVERYTHING))
{ // Out of sight { // Out of sight
continue; continue;
} }
@ -1765,7 +1765,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
if (self->flags & MF_AMBUSH) if (self->flags & MF_AMBUSH)
{ {
if (P_CheckSight (self, self->target, 2)) if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING))
goto seeyou; goto seeyou;
} }
else else
@ -1933,7 +1933,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
if (self->flags & MF_AMBUSH) if (self->flags & MF_AMBUSH)
{ {
dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y);
if (P_CheckSight (self, self->target, 2) && if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) &&
(!minseedist || dist > minseedist) && (!minseedist || dist > minseedist) &&
(!maxseedist || dist < maxseedist)) (!maxseedist || dist < maxseedist))
{ {
@ -2070,7 +2070,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2)
{ {
if (self->flags & MF_AMBUSH) if (self->flags & MF_AMBUSH)
{ {
if (!P_CheckSight (self, targ, 2)) if (!P_CheckSight (self, targ, SF_SEEPASTBLOCKEVERYTHING))
goto nosee; goto nosee;
} }
self->target = targ; self->target = targ;
@ -2745,7 +2745,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
self->target->x, self->target->x,
self->target->y); self->target->y);
self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, false, false, false, self->target); self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target);
if (linetarget == NULL) if (linetarget == NULL)
{ {
// We probably won't hit the target, but aim at it anyway so we don't look stupid. // We probably won't hit the target, but aim at it anyway so we don't look stupid.

View file

@ -1274,7 +1274,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
painchance = target->PainChance; painchance = target->PainChance;
if (pc != NULL) if (pc != NULL)
{ {
BYTE * ppc = pc->CheckKey(mod); int *ppc = pc->CheckKey(mod);
if (ppc != NULL) if (ppc != NULL)
{ {
painchance = *ppc; painchance = *ppc;

View file

@ -189,8 +189,11 @@ FUNC(LS_Door_CloseWaitOpen)
} }
FUNC(LS_Door_Animated) FUNC(LS_Door_Animated)
// Door_Animated (tag, speed, delay) // Door_Animated (tag, speed, delay, lock)
{ {
if (arg3 != 0 && !P_CheckKeys (it, arg3, arg0 != 0))
return false;
return EV_SlidingDoor (ln, it, arg0, arg1, arg2); return EV_SlidingDoor (ln, it, arg0, arg1, arg2);
} }

View file

@ -394,6 +394,15 @@ void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
bool P_BounceWall (AActor *mo); bool P_BounceWall (AActor *mo);
bool P_BounceActor (AActor *mo, AActor * BlockingMobj); bool P_BounceActor (AActor *mo, AActor * BlockingMobj);
bool P_CheckSight (const AActor* t1, const AActor* t2, int flags=0); bool P_CheckSight (const AActor* t1, const AActor* t2, int flags=0);
enum ESightFlags
{
SF_IGNOREVISIBILITY=1,
SF_SEEPASTSHOOTABLELINES=2,
SF_SEEPASTBLOCKEVERYTHING=4,
SF_IGNOREWATERBOUNDARY=8
};
void P_ResetSightCounters (bool full); void P_ResetSightCounters (bool full);
bool P_TalkFacing (AActor *player); bool P_TalkFacing (AActor *player);
void P_UseLines (player_t* player); void P_UseLines (player_t* player);
@ -402,7 +411,16 @@ void P_FindFloorCeiling (AActor *actor, bool onlymidtex = false);
bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset);
fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, bool forcenosmart=false, bool check3d = false, bool checknonshootable = false, AActor *target=NULL); fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL);
enum
{
ALF_FORCENOSMART = 1,
ALF_CHECK3D = 2,
ALF_CHECKNONSHOOTABLE = 4,
ALF_CHECKCONVERSATION = 8,
};
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, bool ismelee = false); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, bool ismelee = false);
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false);
void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch);

View file

@ -2807,8 +2807,7 @@ struct aim_t
AActor * linetarget; AActor * linetarget;
AActor * thing_friend, * thing_other; AActor * thing_friend, * thing_other;
angle_t pitch_friend, pitch_other; angle_t pitch_friend, pitch_other;
bool notsmart; int flags;
bool check3d;
#ifdef _3DFLOORS #ifdef _3DFLOORS
sector_t * lastsector; sector_t * lastsector;
secplane_t * lastfloorplane; secplane_t * lastfloorplane;
@ -2819,7 +2818,7 @@ struct aim_t
bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in); bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in);
#endif #endif
void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool checknonshootable = false, AActor *target=NULL); void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target=NULL);
}; };
@ -2936,7 +2935,7 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in)
// //
//============================================================================ //============================================================================
void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool checknonshootable, AActor *target) void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target)
{ {
FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS); FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in; intercept_t *in;
@ -2994,7 +2993,11 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
if (target != NULL && th != target) if (target != NULL && th != target)
continue; // only care about target, and you're not it continue; // only care about target, and you're not it
if (!checknonshootable) // For info CCMD, ignore stuff about GHOST and SHOOTABLE flags // If we want to start a conversation anything that has one should be
// found, regardless of other settings.
if (!(flags & ALF_CHECKCONVERSATION) || th->Conversation == NULL)
{
if (!(flags & ALF_CHECKNONSHOOTABLE)) // For info CCMD, ignore stuff about GHOST and SHOOTABLE flags
{ {
if (!(th->flags&MF_SHOOTABLE)) if (!(th->flags&MF_SHOOTABLE))
continue; // corpse or something continue; // corpse or something
@ -3008,6 +3011,7 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
continue; continue;
} }
} }
}
dist = FixedMul (attackrange, in->frac); dist = FixedMul (attackrange, in->frac);
#ifdef _3DFLOORS #ifdef _3DFLOORS
@ -3053,7 +3057,7 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
if (crossedffloors) if (crossedffloors)
{ {
// if 3D floors were in the way do an extra visibility check for safety // if 3D floors were in the way do an extra visibility check for safety
if (!P_CheckSight(shootthing, th, 1)) if (!P_CheckSight(shootthing, th, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
{ {
// the thing can't be seen so we can safely exclude its range from our aiming field // the thing can't be seen so we can safely exclude its range from our aiming field
if (thingtoppitch<toppitch) if (thingtoppitch<toppitch)
@ -3079,7 +3083,7 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
thingpitch = thingtoppitch/2 + thingbottompitch/2; thingpitch = thingtoppitch/2 + thingbottompitch/2;
if (check3d) if (flags & ALF_CHECK3D)
{ {
// We need to do a 3D distance check here because this is nearly always used in // We need to do a 3D distance check here because this is nearly always used in
// combination with P_LineAttack. P_LineAttack uses 3D distance but FPathTraverse // combination with P_LineAttack. P_LineAttack uses 3D distance but FPathTraverse
@ -3096,7 +3100,7 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
} }
} }
if (sv_smartaim && !notsmart) if (sv_smartaim != 0 && !(flags & ALF_FORCENOSMART))
{ {
// try to be a little smarter about what to aim at! // try to be a little smarter about what to aim at!
// In particular avoid autoaiming at friends amd barrels. // In particular avoid autoaiming at friends amd barrels.
@ -3131,11 +3135,6 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
aimpitch = thingpitch; aimpitch = thingpitch;
return; return;
} }
if (checknonshootable)
{
linetarget = th;
aimpitch = thingpitch;
}
} }
} }
@ -3145,15 +3144,16 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
// //
//============================================================================ //============================================================================
fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget, fixed_t vrange, bool forcenosmart, bool check3d, bool checknonshootable, AActor *target) fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget, fixed_t vrange,
int flags, AActor *target)
{ {
fixed_t x2; fixed_t x2;
fixed_t y2; fixed_t y2;
aim_t aim; aim_t aim;
angle >>= ANGLETOFINESHIFT; angle >>= ANGLETOFINESHIFT;
aim.flags = flags;
aim.shootthing = t1; aim.shootthing = t1;
aim.check3d = check3d;
x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
@ -3194,7 +3194,6 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p
} }
aim.toppitch = t1->pitch - vrange; aim.toppitch = t1->pitch - vrange;
aim.bottompitch = t1->pitch + vrange; aim.bottompitch = t1->pitch + vrange;
aim.notsmart = forcenosmart;
aim.attackrange = distance; aim.attackrange = distance;
aim.linetarget = NULL; aim.linetarget = NULL;
@ -3223,7 +3222,7 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p
} }
#endif #endif
aim.AimTraverse (t1->x, t1->y, x2, y2, checknonshootable, target); aim.AimTraverse (t1->x, t1->y, x2, y2, target);
if (!aim.linetarget) if (!aim.linetarget)
{ {
@ -3239,7 +3238,9 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p
} }
} }
if (pLineTarget) if (pLineTarget)
{
*pLineTarget = aim.linetarget; *pLineTarget = aim.linetarget;
}
return aim.linetarget ? aim.aimpitch : t1->pitch; return aim.linetarget ? aim.aimpitch : t1->pitch;
} }
@ -3588,7 +3589,7 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, a
{ {
if (bleedtrace.HitType == TRACE_HitWall) if (bleedtrace.HitType == TRACE_HitWall)
{ {
PalEntry bloodcolor = actor->GetClass()->BloodColor; PalEntry bloodcolor = actor->GetBloodColor();
if (bloodcolor != 0) if (bloodcolor != 0)
{ {
bloodcolor.r>>=1; // the full color is too bright for blood decals bloodcolor.r>>=1; // the full color is too bright for blood decals
@ -3921,13 +3922,13 @@ bool P_TalkFacing(AActor *player)
{ {
AActor *linetarget; AActor *linetarget;
P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1*35, true); P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION);
if (linetarget == NULL) if (linetarget == NULL)
{ {
P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, true); P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION);
if (linetarget == NULL) if (linetarget == NULL)
{ {
P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, true); P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION);
if (linetarget == NULL) if (linetarget == NULL)
{ {
return false; return false;
@ -4327,7 +4328,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
} }
points *= thing->GetClass()->RDFactor/(float)FRACUNIT; points *= thing->GetClass()->RDFactor/(float)FRACUNIT;
if (points > 0.f && P_CheckSight (thing, bombspot, 1)) if (points > 0.f && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
float velz; float velz;
float thrust; float thrust;
@ -4385,7 +4386,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
if (dist >= bombdistance) if (dist >= bombdistance)
continue; // out of range continue; // out of range
if (P_CheckSight (thing, bombspot, 1)) if (P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
dist = clamp<int>(dist - fulldamagedistance, 0, dist); dist = clamp<int>(dist - fulldamagedistance, 0, dist);
int damage = Scale (bombdamage, bombdistance-dist, bombdistance); int damage = Scale (bombdamage, bombdistance-dist, bombdistance);
@ -4595,11 +4596,12 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos)
P_DamageMobj (thing, NULL, NULL, cpos->crushchange, NAME_Crush); P_DamageMobj (thing, NULL, NULL, cpos->crushchange, NAME_Crush);
// spray blood in a random direction // spray blood in a random direction
if ((!(thing->flags&MF_NOBLOOD)) && if (!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT)))
(!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT))))
{ {
PalEntry bloodcolor = thing->GetClass()->BloodColor; if (!(thing->flags&MF_NOBLOOD))
PClassActor *bloodcls = PClass::FindActor(thing->GetClass()->BloodType); {
PalEntry bloodcolor = thing->GetBloodColor();
PClassActor *bloodcls = thing->GetBloodType();
P_TraceBleed (cpos->crushchange, thing); P_TraceBleed (cpos->crushchange, thing);
if (cl_bloodtype <= 1 && bloodcls != NULL) if (cl_bloodtype <= 1 && bloodcls != NULL)
@ -4625,6 +4627,11 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos)
thing->z + thing->height/2, an, 2, bloodcolor); thing->z + thing->height/2, an, 2, bloodcolor);
} }
} }
if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound))
{
S_Sound(thing, CHAN_VOICE, thing->CrushPainSound, 1.f, ATTN_NORM);
}
}
} }
// keep checking (crush other things) // keep checking (crush other things)

View file

@ -270,8 +270,12 @@ void AActor::Serialize (FArchive &arc)
<< ActiveSound << ActiveSound
<< UseSound << UseSound
<< BounceSound << BounceSound
<< WallBounceSound << WallBounceSound;
<< Speed if (SaveVersion >= 2234)
{
arc << CrushPainSound;
}
arc << Speed
<< FloatSpeed << FloatSpeed
<< Mass << Mass
<< PainChance << PainChance
@ -1069,7 +1073,7 @@ bool AActor::Grind(bool items)
if (isgeneric) // Not a custom crush state, so colorize it appropriately. if (isgeneric) // Not a custom crush state, so colorize it appropriately.
{ {
S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE);
PalEntry bloodcolor = GetClass()->BloodColor; PalEntry bloodcolor = GetBloodColor();
if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
} }
return false; return false;
@ -1113,7 +1117,7 @@ bool AActor::Grind(bool items)
} }
S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE);
PalEntry bloodcolor = GetClass()->BloodColor; PalEntry bloodcolor = GetBloodColor();
if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
} }
if (flags & MF_ICECORPSE) if (flags & MF_ICECORPSE)
@ -2130,6 +2134,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
fixed_t dist; fixed_t dist;
fixed_t delta; fixed_t delta;
fixed_t oldz = mo->z; fixed_t oldz = mo->z;
fixed_t grav = mo->GetGravity();
// //
// check for smooth step up // check for smooth step up
@ -2155,8 +2160,6 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
if (!mo->waterlevel || mo->flags & MF_CORPSE || (mo->player && if (!mo->waterlevel || mo->flags & MF_CORPSE || (mo->player &&
!(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove))) !(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove)))
{ {
fixed_t grav = mo->GetGravity();
// [RH] Double gravity only if running off a ledge. Coming down from // [RH] Double gravity only if running off a ledge. Coming down from
// an upward thrust (e.g. a jump) should not double it. // an upward thrust (e.g. a jump) should not double it.
if (mo->velz == 0 && oldfloorz > mo->floorz && mo->z == oldfloorz) if (mo->velz == 0 && oldfloorz > mo->floorz && mo->z == oldfloorz)
@ -2230,12 +2233,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
// teleported the actor so it is no longer below the floor. // teleported the actor so it is no longer below the floor.
if (mo->z <= mo->floorz) if (mo->z <= mo->floorz)
{ {
// old code for boss cube disabled if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP))
//if ((mo->flags & MF_MISSILE) && (!(gameinfo.gametype & GAME_DoomChex) || !(mo->flags & MF_NOCLIP)))
// We can't remove this completely because it was abused by some DECORATE definitions
// (e.g. the monster pack's Afrit)
if ((mo->flags & MF_MISSILE) && ((mo->flags & MF_NOGRAVITY) || !(mo->flags & MF_NOCLIP)))
{ {
mo->z = mo->floorz; mo->z = mo->floorz;
if (mo->BounceFlags & BOUNCE_Floors) if (mo->BounceFlags & BOUNCE_Floors)
@ -2297,7 +2295,10 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
mo->HitFloor (); mo->HitFloor ();
if (mo->player) if (mo->player)
{ {
mo->player->jumpTics = 7; // delay any jumping for a short while if (mo->player->jumpTics != 0 && mo->velz < -grav*4)
{ // delay any jumping for a short while
mo->player->jumpTics = 7;
}
if (mo->velz < minvel && !(mo->flags & MF_NOGRAVITY)) if (mo->velz < minvel && !(mo->flags & MF_NOGRAVITY))
{ {
// Squat down. // Squat down.
@ -2346,8 +2347,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
} }
if (mo->velz > 0) if (mo->velz > 0)
mo->velz = 0; mo->velz = 0;
if (mo->flags & MF_MISSILE) if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP))
//&& (!(gameinfo.gametype & GAME_DoomChex) || !(mo->flags & MF_NOCLIP)))
{ {
if (mo->flags3 & MF3_CEILINGHUGGER) if (mo->flags3 & MF3_CEILINGHUGGER)
{ {
@ -2615,11 +2615,6 @@ void AActor::RemoveFromHash ()
tid = 0; tid = 0;
} }
angle_t AActor::AngleIncrements ()
{
return ANGLE_45;
}
//========================================================================== //==========================================================================
// //
// AActor :: GetMissileDamage // AActor :: GetMissileDamage
@ -3022,7 +3017,7 @@ void AActor::Tick ()
&& !players[i].enemy && !players[i].enemy
&& player ? !IsTeammate (players[i].mo) : true && player ? !IsTeammate (players[i].mo) : true
&& P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST
&& P_CheckSight (players[i].mo, this, 2)) && P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING))
{ //Probably a monster, so go kill it. { //Probably a monster, so go kill it.
players[i].enemy = this; players[i].enemy = this;
} }
@ -3700,8 +3695,6 @@ void AActor::LevelSpawned ()
{ {
if (tics > 0 && !(flags4 & MF4_SYNCHRONIZED)) if (tics > 0 && !(flags4 & MF4_SYNCHRONIZED))
tics = 1 + (pr_spawnmapthing() % tics); tics = 1 + (pr_spawnmapthing() % tics);
angle_t incs = AngleIncrements ();
angle -= angle % incs;
flags &= ~MF_DROPPED; // [RH] clear MF_DROPPED flag flags &= ~MF_DROPPED; // [RH] clear MF_DROPPED flag
HandleSpawnFlags (); HandleSpawnFlags ();
} }
@ -3960,8 +3953,16 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer)
{ {
spawn_x = mthing->x; spawn_x = mthing->x;
spawn_y = mthing->y; spawn_y = mthing->y;
// Allow full angular precision but avoid roundoff errors for multiples of 45 degrees.
if (mthing->angle % 45 != 0)
{
spawn_angle = mthing->angle * (ANG45 / 45);
}
else
{
spawn_angle = ANG45 * (mthing->angle / 45); spawn_angle = ANG45 * (mthing->angle / 45);
} }
}
mobj = static_cast<APlayerPawn *> mobj = static_cast<APlayerPawn *>
(Spawn (p->cls, spawn_x, spawn_y, ONFLOORZ, NO_REPLACE)); (Spawn (p->cls, spawn_x, spawn_y, ONFLOORZ, NO_REPLACE));
@ -3986,11 +3987,15 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer)
p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass); p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass);
StatusBar->SetFace (&skins[p->userinfo.skin]); StatusBar->SetFace (&skins[p->userinfo.skin]);
if (!(mobj->flags2 & MF2_DONTTRANSLATE))
{
// [RH] Be sure the player has the right translation // [RH] Be sure the player has the right translation
R_BuildPlayerTranslation (playernum); R_BuildPlayerTranslation (playernum);
// [RH] set color translations for player sprites // [RH] set color translations for player sprites
mobj->Translation = TRANSLATION(TRANSLATION_Players,playernum); mobj->Translation = TRANSLATION(TRANSLATION_Players,playernum);
}
mobj->angle = spawn_angle; mobj->angle = spawn_angle;
mobj->pitch = mobj->roll = 0; mobj->pitch = mobj->roll = 0;
@ -4506,8 +4511,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y
void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator) void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator)
{ {
AActor *th; AActor *th;
PalEntry bloodcolor = originator->GetClass()->BloodColor; PalEntry bloodcolor = originator->GetBloodColor();
PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType); PClassActor *bloodcls = originator->GetBloodType();
int bloodtype = cl_bloodtype; int bloodtype = cl_bloodtype;
@ -4568,8 +4573,8 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{ {
PalEntry bloodcolor = originator->GetClass()->BloodColor; PalEntry bloodcolor = originator->GetBloodColor();
PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType2); PClassActor *bloodcls = originator->GetBloodType(1);
int bloodtype = cl_bloodtype; int bloodtype = cl_bloodtype;
@ -4606,8 +4611,8 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{ {
PalEntry bloodcolor = originator->GetClass()->BloodColor; PalEntry bloodcolor = originator->GetBloodColor();
PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType3); PClassActor *bloodcls = originator->GetBloodType(2);
int bloodtype = cl_bloodtype; int bloodtype = cl_bloodtype;
@ -4645,8 +4650,8 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
void P_RipperBlood (AActor *mo, AActor *bleeder) void P_RipperBlood (AActor *mo, AActor *bleeder)
{ {
fixed_t x, y, z; fixed_t x, y, z;
PalEntry bloodcolor = bleeder->GetClass()->BloodColor; PalEntry bloodcolor = bleeder->GetBloodColor();
PClassActor *bloodcls = PClass::FindActor(bleeder->GetClass()->BloodType); PClassActor *bloodcls = bleeder->GetBloodType();
x = mo->x + (pr_ripperblood.Random2 () << 12); x = mo->x + (pr_ripperblood.Random2 () << 12);
y = mo->y + (pr_ripperblood.Random2 () << 12); y = mo->y + (pr_ripperblood.Random2 () << 12);

View file

@ -294,8 +294,10 @@ MapData *P_OpenMapData(const char * mapname)
{ {
// The following lump is from a different file so whatever this is, // The following lump is from a different file so whatever this is,
// it is not a multi-lump Doom level so let's assume it is a Build map. // it is not a multi-lump Doom level so let's assume it is a Build map.
map->MapLumps[0].FilePos = Wads.GetLumpOffset(lump_name); map->MapLumps[0].FilePos = 0;
map->MapLumps[0].Size = Wads.LumpLength(lump_name); map->MapLumps[0].Size = Wads.LumpLength(lump_name);
map->file = Wads.ReopenLumpNum(lump_name);
map->CloseOnDestruct = true;
if (!P_IsBuildMap(map)) if (!P_IsBuildMap(map))
{ {
delete map; delete map;
@ -312,6 +314,9 @@ MapData *P_OpenMapData(const char * mapname)
if (map->Encrypted) if (map->Encrypted)
{ // If it's encrypted, then it's a Blood file, presumably a map. { // If it's encrypted, then it's a Blood file, presumably a map.
map->file = Wads.ReopenLumpNum(lump_name);
map->CloseOnDestruct = true;
map->MapLumps[0].FilePos = 0;
if (!P_IsBuildMap(map)) if (!P_IsBuildMap(map))
{ {
delete map; delete map;
@ -322,7 +327,7 @@ MapData *P_OpenMapData(const char * mapname)
int index = 0; int index = 0;
if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP")) if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP") != 0)
{ {
for(int i = 1;; i++) for(int i = 1;; i++)
{ {
@ -404,7 +409,8 @@ MapData *P_OpenMapData(const char * mapname)
} }
} }
DWORD id; DWORD id;
(*map->file) >> id;
map->file->Read(&id, sizeof(id));
if (id == IWAD_ID || id == PWAD_ID) if (id == IWAD_ID || id == PWAD_ID)
{ {
@ -705,9 +711,15 @@ void P_FloodZone (sector_t *sec, int zonenum)
continue; continue;
if (check->frontsector == sec) if (check->frontsector == sec)
{
assert(check->backsector != NULL);
other = check->backsector; other = check->backsector;
}
else else
{
assert(check->frontsector != NULL);
other = check->frontsector; other = check->frontsector;
}
if (other->ZoneNumber != zonenum) if (other->ZoneNumber != zonenum)
P_FloodZone (other, zonenum); P_FloodZone (other, zonenum);
@ -717,6 +729,7 @@ void P_FloodZone (sector_t *sec, int zonenum)
void P_FloodZones () void P_FloodZones ()
{ {
int z = 0, i; int z = 0, i;
ReverbContainer *reverb;
for (i = 0; i < numsectors; ++i) for (i = 0; i < numsectors; ++i)
{ {
@ -727,9 +740,15 @@ void P_FloodZones ()
} }
numzones = z; numzones = z;
zones = new zone_t[z]; zones = new zone_t[z];
reverb = S_FindEnvironment(level.DefaultEnvironment);
if (reverb == NULL)
{
Printf("Sound environment %d, %d not found\n", level.DefaultEnvironment >> 8, level.DefaultEnvironment & 255);
reverb = DefaultEnvironments[0];
}
for (i = 0; i < z; ++i) for (i = 0; i < z; ++i)
{ {
zones[i].Environment = DefaultEnvironments[0]; zones[i].Environment = reverb;
} }
} }
@ -3395,11 +3414,9 @@ void P_SetupLevel (char *lumpname, int position)
BYTE *mapdata = new BYTE[map->MapLumps[0].Size]; BYTE *mapdata = new BYTE[map->MapLumps[0].Size];
map->Seek(0); map->Seek(0);
map->file->Read(mapdata, map->MapLumps[0].Size); map->file->Read(mapdata, map->MapLumps[0].Size);
if (map->Encrypted) times[0].Clock();
{
BloodCrypt (mapdata, 0, MIN<int> (map->MapLumps[0].Size, 256));
}
buildmap = P_LoadBuildMap (mapdata, map->MapLumps[0].Size, &buildthings, &numbuildthings); buildmap = P_LoadBuildMap (mapdata, map->MapLumps[0].Size, &buildthings, &numbuildthings);
times[0].Unclock();
delete[] mapdata; delete[] mapdata;
} }

View file

@ -53,7 +53,7 @@ class SightCheck
fixed_t lastzbottom; // z at last line fixed_t lastzbottom; // z at last line
sector_t * lastsector; // last sector being entered by trace sector_t * lastsector; // last sector being entered by trace
fixed_t topslope, bottomslope; // slopes to top and bottom of target fixed_t topslope, bottomslope; // slopes to top and bottom of target
int SeePastBlockEverything, SeePastShootableLines; int Flags;
divline_t trace; divline_t trace;
int myseethrough; int myseethrough;
@ -73,9 +73,8 @@ public:
seeingthing=t2; seeingthing=t2;
bottomslope = t2->z - sightzstart; bottomslope = t2->z - sightzstart;
topslope = bottomslope + t2->height; topslope = bottomslope + t2->height;
Flags = flags;
SeePastBlockEverything = flags & 6;
SeePastShootableLines = flags & 4;
myseethrough = FF_SEETHROUGH; myseethrough = FF_SEETHROUGH;
} }
}; };
@ -144,6 +143,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
F3DFloor* rover=s->e->XFloor.ffloors[j]; F3DFloor* rover=s->e->XFloor.ffloors[j];
if((rover->flags & FF_SEETHROUGH) == myseethrough || !(rover->flags & FF_EXISTS)) continue; if((rover->flags & FF_SEETHROUGH) == myseethrough || !(rover->flags & FF_EXISTS)) continue;
if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY); fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY);
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY); fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
@ -176,6 +176,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
F3DFloor* rover2=sb->e->XFloor.ffloors[k]; F3DFloor* rover2=sb->e->XFloor.ffloors[k];
if((rover2->flags & FF_SEETHROUGH) == myseethrough || !(rover2->flags & FF_EXISTS)) continue; if((rover2->flags & FF_SEETHROUGH) == myseethrough || !(rover2->flags & FF_EXISTS)) continue;
if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue;
fixed_t ffb_bottom=rover2->bottom.plane->ZatPoint(trX, trY); fixed_t ffb_bottom=rover2->bottom.plane->ZatPoint(trX, trY);
fixed_t ffb_top=rover2->top.plane->ZatPoint(trX, trY); fixed_t ffb_top=rover2->top.plane->ZatPoint(trX, trY);
@ -255,7 +256,7 @@ bool SightCheck::P_SightCheckLine (line_t *ld)
// [RH] don't see past block everything lines // [RH] don't see past block everything lines
if (ld->flags & ML_BLOCKEVERYTHING) if (ld->flags & ML_BLOCKEVERYTHING)
{ {
if (!SeePastBlockEverything) if (!(Flags & SF_SEEPASTBLOCKEVERYTHING))
{ {
return false; return false;
} }
@ -263,7 +264,7 @@ bool SightCheck::P_SightCheckLine (line_t *ld)
// that runs a script on the current map. Used to prevent monsters // that runs a script on the current map. Used to prevent monsters
// from trying to attack through a block everything line unless // from trying to attack through a block everything line unless
// there's a chance their attack will make it nonblocking. // there's a chance their attack will make it nonblocking.
if (!SeePastShootableLines) if (!(Flags & SF_SEEPASTSHOOTABLELINES))
{ {
if (!(ld->activation & SPAC_Impact)) if (!(ld->activation & SPAC_Impact))
{ {
@ -407,6 +408,7 @@ bool SightCheck::P_SightTraverseIntercepts ()
F3DFloor* rover = lastsector->e->XFloor.ffloors[i]; F3DFloor* rover = lastsector->e->XFloor.ffloors[i];
if((rover->flags & FF_SOLID) == myseethrough || !(rover->flags & FF_EXISTS)) continue; if((rover->flags & FF_SOLID) == myseethrough || !(rover->flags & FF_EXISTS)) continue;
if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing->x, seeingthing->y); fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing->x, seeingthing->y);
fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing->x, seeingthing->y); fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing->x, seeingthing->y);
@ -670,7 +672,7 @@ sightcounts[0]++;
// //
// [RH] Andy Baker's stealth monsters: // [RH] Andy Baker's stealth monsters:
// Cannot see an invisible object // Cannot see an invisible object
if ((flags & 1) == 0 && ((t2->renderflags & RF_INVISIBLE) || !t2->RenderStyle.IsVisible(t2->alpha))) if ((flags & SF_IGNOREVISIBILITY) == 0 && ((t2->renderflags & RF_INVISIBLE) || !t2->RenderStyle.IsVisible(t2->alpha)))
{ // small chance of an attack being made anyway { // small chance of an attack being made anyway
if ((bglobal.m_Thinking ? pr_botchecksight() : pr_checksight()) > 50) if ((bglobal.m_Thinking ? pr_botchecksight() : pr_checksight()) > 50)
{ {
@ -681,6 +683,8 @@ sightcounts[0]++;
// killough 4/19/98: make fake floors and ceilings block monster view // killough 4/19/98: make fake floors and ceilings block monster view
if (!(flags & SF_IGNOREWATERBOUNDARY))
{
if ((s1->GetHeightSec() && if ((s1->GetHeightSec() &&
((t1->z + t1->height <= s1->heightsec->floorplane.ZatPoint (t1->x, t1->y) && ((t1->z + t1->height <= s1->heightsec->floorplane.ZatPoint (t1->x, t1->y) &&
t2->z >= s1->heightsec->floorplane.ZatPoint (t2->x, t2->y)) || t2->z >= s1->heightsec->floorplane.ZatPoint (t2->x, t2->y)) ||
@ -696,6 +700,7 @@ sightcounts[0]++;
res = false; res = false;
goto done; goto done;
} }
}
// An unobstructed LOS is possible. // An unobstructed LOS is possible.
// Now look from eyes of t1 to any part of t2. // Now look from eyes of t1 to any part of t2.

View file

@ -1939,7 +1939,7 @@ void DPusher::Tick ()
// If speed <= 0, you're outside the effective radius. You also have // If speed <= 0, you're outside the effective radius. You also have
// to be able to see the push/pull source point. // to be able to see the push/pull source point.
if ((speed > 0) && (P_CheckSight (thing, m_Source, 1))) if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY)))
{ {
angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy);
if (m_Source->GetClass()->TypeName == NAME_PointPusher) if (m_Source->GetClass()->TypeName == NAME_PointPusher)

View file

@ -55,7 +55,6 @@
static FRandom pr_skullpop ("SkullPop"); static FRandom pr_skullpop ("SkullPop");
// [RH] # of ticks to complete a turn180 // [RH] # of ticks to complete a turn180
#define TURN180_TICKS ((TICRATE / 4) + 1) #define TURN180_TICKS ((TICRATE / 4) + 1)
@ -2671,3 +2670,47 @@ void player_t::Serialize (FArchive &arc)
} }
} }
static FPlayerColorSetMap *GetPlayerColors(FName classname)
{
PClassPlayerPawn *cls = dyn_cast<PClassPlayerPawn>(PClass::FindClass(classname));
if (cls != NULL)
{
return cls->ColorSets;
}
return NULL;
}
FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum)
{
FPlayerColorSetMap *map = GetPlayerColors(classname);
if (map == NULL)
{
return NULL;
}
return map->CheckKey(setnum);
}
static int STACK_ARGS intcmp(const void *a, const void *b)
{
return *(const int *)a - *(const int *)b;
}
void P_EnumPlayerColorSets(FName classname, TArray<int> *out)
{
out->Clear();
FPlayerColorSetMap *map = GetPlayerColors(classname);
if (map != NULL)
{
FPlayerColorSetMap::Iterator it(*map);
FPlayerColorSetMap::Pair *pair;
while (it.NextPair(pair))
{
out->Push(pair->Key);
}
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
}
}

View file

@ -795,25 +795,25 @@ static void UpdateSegBBox (seg_t *seg)
line = seg->linedef; line = seg->linedef;
if (seg->v1->x < seg->v2->x) if (line->v1->x < line->v2->x)
{ {
line->bbox[BOXLEFT] = seg->v1->x; line->bbox[BOXLEFT] = line->v1->x;
line->bbox[BOXRIGHT] = seg->v2->x; line->bbox[BOXRIGHT] = line->v2->x;
} }
else else
{ {
line->bbox[BOXLEFT] = seg->v2->x; line->bbox[BOXLEFT] = line->v2->x;
line->bbox[BOXRIGHT] = seg->v1->x; line->bbox[BOXRIGHT] = line->v1->x;
} }
if (seg->v1->y < seg->v2->y) if (line->v1->y < line->v2->y)
{ {
line->bbox[BOXBOTTOM] = seg->v1->y; line->bbox[BOXBOTTOM] = line->v1->y;
line->bbox[BOXTOP] = seg->v2->y; line->bbox[BOXTOP] = line->v2->y;
} }
else else
{ {
line->bbox[BOXBOTTOM] = seg->v2->y; line->bbox[BOXBOTTOM] = line->v2->y;
line->bbox[BOXTOP] = seg->v1->y; line->bbox[BOXTOP] = line->v1->y;
} }
// Update the line's slopetype // Update the line's slopetype

View file

@ -2181,7 +2181,7 @@ ESPSResult R_SetPatchStyle (FRenderStyle style, fixed_t alpha, int translation,
if (translation != 0) if (translation != 0)
{ {
FRemapTable *table = TranslationToTable(translation); FRemapTable *table = TranslationToTable(translation);
if (table != NULL) if (table != NULL && !table->Inactive)
{ {
dc_translation = table->Remap; dc_translation = table->Remap;
} }

View file

@ -1081,7 +1081,7 @@ void R_SetupFrame (AActor *actor)
iview->otic = nowtic; iview->otic = nowtic;
} }
R_UpdateAnimations (I_MSTime()); R_UpdateAnimations (I_FPSTime());
r_TicFrac = I_GetTimeFrac (&r_FrameTime); r_TicFrac = I_GetTimeFrac (&r_FrameTime);
if (cl_capfps || r_NoInterpolate) if (cl_capfps || r_NoInterpolate)
{ {

View file

@ -2346,7 +2346,7 @@ CUSTOM_CVAR( Int, r_maxparticles, 4000, CVAR_ARCHIVE )
void R_InitParticles () void R_InitParticles ()
{ {
char *i; const char *i;
if ((i = Args->CheckValue ("-numparticles"))) if ((i = Args->CheckValue ("-numparticles")))
NumParticles = atoi (i); NumParticles = atoi (i);

View file

@ -46,6 +46,7 @@
#include "sc_man.h" #include "sc_man.h"
#include "doomerrors.h" #include "doomerrors.h"
#include "i_system.h" #include "i_system.h"
#include "w_wad.h"
#include "gi.h" #include "gi.h"
#include "stats.h" #include "stats.h"
@ -78,7 +79,7 @@ const BYTE IcePalette[16][3] =
FRemapTable::FRemapTable(int count) FRemapTable::FRemapTable(int count)
{ {
assert(count <= 256); assert(count <= 256);
Inactive = false;
Alloc(count); Alloc(count);
// Note that the tables are left uninitialized. It is assumed that // Note that the tables are left uninitialized. It is assumed that
@ -163,6 +164,7 @@ FRemapTable &FRemapTable::operator=(const FRemapTable &o)
{ {
Alloc(o.NumEntries); Alloc(o.NumEntries);
} }
Inactive = o.Inactive;
memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette)); memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette));
return *this; return *this;
} }
@ -892,7 +894,8 @@ static void SetRemap(FRemapTable *table, int i, float r, float g, float b)
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerColorSet *colorset,
FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable)
{ {
int i; int i;
BYTE start = skin->range0start; BYTE start = skin->range0start;
@ -915,7 +918,7 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
{ {
for (i = 0; i < table->NumEntries; ++i) for (i = 0; i < table->NumEntries; ++i)
{ {
table->Remap[i] = i; table->Remap[i] = GPalette.Remap[i];
} }
memcpy(table->Palette, GPalette.BaseColors, sizeof(*table->Palette) * table->NumEntries); memcpy(table->Palette, GPalette.BaseColors, sizeof(*table->Palette) * table->NumEntries);
} }
@ -927,16 +930,63 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
// [GRB] Don't translate skins with color range 0-0 (APlayerPawn default) // [GRB] Don't translate skins with color range 0-0 (APlayerPawn default)
if (start == 0 && end == 0) if (start == 0 && end == 0)
{ {
table->Inactive = true;
table->UpdateNative(); table->UpdateNative();
return; return;
} }
table->Inactive = false;
range = (float)(end-start+1); range = (float)(end-start+1);
bases = s; bases = s;
basev = v; basev = v;
if (gameinfo.gametype & GAME_DoomStrifeChex) if (colorset != NULL && colorset->Lump >= 0 && Wads.LumpLength(colorset->Lump) < 256)
{ // Bad table length. Ignore it.
colorset = NULL;
}
if (colorset != NULL)
{
bool identity = true;
// Use the pre-defined range instead of a custom one.
if (colorset->Lump < 0)
{
int first = colorset->FirstColor;
if (start == end)
{
table->Remap[i] = (first + colorset->LastColor) / 2;
}
else
{
int palrange = colorset->LastColor - first;
for (i = start; i <= end; ++i)
{
int pi = first + palrange * (i - start) / (end - start);
table->Remap[i] = GPalette.Remap[pi];
if (pi != i) identity = false;
}
}
}
else
{
FMemLump translump = Wads.ReadLump(colorset->Lump);
const BYTE *trans = (const BYTE *)translump.GetMem();
for (i = start; i <= end; ++i)
{
table->Remap[i] = GPalette.Remap[trans[i]];
if (trans[i] != i) identity = false;
}
}
for (i = start; i <= end; ++i)
{
table->Palette[i] = GPalette.BaseColors[table->Remap[i]];
table->Palette[i].a = 255;
}
// If the colorset created an identity translation mark it as inactive
table->Inactive = identity;
}
else if (gameinfo.gametype & GAME_DoomStrifeChex)
{ {
// Build player sprite translation // Build player sprite translation
s -= 0.23f; s -= 0.23f;
@ -1014,9 +1064,19 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
SetRemap(table, i, r, g, b); SetRemap(table, i, r, g, b);
} }
} }
}
if (gameinfo.gametype == GAME_Hexen && alttable != NULL)
{
// Build Hexen's lifegem translation.
// Build lifegem translation // Is the player's translation range the same as the gem's and we are using a
if (alttable) // predefined translation? If so, then use the same one for the gem. Otherwise,
// build one as per usual.
if (colorset != NULL && start == 164 && end == 185)
{
*alttable = *table;
}
else
{ {
for (i = 164; i <= 185; ++i) for (i = 164; i <= 185; ++i)
{ {
@ -1027,8 +1087,8 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); HSVtoRGB (&r, &g, &b, h, s*bases, v*basev);
SetRemap(alttable, i, r, g, b); SetRemap(alttable, i, r, g, b);
} }
alttable->UpdateNative();
} }
alttable->UpdateNative();
} }
table->UpdateNative(); table->UpdateNative();
} }
@ -1042,10 +1102,11 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
void R_BuildPlayerTranslation (int player) void R_BuildPlayerTranslation (int player)
{ {
float h, s, v; float h, s, v;
FPlayerColorSet *colorset;
D_GetPlayerColor (player, &h, &s, &v); D_GetPlayerColor (player, &h, &s, &v, &colorset);
R_CreatePlayerTranslation (h, s, v, R_CreatePlayerTranslation (h, s, v, colorset,
&skins[players[player].userinfo.skin], &skins[players[player].userinfo.skin],
translationtables[TRANSLATION_Players][player], translationtables[TRANSLATION_Players][player],
translationtables[TRANSLATION_PlayersExtra][player]); translationtables[TRANSLATION_PlayersExtra][player]);
@ -1057,13 +1118,17 @@ void R_BuildPlayerTranslation (int player)
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayerSkin *skin, FRemapTable *table)
{ {
float h, s, v; float h, s, v;
if (colorset != NULL)
{
color = colorset->RepresentativeColor;
}
RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f,
&h, &s, &v); &h, &s, &v);
R_CreatePlayerTranslation (h, s, v, skin, table, NULL); R_CreatePlayerTranslation (h, s, v, colorset, skin, table, NULL);
} }

View file

@ -46,6 +46,7 @@ struct FRemapTable
PalEntry *Palette; // The ideal palette this maps to PalEntry *Palette; // The ideal palette this maps to
FNativePalette *Native; // The Palette stored in a HW texture FNativePalette *Native; // The Palette stored in a HW texture
int NumEntries; // # of elements in this table (usually 256) int NumEntries; // # of elements in this table (usually 256)
bool Inactive; // This table is inactive and should be treated as if it was passed as NULL
private: private:
void Free(); void Free();

View file

@ -56,13 +56,15 @@ struct RFFInfo
struct RFFLump struct RFFLump
{ {
BYTE IDontKnow[16]; DWORD DontKnow1[4];
DWORD FilePos; DWORD FilePos;
DWORD Size; DWORD Size;
BYTE IStillDontKnow[8]; DWORD DontKnow2;
DWORD Time;
BYTE Flags; BYTE Flags;
char Extension[3]; char Extension[3];
char Name[8+4]; // 4 bytes that I don't know what they are for char Name[8];
DWORD IndexNum; // Used by .sfx, possibly others
}; };
//========================================================================== //==========================================================================
@ -75,6 +77,10 @@ struct FRFFLump : public FUncompressedLump
{ {
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual int FillCache(); virtual int FillCache();
DWORD IndexNum;
int GetIndexNum() const { return IndexNum; }
}; };
//========================================================================== //==========================================================================
@ -149,33 +155,34 @@ bool FRFFFile::Open(bool quiet)
if (!quiet) Printf(", %d lumps\n", NumLumps); if (!quiet) Printf(", %d lumps\n", NumLumps);
for (DWORD i = 0; i < NumLumps; ++i) for (DWORD i = 0; i < NumLumps; ++i)
{ {
if (lumps[i].Extension[0] == 'S' && lumps[i].Extension[1] == 'F' &&
lumps[i].Extension[2] == 'X')
{
Lumps[i].Namespace = ns_bloodsfx;
}
else if (lumps[i].Extension[0] == 'R' && lumps[i].Extension[1] == 'A' &&
lumps[i].Extension[2] == 'W')
{
Lumps[i].Namespace = ns_bloodraw;
}
else
{
Lumps[i].Namespace = ns_global;
}
Lumps[i].Position = LittleLong(lumps[i].FilePos); Lumps[i].Position = LittleLong(lumps[i].FilePos);
Lumps[i].LumpSize = LittleLong(lumps[i].Size); Lumps[i].LumpSize = LittleLong(lumps[i].Size);
Lumps[i].Owner = this; Lumps[i].Owner = this;
if (lumps[i].Flags & 0x10) Lumps[i].Flags |= LUMPF_BLOODCRYPT; if (lumps[i].Flags & 0x10)
{
// Rearrange the name and extension in a part of the lump record Lumps[i].Flags |= LUMPF_BLOODCRYPT;
// that I don't have any use for in order to cnstruct the fullname. }
lumps[i].Name[8] = '\0'; Lumps[i].IndexNum = LittleLong(lumps[i].IndexNum);
strcpy ((char *)lumps[i].IDontKnow, lumps[i].Name); // Rearrange the name and extension to construct the fullname.
strcat ((char *)lumps[i].IDontKnow, "."); char name[13];
strcat ((char *)lumps[i].IDontKnow, lumps[i].Extension); strncpy(name, lumps[i].Name, 8);
Lumps[i].LumpNameSetup((char *)lumps[i].IDontKnow); name[8] = 0;
size_t len = strlen(name);
assert(len + 4 <= 12);
name[len+0] = '.';
name[len+1] = lumps[i].Extension[0];
name[len+2] = lumps[i].Extension[1];
name[len+3] = lumps[i].Extension[2];
name[len+4] = 0;
Lumps[i].LumpNameSetup(name);
if (name[len+1] == 'S' && name[len+2] == 'F' && name[len+3] == 'X')
{
Lumps[i].Namespace = ns_bloodsfx;
}
else if (name[len+1] == 'R' && name[len+2] == 'A' && name[len+3] == 'W')
{
Lumps[i].Namespace = ns_bloodraw;
}
} }
delete[] lumps; delete[] lumps;
return true; return true;
@ -183,7 +190,10 @@ bool FRFFFile::Open(bool quiet)
FRFFFile::~FRFFFile() FRFFFile::~FRFFFile()
{ {
if (Lumps != NULL) delete [] Lumps; if (Lumps != NULL)
{
delete[] Lumps;
}
} }
@ -197,8 +207,14 @@ FileReader *FRFFLump::GetReader()
{ {
// Don't return the reader if this lump is encrypted // Don't return the reader if this lump is encrypted
// In that case always force caching of the lump // In that case always force caching of the lump
if (!(Flags & LUMPF_BLOODCRYPT)) return FUncompressedLump::GetReader(); if (!(Flags & LUMPF_BLOODCRYPT))
else return NULL; {
return FUncompressedLump::GetReader();
}
else
{
return NULL;
}
} }
//========================================================================== //==========================================================================

View file

@ -41,6 +41,7 @@ struct FResourceLump
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual FileReader *NewReader(); virtual FileReader *NewReader();
virtual int GetFileOffset() { return -1; } virtual int GetFileOffset() { return -1; }
virtual int GetIndexNum() const { return 0; }
void LumpNameSetup(const char *iname); void LumpNameSetup(const char *iname);
void CheckEmbedded(); void CheckEmbedded();

View file

@ -114,7 +114,7 @@ protected:
void Free (); void Free ();
}; };
static struct AmbientSound struct FAmbientSound
{ {
unsigned type; // type of ambient sound unsigned type; // type of ambient sound
int periodmin; // # of tics between repeats int periodmin; // # of tics between repeats
@ -122,7 +122,8 @@ static struct AmbientSound
float volume; // relative volume of sound float volume; // relative volume of sound
float attenuation; float attenuation;
FString sound; // Logical name of sound to play FString sound; // Logical name of sound to play
} *Ambients[256]; };
TMap<int, FAmbientSound> Ambients;
enum SICommands enum SICommands
{ {
@ -509,6 +510,7 @@ int S_AddSoundLump (const char *logicalname, int lump)
newsfx.Rolloff.RolloffType = ROLLOFF_Doom; newsfx.Rolloff.RolloffType = ROLLOFF_Doom;
newsfx.Rolloff.MinDistance = 0; newsfx.Rolloff.MinDistance = 0;
newsfx.Rolloff.MaxDistance = 0; newsfx.Rolloff.MaxDistance = 0;
newsfx.LoopStart = -1;
return (int)S_sfx.Push (newsfx); return (int)S_sfx.Push (newsfx);
} }
@ -836,15 +838,7 @@ static void S_ClearSoundData()
S_UnloadSound(&S_sfx[i]); S_UnloadSound(&S_sfx[i]);
} }
S_sfx.Clear(); S_sfx.Clear();
Ambients.Clear();
for(i = 0; i < countof(Ambients); i++)
{
if (Ambients[i] != NULL)
{
delete Ambients[i];
Ambients[i] = NULL;
}
}
while (MusicVolumes != NULL) while (MusicVolumes != NULL)
{ {
FMusicVolume *me = MusicVolumes; FMusicVolume *me = MusicVolumes;
@ -967,23 +961,10 @@ static void S_AddSNDINFO (int lump)
// $ambient <num> <logical name> [point [atten] | surround | [world]] // $ambient <num> <logical name> [point [atten] | surround | [world]]
// <continuous | random <minsecs> <maxsecs> | periodic <secs>> // <continuous | random <minsecs> <maxsecs> | periodic <secs>>
// <volume> // <volume>
AmbientSound *ambient, dummy; FAmbientSound *ambient;
sc.MustGetNumber (); sc.MustGetNumber ();
if (sc.Number < 0 || sc.Number > 255) ambient = &Ambients[sc.Number];
{
Printf ("Bad ambient index (%d)\n", sc.Number);
ambient = &dummy;
}
else if (Ambients[sc.Number] == NULL)
{
ambient = new AmbientSound;
Ambients[sc.Number] = ambient;
}
else
{
ambient = Ambients[sc.Number];
}
ambient->type = 0; ambient->type = 0;
ambient->periodmin = 0; ambient->periodmin = 0;
ambient->periodmax = 0; ambient->periodmax = 0;
@ -1366,7 +1347,6 @@ static void S_AddSNDINFO (int lump)
static void S_AddBloodSFX (int lumpnum) static void S_AddBloodSFX (int lumpnum)
{ {
char name[13];
FMemLump sfxlump = Wads.ReadLump(lumpnum); FMemLump sfxlump = Wads.ReadLump(lumpnum);
const FBloodSFX *sfx = (FBloodSFX *)sfxlump.GetMem(); const FBloodSFX *sfx = (FBloodSFX *)sfxlump.GetMem();
int rawlump = Wads.CheckNumForName(sfx->RawName, ns_bloodraw); int rawlump = Wads.CheckNumForName(sfx->RawName, ns_bloodraw);
@ -1374,9 +1354,7 @@ static void S_AddBloodSFX (int lumpnum)
if (rawlump != -1) if (rawlump != -1)
{ {
Wads.GetLumpName (name, lumpnum); const char *name = Wads.GetLumpFullName(lumpnum);
name[8] = 0;
strcat (name, ".SFX");
sfxnum = S_AddSound(name, rawlump); sfxnum = S_AddSound(name, rawlump);
if (sfx->Format == 5) if (sfx->Format == 5)
{ {
@ -1387,6 +1365,17 @@ static void S_AddBloodSFX (int lumpnum)
S_sfx[sfxnum].bForce11025 = true; S_sfx[sfxnum].bForce11025 = true;
} }
S_sfx[sfxnum].bLoadRAW = true; S_sfx[sfxnum].bLoadRAW = true;
S_sfx[sfxnum].LoopStart = LittleLong(sfx->LoopStart);
// Make an ambient sound out of it, whether it has a loop point
// defined or not. (Because none of the standard Blood ambient
// sounds are explicitly defined as looping.)
FAmbientSound *ambient = &Ambients[Wads.GetLumpIndexNum(lumpnum)];
ambient->type = CONTINUOUS;
ambient->periodmin = 0;
ambient->periodmax = 0;
ambient->volume = 1;
ambient->attenuation = 1;
ambient->sound = name;
} }
} }
@ -1906,12 +1895,18 @@ public:
protected: protected:
bool bActive; bool bActive;
private: private:
void SetTicker (struct AmbientSound *ambient); void SetTicker (struct FAmbientSound *ambient);
int NextCheck; int NextCheck;
}; };
IMPLEMENT_CLASS (AAmbientSound) IMPLEMENT_CLASS (AAmbientSound)
//==========================================================================
//
// AmbientSound :: Serialize
//
//==========================================================================
void AAmbientSound::Serialize (FArchive &arc) void AAmbientSound::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
@ -1948,6 +1943,11 @@ void AAmbientSound::Serialize (FArchive &arc)
} }
} }
//==========================================================================
//
// AmbientSound :: Tick
//
//==========================================================================
void AAmbientSound::Tick () void AAmbientSound::Tick ()
{ {
@ -1956,17 +1956,47 @@ void AAmbientSound::Tick ()
if (!bActive || gametic < NextCheck) if (!bActive || gametic < NextCheck)
return; return;
AmbientSound *ambient = Ambients[args[0]]; FAmbientSound *ambient;
int loop = 0; int loop = 0;
ambient = Ambients.CheckKey(args[0]);
if (ambient == NULL)
{
return;
}
if ((ambient->type & CONTINUOUS) == CONTINUOUS) if ((ambient->type & CONTINUOUS) == CONTINUOUS)
{ {
loop = CHAN_LOOP; loop = CHAN_LOOP;
} }
if (ambient->sound[0]) if (ambient->sound.IsNotEmpty())
{ {
S_Sound(this, CHAN_BODY | loop, ambient->sound, ambient->volume, ambient->attenuation); // The second argument scales the ambient sound's volume.
// 0 and 100 are normal volume. The maximum volume level
// possible is always 1.
float volscale = args[1] == 0 ? 1 : args[1] / 100.f;
float usevol = clamp(ambient->volume * volscale, 0.f, 1.f);
// The third argument is the minimum distance for audible fading, and
// the fourth argument is the maximum distance for audibility. Setting
// either of these to 0 or setting min distance > max distance will
// use the standard rolloff.
if ((args[2] | args[3]) == 0 || args[2] > args[3])
{
S_Sound(this, CHAN_BODY | loop, ambient->sound, usevol, ambient->attenuation);
}
else
{
float min = float(args[2]), max = float(args[3]);
// The fifth argument acts as a scalar for the preceding two, if it's non-zero.
if (args[4] > 0)
{
min *= args[4];
max *= args[4];
}
S_SoundMinMaxDist(this, CHAN_BODY | loop, ambient->sound, usevol, min, max);
}
if (!loop) if (!loop)
{ {
SetTicker (ambient); SetTicker (ambient);
@ -1982,8 +2012,13 @@ void AAmbientSound::Tick ()
} }
} }
//==========================================================================
//
// AmbientSound :: SetTicker
//
//==========================================================================
void AAmbientSound::SetTicker (struct AmbientSound *ambient) void AAmbientSound::SetTicker (struct FAmbientSound *ambient)
{ {
if ((ambient->type & CONTINUOUS) == CONTINUOUS) if ((ambient->type & CONTINUOUS) == CONTINUOUS)
{ {
@ -2001,17 +2036,31 @@ void AAmbientSound::SetTicker (struct AmbientSound *ambient)
} }
} }
//==========================================================================
//
// AmbientSound :: BeginPlay
//
//==========================================================================
void AAmbientSound::BeginPlay () void AAmbientSound::BeginPlay ()
{ {
Super::BeginPlay (); Super::BeginPlay ();
Activate (NULL); Activate (NULL);
} }
//==========================================================================
//
// AmbientSound :: Activate
//
// Starts playing a sound (or does nothing of the sound is already playing).
//
//==========================================================================
void AAmbientSound::Activate (AActor *activator) void AAmbientSound::Activate (AActor *activator)
{ {
Super::Activate (activator); Super::Activate (activator);
AmbientSound *amb = Ambients[args[0]]; FAmbientSound *amb = Ambients.CheckKey(args[0]);
if (amb == NULL) if (amb == NULL)
{ {
@ -2040,13 +2089,23 @@ void AAmbientSound::Activate (AActor *activator)
} }
} }
//==========================================================================
//
// AmbientSound :: Deactivate
//
// Stops playing CONTINUOUS sounds immediately. Also prevents further
// occurrences of repeated sounds.
//
//==========================================================================
void AAmbientSound::Deactivate (AActor *activator) void AAmbientSound::Deactivate (AActor *activator)
{ {
Super::Deactivate (activator); Super::Deactivate (activator);
if (bActive) if (bActive)
{ {
bActive = false; bActive = false;
if ((Ambients[args[0]]->type & CONTINUOUS) == CONTINUOUS) FAmbientSound *ambient = Ambients.CheckKey(args[0]);
if (ambient != NULL && (ambient->type & CONTINUOUS) == CONTINUOUS)
{ {
S_StopSound (this, CHAN_BODY); S_StopSound (this, CHAN_BODY);
} }

View file

@ -198,7 +198,7 @@ int FPlayList::Advance ()
int FPlayList::Backup () int FPlayList::Backup ()
{ {
if (--Position < 0) if (Position-- == 0)
{ {
Position = Songs.Size() - 1; Position = Songs.Size() - 1;
} }

View file

@ -108,7 +108,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, co
static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fixed_t *y, fixed_t *z); static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fixed_t *y, fixed_t *z);
static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z); static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z);
static FSoundChan *S_StartSound(AActor *mover, const sector_t *sec, const FPolyObj *poly, static FSoundChan *S_StartSound(AActor *mover, const sector_t *sec, const FPolyObj *poly,
const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation); const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, FRolloffInfo *rolloff);
static void S_SetListener(SoundListener &listener, AActor *listenactor); static void S_SetListener(SoundListener &listener, AActor *listenactor);
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -165,6 +165,7 @@ void S_NoiseDebug (void)
screen->DrawText (SmallFont, CR_GOLD, 340, y, "pri", TAG_DONE); screen->DrawText (SmallFont, CR_GOLD, 340, y, "pri", TAG_DONE);
screen->DrawText (SmallFont, CR_GOLD, 380, y, "flags", TAG_DONE); screen->DrawText (SmallFont, CR_GOLD, 380, y, "flags", TAG_DONE);
screen->DrawText (SmallFont, CR_GOLD, 460, y, "aud", TAG_DONE); screen->DrawText (SmallFont, CR_GOLD, 460, y, "aud", TAG_DONE);
screen->DrawText (SmallFont, CR_GOLD, 520, y, "pos", TAG_DONE);
y += 8; y += 8;
if (Channels == NULL) if (Channels == NULL)
@ -253,6 +254,11 @@ void S_NoiseDebug (void)
mysnprintf(temp, countof(temp), "%.4f", GSnd->GetAudibility(chan)); mysnprintf(temp, countof(temp), "%.4f", GSnd->GetAudibility(chan));
screen->DrawText(SmallFont, color, 460, y, temp, TAG_DONE); screen->DrawText(SmallFont, color, 460, y, temp, TAG_DONE);
// Position
mysnprintf(temp, countof(temp), "%u", GSnd->GetPosition(chan));
screen->DrawText(SmallFont, color, 520, y, temp, TAG_DONE);
y += 8; y += 8;
if (chan->PrevChan == &Channels) if (chan->PrevChan == &Channels)
{ {
@ -317,7 +323,6 @@ void S_InitData ()
LastLocalSndInfo = LastLocalSndSeq = ""; LastLocalSndInfo = LastLocalSndSeq = "";
S_ParseSndInfo (); S_ParseSndInfo ();
S_ParseSndSeq (-1); S_ParseSndSeq (-1);
S_ParseReverbDef ();
} }
//========================================================================== //==========================================================================
@ -808,7 +813,8 @@ static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fi
//========================================================================== //==========================================================================
static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyObj *poly, static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyObj *poly,
const FVector3 *pt, int channel, FSoundID sound_id, double volume, double attenuation) const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation,
FRolloffInfo *forcedrolloff=NULL)
{ {
sfxinfo_t *sfx; sfxinfo_t *sfx;
int chanflags; int chanflags;
@ -866,7 +872,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO
sfx = &S_sfx[sound_id]; sfx = &S_sfx[sound_id];
// Scale volume according to SNDINFO data. // Scale volume according to SNDINFO data.
volume = MIN(volume * sfx->Volume, 1.0); volume = MIN(volume * sfx->Volume, 1.f);
if (volume <= 0) if (volume <= 0)
return NULL; return NULL;
@ -894,7 +900,10 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO
near_limit = S_sfx[sound_id].NearLimit; near_limit = S_sfx[sound_id].NearLimit;
limit_range = S_sfx[sound_id].LimitRange; limit_range = S_sfx[sound_id].LimitRange;
} }
if (rolloff->MinDistance == 0) rolloff = &S_sfx[sound_id].Rolloff; if (rolloff->MinDistance == 0)
{
rolloff = &S_sfx[sound_id].Rolloff;
}
} }
else else
{ {
@ -904,13 +913,25 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO
near_limit = S_sfx[sound_id].NearLimit; near_limit = S_sfx[sound_id].NearLimit;
limit_range = S_sfx[sound_id].LimitRange; limit_range = S_sfx[sound_id].LimitRange;
} }
if (rolloff->MinDistance == 0) rolloff = &S_sfx[sound_id].Rolloff; if (rolloff->MinDistance == 0)
{
rolloff = &S_sfx[sound_id].Rolloff;
}
} }
sfx = &S_sfx[sound_id]; sfx = &S_sfx[sound_id];
} }
// If no valid rolloff was set use the global default // The passed rolloff overrides any sound-specific rolloff.
if (rolloff->MinDistance == 0) rolloff = &S_Rolloff; if (forcedrolloff != NULL && forcedrolloff->MinDistance != 0)
{
rolloff = forcedrolloff;
}
// If no valid rolloff was set, use the global default.
if (rolloff->MinDistance == 0)
{
rolloff = &S_Rolloff;
}
// If this is a singular sound, don't play it if it's already playing. // If this is a singular sound, don't play it if it's already playing.
if (sfx->bSingular && S_CheckSingular(sound_id)) if (sfx->bSingular && S_CheckSingular(sound_id))
@ -1162,7 +1183,7 @@ void S_RestartSound(FSoundChan *chan)
// //
//========================================================================== //==========================================================================
void S_Sound (int channel, FSoundID sound_id, double volume, double attenuation) void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation)
{ {
S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation);
} }
@ -1173,20 +1194,41 @@ void S_Sound (int channel, FSoundID sound_id, double volume, double attenuation)
// //
//========================================================================== //==========================================================================
void S_Sound (AActor *ent, int channel, FSoundID sound_id, double volume, double attenuation) void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation)
{ {
if (ent == NULL || ent->Sector->Flags & SECF_SILENT) if (ent == NULL || ent->Sector->Flags & SECF_SILENT)
return; return;
S_StartSound (ent, NULL, NULL, NULL, channel, sound_id, volume, attenuation); S_StartSound (ent, NULL, NULL, NULL, channel, sound_id, volume, attenuation);
} }
//==========================================================================
//
// S_SoundMinMaxDist - An actor is source
//
// Attenuation is specified as min and max distances, rather than a scalar.
//
//==========================================================================
void S_SoundMinMaxDist(AActor *ent, int channel, FSoundID sound_id, float volume, float mindist, float maxdist)
{
if (ent == NULL || ent->Sector->Flags & SECF_SILENT)
return;
FRolloffInfo rolloff;
rolloff.RolloffType = ROLLOFF_Linear;
rolloff.MinDistance = mindist;
rolloff.MaxDistance = maxdist;
S_StartSound(ent, NULL, NULL, NULL, channel, sound_id, volume, 1, &rolloff);
}
//========================================================================== //==========================================================================
// //
// S_Sound - A polyobject is source // S_Sound - A polyobject is source
// //
//========================================================================== //==========================================================================
void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, double volume, double attenuation) void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, float volume, float attenuation)
{ {
S_StartSound (NULL, NULL, poly, NULL, channel, sound_id, volume, attenuation); S_StartSound (NULL, NULL, poly, NULL, channel, sound_id, volume, attenuation);
} }
@ -1197,7 +1239,7 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, double volum
// //
//========================================================================== //==========================================================================
void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, double volume, double attenuation) void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, float volume, float attenuation)
{ {
FVector3 pt(FIXED2FLOAT(x), FIXED2FLOAT(z), FIXED2FLOAT(y)); FVector3 pt(FIXED2FLOAT(x), FIXED2FLOAT(z), FIXED2FLOAT(y));
S_StartSound (NULL, NULL, NULL, &pt, channel, sound_id, volume, attenuation); S_StartSound (NULL, NULL, NULL, &pt, channel, sound_id, volume, attenuation);
@ -1209,7 +1251,7 @@ void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, d
// //
//========================================================================== //==========================================================================
void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation) void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation)
{ {
S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation);
} }
@ -1285,7 +1327,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx)
} }
sfxstart = sfxdata + 8; sfxstart = sfxdata + 8;
} }
sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8); sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8, sfx->LoopStart);
} }
else else
{ {
@ -1879,8 +1921,8 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor)
*/ */
listener.velocity.Zero(); listener.velocity.Zero();
listener.position.X = FIXED2FLOAT(listenactor->x); listener.position.X = FIXED2FLOAT(listenactor->x);
listener.position.Y = FIXED2FLOAT(listenactor->y); listener.position.Y = FIXED2FLOAT(listenactor->z);
listener.position.Z = FIXED2FLOAT(listenactor->z); listener.position.Z = FIXED2FLOAT(listenactor->y);
listener.underwater = listenactor->waterlevel == 3; listener.underwater = listenactor->waterlevel == 3;
assert(zones != NULL); assert(zones != NULL);
listener.Environment = zones[listenactor->Sector->ZoneNumber].Environment; listener.Environment = zones[listenactor->Sector->ZoneNumber].Environment;

View file

@ -59,6 +59,8 @@ struct sfxinfo_t
WORD bSingular:1; WORD bSingular:1;
WORD bTentative:1; WORD bTentative:1;
int LoopStart; // -1 means no specific loop defined
unsigned int link; unsigned int link;
enum { NO_LINK = 0xffffffff }; enum { NO_LINK = 0xffffffff };
@ -216,11 +218,12 @@ void S_PrecacheLevel ();
void S_CacheSound (sfxinfo_t *sfx); void S_CacheSound (sfxinfo_t *sfx);
// Start sound for thing at <ent> // Start sound for thing at <ent>
void S_Sound (int channel, FSoundID sfxid, double volume, double attenuation); void S_Sound (int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (AActor *ent, int channel, FSoundID sfxid, double volume, double attenuation); void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, double volume, double attenuation); void S_SoundMinMaxDist (AActor *ent, int channel, FSoundID sfxid, float volume, float mindist, float maxdist);
void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation); void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, double volume, double attenuation); void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, float volume, float attenuation);
// sound channels // sound channels
// channel 0 never willingly overrides // channel 0 never willingly overrides

View file

@ -1737,7 +1737,7 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *
if (FMOD_OK == chan->getCurrentSound(&sound)) if (FMOD_OK == chan->getCurrentSound(&sound))
{ {
unsigned int len; unsigned int len;
if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS)) if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len)
{ {
difftime %= len; difftime %= len;
} }
@ -1994,11 +1994,11 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener)
// Set velocity to 0 to prevent crazy doppler shifts just from running. // Set velocity to 0 to prevent crazy doppler shifts just from running.
vel.x = listener->velocity.X; vel.x = listener->velocity.X;
vel.z = listener->velocity.Y; vel.y = listener->velocity.Y;
vel.y = listener->velocity.Z; vel.z = listener->velocity.Z;
pos.x = listener->position.X; pos.x = listener->position.X;
pos.z = listener->position.Y; pos.y = listener->position.Y;
pos.y = listener->position.Z; pos.z = listener->position.Z;
float angle = listener->angle; float angle = listener->angle;
forward.x = cos(angle); forward.x = cos(angle);
@ -2190,12 +2190,16 @@ void FMODSoundRenderer::UpdateSounds()
// //
//========================================================================== //==========================================================================
SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart)
{ {
FMOD_CREATESOUNDEXINFO exinfo; FMOD_CREATESOUNDEXINFO exinfo;
SoundHandle retval = { NULL }; SoundHandle retval = { NULL };
int numsamples;
if (length == 0) return retval; if (length <= 0)
{
return retval;
}
InitCreateSoundExInfo(&exinfo); InitCreateSoundExInfo(&exinfo);
exinfo.length = length; exinfo.length = length;
@ -2212,14 +2216,17 @@ SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequ
case -8: case -8:
exinfo.format = FMOD_SOUND_FORMAT_PCM8; exinfo.format = FMOD_SOUND_FORMAT_PCM8;
numsamples = length;
break; break;
case 16: case 16:
exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.format = FMOD_SOUND_FORMAT_PCM16;
numsamples = length >> 1;
break; break;
case 32: case 32:
exinfo.format = FMOD_SOUND_FORMAT_PCM32; exinfo.format = FMOD_SOUND_FORMAT_PCM32;
numsamples = length >> 2;
break; break;
default: default:
@ -2236,6 +2243,12 @@ SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequ
DPrintf("Failed to allocate sample: Error %d\n", result); DPrintf("Failed to allocate sample: Error %d\n", result);
return retval; return retval;
} }
if (loopstart >= 0)
{
sample->setLoopPoints(loopstart, FMOD_TIMEUNIT_PCM, numsamples - 1, FMOD_TIMEUNIT_PCM);
}
retval.data = sample; retval.data = sample;
return retval; return retval;
} }

View file

@ -14,7 +14,7 @@ public:
void SetSfxVolume (float volume); void SetSfxVolume (float volume);
void SetMusicVolume (float volume); void SetMusicVolume (float volume);
SoundHandle LoadSound(BYTE *sfxdata, int length); SoundHandle LoadSound(BYTE *sfxdata, int length);
SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits); SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart);
void UnloadSound (SoundHandle sfx); void UnloadSound (SoundHandle sfx);
unsigned int GetMSLength(SoundHandle sfx); unsigned int GetMSLength(SoundHandle sfx);
unsigned int GetSampleLength(SoundHandle sfx); unsigned int GetSampleLength(SoundHandle sfx);

View file

@ -112,7 +112,10 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
else else
{ {
// Set general music volume. // Set general music volume.
if (GSnd != NULL)
{
GSnd->SetMusicVolume(clamp<float>(self * relative_volume, 0, 1)); GSnd->SetMusicVolume(clamp<float>(self * relative_volume, 0, 1));
}
// For music not implemented through the digital sound system, // For music not implemented through the digital sound system,
// let them know about the change. // let them know about the change.
if (currSong != NULL) if (currSong != NULL)

View file

@ -123,7 +123,7 @@ public:
SoundHandle retval = { NULL }; SoundHandle retval = { NULL };
return retval; return retval;
} }
SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart)
{ {
SoundHandle retval = { NULL }; SoundHandle retval = { NULL };
return retval; return retval;

View file

@ -92,7 +92,7 @@ public:
virtual void SetSfxVolume (float volume) = 0; virtual void SetSfxVolume (float volume) = 0;
virtual void SetMusicVolume (float volume) = 0; virtual void SetMusicVolume (float volume) = 0;
virtual SoundHandle LoadSound(BYTE *sfxdata, int length) = 0; virtual SoundHandle LoadSound(BYTE *sfxdata, int length) = 0;
virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) = 0; virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) = 0;
virtual void UnloadSound (SoundHandle sfx) = 0; // unloads a sound from memory virtual void UnloadSound (SoundHandle sfx) = 0; // unloads a sound from memory
virtual unsigned int GetMSLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency virtual unsigned int GetMSLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency
virtual unsigned int GetSampleLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency virtual unsigned int GetSampleLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency

View file

@ -171,7 +171,7 @@ static BYTE CheatDigitalCafe[] = { 'd','i','g','i','t','a','l','c','a','f','e',2
static BYTE CheatJoshuaStorms[] = { 'j','o','s','h','u','a','s','t','o','r','m','s',255 }; static BYTE CheatJoshuaStorms[] = { 'j','o','s','h','u','a','s','t','o','r','m','s',255 };
static BYTE CheatLeeSnyder[] = { 'l','e','e','s','n','y','d','e','r',0,0,255 }; static BYTE CheatLeeSnyder[] = { 'l','e','e','s','n','y','d','e','r',0,0,255 };
static BYTE CheatKimHyers[] = { 'k','i','m','h','y','e','r','s',255 }; static BYTE CheatKimHyers[] = { 'k','i','m','h','y','e','r','s',255 };
static BYTE CheatShrrill[] = { 's','h','r','r','i','l','l',255 }; static BYTE CheatShrrill[] = { 's','h','e','r','r','i','l','l',255 };
static BYTE CheatTNTem[] = { 't','n','t','e','m',255 }; static BYTE CheatTNTem[] = { 't','n','t','e','m',255 };
@ -274,8 +274,8 @@ static cheatseq_t ChexCheats[] =
{ CheatKimHyers, 0, 1, 0, {0,0}, Cht_MyPos }, { CheatKimHyers, 0, 1, 0, {0,0}, Cht_MyPos },
{ CheatShrrill, 0, 0, 0, {0,0}, Cht_AutoMap }, { CheatShrrill, 0, 0, 0, {0,0}, Cht_AutoMap },
{ CheatDavidBrus, 0, 0, 0, {CHT_IDDQD,0}, Cht_Generic }, { CheatDavidBrus, 0, 0, 0, {CHT_IDDQD,0}, Cht_Generic },
{ CheatMikeKoenigs, 0, 0, 0, {CHT_IDKFA,0}, Cht_Generic }, { CheatScottHolman, 0, 0, 0, {CHT_IDKFA,0}, Cht_Generic },
{ CheatScottHolman, 0, 0, 0, {CHT_IDFA,0}, Cht_Generic }, { CheatMikeKoenigs, 0, 0, 0, {CHT_IDFA,0}, Cht_Generic },
{ CheatCharlesJacobi, 0, 0, 0, {CHT_NOCLIP,0}, Cht_Generic }, { CheatCharlesJacobi, 0, 0, 0, {CHT_NOCLIP,0}, Cht_Generic },
{ CheatAndrewBenson, 0, 0, 0, {CHT_BEHOLDV,0}, Cht_Generic }, { CheatAndrewBenson, 0, 0, 0, {CHT_BEHOLDV,0}, Cht_Generic },
{ CheatDeanHyers, 0, 0, 0, {CHT_BEHOLDS,0}, Cht_Generic }, { CheatDeanHyers, 0, 0, 0, {CHT_BEHOLDS,0}, Cht_Generic },

View file

@ -745,7 +745,11 @@ protected:
Node *mp = MainPosition(key), **mpp; Node *mp = MainPosition(key), **mpp;
HashTraits Traits; HashTraits Traits;
if (!mp->IsNil() && !Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */ if (mp->IsNil())
{
/* the key is definitely not present, because there is nothing at its main position */
}
else if (!Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */
{ {
if (mp->Next != NULL) /* move next node to its main position */ if (mp->Next != NULL) /* move next node to its main position */
{ {

View file

@ -158,7 +158,7 @@ const BYTE *FBuildTexture::GetColumn (unsigned int column, const Span **spans_ou
// //
//=========================================================================== //===========================================================================
static void AddTiles (void *tiles) void AddTiles (void *tiles)
{ {
// int numtiles = LittleLong(((DWORD *)tiles)[1]); // This value is not reliable // int numtiles = LittleLong(((DWORD *)tiles)[1]); // This value is not reliable
int tilestart = LittleLong(((DWORD *)tiles)[2]); int tilestart = LittleLong(((DWORD *)tiles)[2]);
@ -224,29 +224,29 @@ static void AddTiles (void *tiles)
if (rotType == 1) if (rotType == 1)
{ {
spriteframe_t rot; spriteframe_t rot;
rot.Texture[0] = texnum; rot.Texture[0] =
rot.Texture[1] = texnum; rot.Texture[1] = texnum;
for (int j = 1; j < 4; ++j) for (int j = 1; j < 4; ++j)
{ {
rot.Texture[j*2] = texnum + j; rot.Texture[j*2] =
rot.Texture[j*2+1] = texnum + j; rot.Texture[j*2+1] =
rot.Texture[16-j*2] = texnum + j; rot.Texture[16-j*2] =
rot.Texture[17-j*2] = texnum + j; rot.Texture[17-j*2] = texnum.GetIndex() + j;
} }
rot.Texture[8] = texnum + 4; rot.Texture[8] =
rot.Texture[9] = texnum + 4; rot.Texture[9] = texnum.GetIndex() + 4;
rot.Flip = 0x00FC; rot.Flip = 0x00FC;
tex->Rotations = SpriteFrames.Push (rot); tex->Rotations = SpriteFrames.Push (rot);
} }
else if (rotType == 2) else if (rotType == 2)
{ {
spriteframe_t rot; spriteframe_t rot;
rot.Texture[0] = texnum; rot.Texture[0] =
rot.Texture[1] = texnum; rot.Texture[1] = texnum;
for (int j = 1; j < 8; ++j) for (int j = 1; j < 8; ++j)
{ {
rot.Texture[16-j*2] = texnum + j; rot.Texture[16-j*2] =
rot.Texture[17-j*2] = texnum + j; rot.Texture[17-j*2] = texnum.GetIndex() + j;
} }
rot.Flip = 0; rot.Flip = 0;
tex->Rotations = SpriteFrames.Push (rot); tex->Rotations = SpriteFrames.Push (rot);

View file

@ -634,7 +634,7 @@ void FDDSTexture::DecompressDXT1 (FWadLump &lump, BYTE *tcbuf)
bMasked = true; bMasked = true;
} }
// Pick colors from the palette for each of the four colors. // Pick colors from the palette for each of the four colors.
if (!tcbuf) for (i = 3; i >= 0; --i) /*if (!tcbuf)*/ for (i = 3; i >= 0; --i)
{ {
palcol[i] = color[i].a ? RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3] : 0; palcol[i] = color[i].a ? RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3] : 0;
} }
@ -652,18 +652,18 @@ void FDDSTexture::DecompressDXT1 (FWadLump &lump, BYTE *tcbuf)
{ {
break; break;
} }
int ci = (yslice >> (x + x)) & 3;
if (!tcbuf) if (!tcbuf)
{ {
Pixels[oy + y + (ox + x) * Height] = palcol[(yslice >> (x + x)) & 3]; Pixels[oy + y + (ox + x) * Height] = palcol[ci];
} }
else else
{ {
BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4];
int c = (yslice >> (x + x)) & 3; tcp[0] = color[ci].r;
tcp[0] = color[c].r; tcp[1] = color[ci].g;
tcp[1] = color[c].g; tcp[2] = color[ci].b;
tcp[2] = color[c].b; tcp[3] = color[ci].a;
tcp[3] = color[c].a;
} }
} }
} }
@ -740,7 +740,7 @@ void FDDSTexture::DecompressDXT3 (FWadLump &lump, bool premultiplied, BYTE *tcbu
} }
else else
{ {
BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4];
int c = (yslice >> (x + x)) & 3; int c = (yslice >> (x + x)) & 3;
tcp[0] = color[c].r; tcp[0] = color[c].r;
tcp[1] = color[c].g; tcp[1] = color[c].g;
@ -769,7 +769,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu
BYTE *block; BYTE *block;
PalEntry color[4]; PalEntry color[4];
BYTE palcol[4]; BYTE palcol[4];
DWORD yalphaslice; DWORD yalphaslice = 0;
int ox, oy, x, y, i; int ox, oy, x, y, i;
for (oy = 0; oy < Height; oy += 4) for (oy = 0; oy < Height; oy += 4)
@ -831,7 +831,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu
break; break;
} }
// Alpha values are stored in 3 bytes for 2 rows // Alpha values are stored in 3 bytes for 2 rows
if ((y & 0) == 0) if ((y & 1) == 0)
{ {
yalphaslice = block[y*3] | (block[y*3+1] << 8) | (block[y*3+2] << 16); yalphaslice = block[y*3] | (block[y*3+1] << 8) | (block[y*3+2] << 16);
} }
@ -853,7 +853,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu
} }
else else
{ {
BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4];
int c = (yslice >> (x + x)) & 3; int c = (yslice >> (x + x)) & 3;
tcp[0] = color[c].r; tcp[0] = color[c].r;
tcp[1] = color[c].g; tcp[1] = color[c].g;

View file

@ -140,7 +140,9 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF
else else
{ {
if (firsttype == FTexture::TEX_Null || if (firsttype == FTexture::TEX_Null ||
(firsttype == FTexture::TEX_MiscPatch && tex->UseType != FTexture::TEX_Null) (firsttype == FTexture::TEX_MiscPatch &&
tex->UseType != firsttype &&
tex->UseType != FTexture::TEX_Null)
) )
{ {
firstfound = i; firstfound = i;
@ -1005,7 +1007,7 @@ FArchive &operator<< (FArchive &arc, FTextureID &tex)
//========================================================================== //==========================================================================
// //
// FTextureID::operator+ // FTextureID::operator+
// Does not return incvalid texture IDs // Does not return invalid texture IDs
// //
//========================================================================== //==========================================================================

View file

@ -41,6 +41,8 @@ protected:
FTextureID(int num) { texnum = num; } FTextureID(int num) { texnum = num; }
private: private:
int texnum; int texnum;
friend void AddTiles (void *tiles);
}; };
class FNullTextureID : public FTextureID class FNullTextureID : public FTextureID

View file

@ -153,6 +153,12 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par
ti->PainChances = new PainChanceList; ti->PainChances = new PainChanceList;
*ti->PainChances = *parent->PainChances; *ti->PainChances = *parent->PainChances;
} }
if (parent->ColorSets != NULL)
{
// copy color sets from parent
ti->ColorSets = new FPlayerColorSetMap;
*ti->ColorSets = *parent->ColorSets;
}
ti->Replacee = ti->Replacement = NULL; ti->Replacee = ti->Replacement = NULL;
ti->DoomEdNum = -1; ti->DoomEdNum = -1;
return ti; return ti;

View file

@ -1280,7 +1280,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
self->target->x, self->target->x,
self->target->y); self->target->y);
} }
self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, false, false, false, aim ? self->target : NULL); self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL);
if (linetarget == NULL && aim) if (linetarget == NULL && aim)
{ {
// We probably won't hit the target, but aim at it anyway so we don't look stupid. // We probably won't hit the target, but aim at it anyway so we don't look stupid.
@ -2016,7 +2016,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight)
for (int i = 0; i < MAXPLAYERS; i++) for (int i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && P_CheckSight(players[i].camera, self, true)) if (playeringame[i] && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY))
return 0; return 0;
} }
@ -2024,6 +2024,61 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight)
return 0; return 0;
} }
//===========================================================================
//
// A_CheckSightOrRange
// Jumps if this actor is out of range of all players *and* out of sight.
// Useful for maps with many multi-actor special effects.
//
//===========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange)
{
PARAM_ACTION_PROLOGUE;
PARAM_FLOAT(range);
PARAM_STATE(jump);
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
range = range * range * (double(FRACUNIT) * FRACUNIT); // no need for square roots
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i])
{
AActor *camera = players[i].camera;
// Check distance first, since it's cheaper than checking sight.
double dx = self->x - camera->x;
double dy = self->y - camera->y;
double dz;
fixed_t eyez = (camera->z + camera->height - (camera->height>>2)); // same eye height as P_CheckSight
if (eyez > self->z + self->height)
{
dz = self->z + self->height - eyez;
}
else if (eyez < self->z)
{
dz = self->z - eyez;
}
else
{
dz = 0;
}
if ((dx*dx) + (dy*dy) + (dz*dz) <= range)
{ // Within range
return 0;
}
// Now check LOS.
if (P_CheckSight(camera, self, SF_IGNOREVISIBILITY))
{ // Visible
return 0;
}
}
}
ACTION_JUMP(jump);
return 0;
}
//=========================================================================== //===========================================================================
// //
@ -2493,7 +2548,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
if (target == NULL) if (target == NULL)
return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case.
if (!P_CheckSight (self, target, 1)) if (!P_CheckSight (self, target, SF_IGNOREVISIBILITY))
return 0; return 0;
if (fov && (fov < ANGLE_MAX)) if (fov && (fov < ANGLE_MAX))
@ -2555,7 +2610,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
if (target == NULL) if (target == NULL)
return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case.
if (!P_CheckSight (target, self, 1)) if (!P_CheckSight (target, self, SF_IGNOREVISIBILITY))
return 0; return 0;
if (fov && (fov < ANGLE_MAX)) if (fov && (fov < ANGLE_MAX))
@ -2963,7 +3018,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire)
if (self->target == NULL if (self->target == NULL
|| P_HitFriend (self) || P_HitFriend (self)
|| self->target->health <= 0 || self->target->health <= 0
|| !P_CheckSight(self, self->target, 0) ) || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) )
{ {
ACTION_JUMP(jump); ACTION_JUMP(jump);
} }
@ -3132,16 +3187,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar)
PARAM_NAME (varname); PARAM_NAME (varname);
PARAM_INT (value); PARAM_INT (value);
PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); PSymbolVariable *var = dyn_cast<PSymbolVariable>(stateowner->GetClass()->Symbols.FindSymbol(varname, true));
if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int) if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int)
{ {
Printf("%s is not a user variable in class %s\n", varname.GetChars(), Printf("%s is not a user variable in class %s\n", varname.GetChars(),
self->GetClass()->TypeName.GetChars()); stateowner->GetClass()->TypeName.GetChars());
return 0; return 0;
} }
// Set the value of the specified user variable. // Set the value of the specified user variable.
*(int *)(reinterpret_cast<BYTE *>(self) + var->offset) = value; *(int *)(reinterpret_cast<BYTE *>(stateowner) + var->offset) = value;
return 0; return 0;
} }
@ -3158,22 +3213,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray)
PARAM_INT (pos); PARAM_INT (pos);
PARAM_INT (value); PARAM_INT (value);
PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); PSymbolVariable *var = dyn_cast<PSymbolVariable>(stateowner->GetClass()->Symbols.FindSymbol(varname, true));
if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int)
{ {
Printf("%s is not a user array in class %s\n", varname.GetChars(), Printf("%s is not a user array in class %s\n", varname.GetChars(),
self->GetClass()->TypeName.GetChars()); stateowner->GetClass()->TypeName.GetChars());
return 0; return 0;
} }
if (pos < 0 || pos >= var->ValueType.size) if (pos < 0 || pos >= var->ValueType.size)
{ {
Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(),
self->GetClass()->TypeName.GetChars()); stateowner->GetClass()->TypeName.GetChars());
return 0; return 0;
} }
// Set the value of the specified user array at index pos. // Set the value of the specified user array at index pos.
((int *)(reinterpret_cast<BYTE *>(self) + var->offset))[pos] = value; ((int *)(reinterpret_cast<BYTE *>(stateowner) + var->offset))[pos] = value;
return 0; return 0;
} }

View file

@ -310,6 +310,7 @@ static FFlagDef WeaponFlags[] =
DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags),
DEFINE_DUMMY_FLAG(NOLMS), DEFINE_DUMMY_FLAG(NOLMS),
DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL),
}; };
static FFlagDef PlayerPawnFlags[] = static FFlagDef PlayerPawnFlags[] =
@ -612,3 +613,4 @@ void InitThingdef()
qsort(&variables[0], variables.Size(), sizeof(variables[0]), varcmp); qsort(&variables[0], variables.Size(), sizeof(variables[0]), varcmp);
} }
} }

View file

@ -370,8 +370,7 @@ DEFINE_PROPERTY(painchance, ZI, Actor)
if (!stricmp(str, "Normal")) painType = NAME_None; if (!stricmp(str, "Normal")) painType = NAME_None;
else painType=str; else painType=str;
if (info->PainChances == NULL) info->PainChances=new PainChanceList; info->SetPainChance(painType, id);
(*info->PainChances)[painType] = (BYTE)id;
} }
} }
@ -568,6 +567,15 @@ DEFINE_PROPERTY(howlsound, S, Actor)
static_cast<PClassActor *>(info)->HowlSound = str; static_cast<PClassActor *>(info)->HowlSound = str;
} }
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(crushpainsound, S, Actor)
{
PROP_STRING_PARM(str, 0);
defaults->CrushPainSound = str;
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -978,13 +986,11 @@ DEFINE_PROPERTY(damagefactor, ZF, Actor)
} }
else else
{ {
if (info->DamageFactors == NULL) info->DamageFactors=new DmgFactors;
FName dmgType; FName dmgType;
if (!stricmp(str, "Normal")) dmgType = NAME_None; if (!stricmp(str, "Normal")) dmgType = NAME_None;
else dmgType=str; else dmgType=str;
(*info->DamageFactors)[dmgType]=id; info->SetDamageFactor(dmgType, id);
} }
} }
@ -1606,6 +1612,15 @@ DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
static_cast<PClassWeapon *>(info)->SlotPriority = i; static_cast<PClassWeapon *>(info)->SlotPriority = i;
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(preferredskin, S, Weapon)
{
PROP_STRING_PARM(str, 0);
// NoOp - only for Skulltag compatibility
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -1892,6 +1907,75 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn)
static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end; static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end;
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIII, PlayerPawn)
{
PROP_INT_PARM(setnum, 0);
PROP_STRING_PARM(setname, 1);
PROP_INT_PARM(rangestart, 2);
PROP_INT_PARM(rangeend, 3);
PROP_INT_PARM(representative_color, 4);
FPlayerColorSet color;
color.Name = setname;
color.Lump = -1;
color.FirstColor = rangestart;
color.LastColor = rangeend;
color.RepresentativeColor = representative_color;
if (setnum < 0)
{
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
}
else
{
info->SetColorSet(setnum, &color);
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
{
PROP_INT_PARM(setnum, 0);
PROP_STRING_PARM(setname, 1);
PROP_STRING_PARM(rangefile, 2);
PROP_INT_PARM(representative_color, 3);
FPlayerColorSet color;
color.Name = setname;
color.Lump = Wads.CheckNumForName(rangefile);
color.RepresentativeColor = representative_color;
if (setnum < 0)
{
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
}
else if (color.Lump >= 0)
{
info->SetColorSet(setnum, &color);
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
{
PROP_INT_PARM(setnum, 0);
if (setnum < 0)
{
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
}
else
{
info->SetColorSet(setnum, NULL);
}
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================

View file

@ -527,6 +527,10 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag
case DTA_Translation: case DTA_Translation:
parms->remap = va_arg(tags, FRemapTable *); parms->remap = va_arg(tags, FRemapTable *);
if (parms->remap != NULL && parms->remap->Inactive)
{ // If it's inactive, pretend we were passed NULL instead.
parms->remap = NULL;
}
break; break;
case DTA_ColorOverlay: case DTA_ColorOverlay:

View file

@ -130,7 +130,10 @@ protected:
bool rescale, PalEntry *out_palette); bool rescale, PalEntry *out_palette);
void LoadFON1 (int lump, const BYTE *data); void LoadFON1 (int lump, const BYTE *data);
void LoadFON2 (int lump, const BYTE *data); void LoadFON2 (int lump, const BYTE *data);
void LoadBMF (int lump, const BYTE *data);
void CreateFontFromPic (FTextureID picnum); void CreateFontFromPic (FTextureID picnum);
static int STACK_ARGS BMFCompare(const void *a, const void *b);
}; };
class FSinglePicFont : public FFont class FSinglePicFont : public FFont
@ -175,7 +178,7 @@ protected:
class FFontChar2 : public FTexture class FFontChar2 : public FTexture
{ {
public: public:
FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height); FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
~FFontChar2 (); ~FFontChar2 ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out); const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -261,12 +264,13 @@ FFont *V_GetFont(const char *name)
if (lump != -1) if (lump != -1)
{ {
char head[3]; uint32 head;
{ {
FWadLump lumpy = Wads.OpenLumpNum (lump); FWadLump lumpy = Wads.OpenLumpNum (lump);
lumpy.Read (head, 3); lumpy.Read (&head, 4);
} }
if (head[0] == 'F' && head[1] == 'O' && head[2] == 'N') if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) ||
head == MAKE_ID(0xE1,0xE6,0xD5,0x1A))
{ {
font = new FSingleLumpFont (name, lump); font = new FSingleLumpFont (name, lump);
} }
@ -399,21 +403,26 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
if (charlumps[i] != NULL) if (charlumps[i] != NULL)
{ {
Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap); Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap);
Chars[i].XMove = Chars[i].Pic->GetScaledWidth();
} }
else else
{ {
Chars[i].Pic = NULL; Chars[i].Pic = NULL;
Chars[i].XMove = INT_MIN;
} }
} }
if ('N'-first>=0 && 'N'-first<count && Chars['N' - first].Pic) if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL)
{ {
SpaceWidth = (Chars['N' - first].Pic->GetScaledWidth() + 1) / 2; SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
} }
else else
{ {
SpaceWidth = 4; SpaceWidth = 4;
} }
FixXMoves();
BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL);
delete[] luminosity; delete[] luminosity;
@ -717,6 +726,33 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range) const
return &Ranges[range]; return &Ranges[range];
} }
//==========================================================================
//
// FFont :: GetCharCode
//
// If the character code is in the font, returns it. If it is not, but it
// is lowercase and has an uppercase variant present, return that. Otherwise
// return -1.
//
//==========================================================================
int FFont::GetCharCode(int code, bool needpic) const
{
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL))
{
return code;
}
if (myislower[code])
{
code -= 32;
if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL))
{
return code;
}
}
return -1;
}
//========================================================================== //==========================================================================
// //
// FFont :: GetChar // FFont :: GetChar
@ -725,31 +761,28 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range) const
FTexture *FFont::GetChar (int code, int *const width) const FTexture *FFont::GetChar (int code, int *const width) const
{ {
if (code < FirstChar || code = GetCharCode(code, false);
code > LastChar || int xmove = SpaceWidth;
Chars[code - FirstChar].Pic == NULL)
{
if (myislower[code])
{
code -= 32;
if (code < FirstChar ||
code > LastChar ||
Chars[code - FirstChar].Pic == NULL)
{
if (width != NULL) *width = SpaceWidth;
return NULL;
}
}
else
{
if (width != NULL) *width = SpaceWidth;
return NULL;
}
}
if (code >= 0)
{
code -= FirstChar; code -= FirstChar;
if (width != NULL) *width = Chars[code].Pic->GetScaledWidth(); xmove = Chars[code].XMove;
return Chars[code].Pic; if (Chars[code].Pic == NULL)
{
code = GetCharCode(code + FirstChar, true);
if (code >= 0)
{
code -= FirstChar;
xmove = Chars[code].XMove;
}
}
}
if (width != NULL)
{
*width = xmove;
}
return (code < 0) ? NULL : Chars[code].Pic;
} }
//========================================================================== //==========================================================================
@ -760,27 +793,8 @@ FTexture *FFont::GetChar (int code, int *const width) const
int FFont::GetCharWidth (int code) const int FFont::GetCharWidth (int code) const
{ {
if (code < FirstChar || code = GetCharCode(code, false);
code > LastChar || return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove;
Chars[code - FirstChar].Pic == NULL)
{
if (myislower[code])
{
code -= 32;
if (code < FirstChar ||
code > LastChar ||
Chars[code - FirstChar].Pic == NULL)
{
return SpaceWidth;
}
}
else
{
return SpaceWidth;
}
}
return Chars[code - FirstChar].Pic->GetScaledWidth();
} }
//========================================================================== //==========================================================================
@ -858,7 +872,11 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump)
FMemLump data1 = Wads.ReadLump (lump); FMemLump data1 = Wads.ReadLump (lump);
const BYTE *data = (const BYTE *)data1.GetMem(); const BYTE *data = (const BYTE *)data1.GetMem();
if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A)
{
LoadBMF(lump, data);
}
else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' ||
(data[3] != '1' && data[3] != '2')) (data[3] != '1' && data[3] != '2'))
{ {
I_FatalError ("%s is not a recognizable font", name); I_FatalError ("%s is not a recognizable font", name);
@ -1012,6 +1030,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
{ {
int destSize = widths2[i] * FontHeight; int destSize = widths2[i] * FontHeight;
Chars[i].XMove = widths2[i];
if (destSize <= 0) if (destSize <= 0)
{ {
Chars[i].Pic = NULL; Chars[i].Pic = NULL;
@ -1045,6 +1064,157 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
delete[] widths2; delete[] widths2;
} }
//==========================================================================
//
// FSingleLumpFont :: LoadBMF
//
// Loads a BMF font. The file format is described at
// <http://bmf.wz.cz/bmf-format.htm>
//
//==========================================================================
void FSingleLumpFont::LoadBMF(int lump, const BYTE *data)
{
const BYTE *chardata;
int numchars, count, totalwidth, nwidth;
int infolen;
int i, chari;
BYTE raw_palette[256*3];
PalEntry sort_palette[256];
PalEntry local_palette[256];
double luminosity[256];
BYTE identity[256];
FontHeight = data[5];
GlobalKerning = (SBYTE)data[8];
ActiveColors = data[16];
SpaceWidth = -1;
nwidth = -1;
infolen = data[17 + ActiveColors*3];
chardata = data + 18 + ActiveColors*3 + infolen;
numchars = chardata[0] + 256*chardata[1];
chardata += 2;
// Scan for lowest and highest characters defined and total font width.
FirstChar = 256;
LastChar = 0;
totalwidth = 0;
for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2])
{
if ((chardata[chari+1] == 0 || chardata[chari+2] == 0) && chardata[chari+5] == 0)
{ // Don't count empty characters.
continue;
}
if (chardata[chari] < FirstChar)
{
FirstChar = chardata[chari];
}
if (chardata[chari] > LastChar)
{
LastChar = chardata[chari];
}
totalwidth += chardata[chari+1];
}
if (LastChar < FirstChar)
{
I_FatalError("BMF font defines no characters");
}
count = LastChar - FirstChar + 1;
Chars = new CharData[count];
for (i = 0; i < count; ++i)
{
Chars[i].Pic = NULL;
Chars[i].XMove = INT_MIN;
}
// BMF palettes are only six bits per component. Fix that.
for (i = 0; i < ActiveColors*3; ++i)
{
raw_palette[i] = (data[17 + i] << 2) | (data[17 + i] >> 4);
}
// Sort the palette by increasing brightness
for (i = 0; i < ActiveColors; ++i)
{
PalEntry *pal = &sort_palette[i];
pal->a = i; // Use alpha part to point back to original entry
pal->r = raw_palette[i*3 + 0];
pal->g = raw_palette[i*3 + 1];
pal->b = raw_palette[i*3 + 2];
}
qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare);
// Create the PatchRemap table from the sorted "alpha" values.
PatchRemap = new BYTE[ActiveColors];
PatchRemap[0] = 0;
for (i = 1; i < ActiveColors; ++i)
{
PatchRemap[sort_palette[i].a] = i;
}
FixupPalette(identity, luminosity, raw_palette, true, local_palette);
// Now scan through the characters again, creating glyphs for each one.
for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2])
{
assert(chardata[chari] - FirstChar >= 0);
assert(chardata[chari] - FirstChar < count);
if (chardata[chari] == ' ')
{
SpaceWidth = chardata[chari+5];
}
else if (chardata[chari] == 'N')
{
nwidth = chardata[chari+5];
}
Chars[chardata[chari] - FirstChar].XMove = chardata[chari+5];
if (chardata[chari+1] == 0 || chardata[chari+2] == 0)
{ // Empty character: skip it.
continue;
}
Chars[chardata[chari] - FirstChar].Pic = new FFontChar2(lump, PatchRemap, int(chardata + chari + 6 - data),
chardata[chari+1], // width
chardata[chari+2], // height
-(SBYTE)chardata[chari+3], // x offset
-(SBYTE)chardata[chari+4] // y offset
);
}
// If the font did not define a space character, determine a suitable space width now.
if (SpaceWidth < 0)
{
if (nwidth >= 0)
{
SpaceWidth = nwidth;
}
else
{
SpaceWidth = totalwidth * 2 / (3 * count);
}
}
FixXMoves();
BuildTranslations(luminosity, identity, &TranslationParms[0][0], ActiveColors, local_palette);
}
//==========================================================================
//
// FSingleLumpFont :: BMFCompare STATIC
//
// Helper to sort BMF palettes.
//
//==========================================================================
int STACK_ARGS FSingleLumpFont::BMFCompare(const void *a, const void *b)
{
const PalEntry *pa = (const PalEntry *)a;
const PalEntry *pb = (const PalEntry *)b;
return (pa->r * 299 + pa->g * 587 + pa->b * 114) -
(pb->r * 299 + pb->g * 587 + pb->b * 114);
}
//========================================================================== //==========================================================================
// //
// FSingleLumpFont :: CheckFON1Chars // FSingleLumpFont :: CheckFON1Chars
@ -1069,6 +1239,7 @@ void FSingleLumpFont::CheckFON1Chars (int lump, const BYTE *data, double *lumino
int destSize = SpaceWidth * FontHeight; int destSize = SpaceWidth * FontHeight;
Chars[i].Pic = new FFontChar2 (lump, PatchRemap, int(data_p - data), SpaceWidth, FontHeight); Chars[i].Pic = new FFontChar2 (lump, PatchRemap, int(data_p - data), SpaceWidth, FontHeight);
Chars[i].XMove = SpaceWidth;
// Advance to next char's data and count the used colors. // Advance to next char's data and count the used colors.
do do
@ -1181,8 +1352,8 @@ FSinglePicFont::FSinglePicFont(const char *picname)
FTexture *pic = TexMan[picnum]; FTexture *pic = TexMan[picnum];
Name = copystring(picname); Name = copystring(picname);
FontHeight = pic->GetHeight(); FontHeight = pic->GetScaledHeight();
SpaceWidth = pic->GetWidth(); SpaceWidth = pic->GetScaledWidth();
GlobalKerning = 0; GlobalKerning = 0;
FirstChar = LastChar = 'A'; FirstChar = LastChar = 'A';
ActiveColors = 0; ActiveColors = 0;
@ -1332,14 +1503,14 @@ FFontChar1::~FFontChar1 ()
// //
//========================================================================== //==========================================================================
FFontChar2::FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height) FFontChar2::FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs, int topofs)
: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(sourceremap) : SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(sourceremap)
{ {
UseType = TEX_FontChar; UseType = TEX_FontChar;
Width = width; Width = width;
Height = height; Height = height;
TopOffset = 0; LeftOffset = leftofs;
LeftOffset = 0; TopOffset = topofs;
CalcBitSize (); CalcBitSize ();
} }
@ -1427,10 +1598,11 @@ void FFontChar2::MakeTexture ()
FWadLump lump = Wads.OpenLumpNum (SourceLump); FWadLump lump = Wads.OpenLumpNum (SourceLump);
int destSize = Width * Height; int destSize = Width * Height;
BYTE max = 255; BYTE max = 255;
bool rle = true;
// This is to "fix" bad fonts // This is to "fix" bad fonts
{ {
BYTE buff[8]; BYTE buff[16];
lump.Read (buff, 4); lump.Read (buff, 4);
if (buff[3] == '2') if (buff[3] == '2')
{ {
@ -1438,6 +1610,13 @@ void FFontChar2::MakeTexture ()
max = buff[6]; max = buff[6];
lump.Seek (SourcePos - 11, SEEK_CUR); lump.Seek (SourcePos - 11, SEEK_CUR);
} }
else if (buff[3] == 0x1A)
{
lump.Read(buff, 13);
max = buff[12] - 1;
lump.Seek (SourcePos - 17, SEEK_CUR);
rle = false;
}
else else
{ {
lump.Seek (SourcePos - 4, SEEK_CUR); lump.Seek (SourcePos - 4, SEEK_CUR);
@ -1452,6 +1631,8 @@ void FFontChar2::MakeTexture ()
int dest_adv = Height; int dest_adv = Height;
int dest_rew = destSize - 1; int dest_rew = destSize - 1;
if (rle)
{
for (int y = Height; y != 0; --y) for (int y = Height; y != 0; --y)
{ {
for (int x = Width; x != 0; ) for (int x = Width; x != 0; )
@ -1461,11 +1642,12 @@ void FFontChar2::MakeTexture ()
BYTE color; BYTE color;
lump >> color; lump >> color;
*dest_p = MIN (color, max); color = MIN (color, max);
if (SourceRemap != NULL) if (SourceRemap != NULL)
{ {
*dest_p = SourceRemap[*dest_p]; color = SourceRemap[color];
} }
*dest_p = color;
dest_p += dest_adv; dest_p += dest_adv;
x--; x--;
runlen--; runlen--;
@ -1502,6 +1684,29 @@ void FFontChar2::MakeTexture ()
} }
dest_p -= dest_rew; dest_p -= dest_rew;
} }
}
else
{
for (int y = Height; y != 0; --y)
{
for (int x = Width; x != 0; --x)
{
BYTE color;
lump >> color;
if (color > max)
{
color = max;
}
if (SourceRemap != NULL)
{
color = SourceRemap[color];
}
*dest_p = color;
dest_p += dest_adv;
}
dest_p -= dest_rew;
}
}
if (destSize < 0) if (destSize < 0)
{ {
@ -1593,23 +1798,27 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
if (charlumps[i] != NULL) if (charlumps[i] != NULL)
{ {
Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap); Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap);
Chars[i].XMove = Chars[i].Pic->GetScaledWidth();
} }
else else
{ {
Chars[i].Pic = NULL; Chars[i].Pic = NULL;
Chars[i].XMove = INT_MIN;
} }
} }
// Special fonts normally don't have all characters so be careful here! // Special fonts normally don't have all characters so be careful here!
if ('N'-first>=0 && 'N'-first<count && Chars['N' - first].Pic) if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL)
{ {
SpaceWidth = (Chars['N' - first].Pic->GetScaledWidth() + 1) / 2; SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
} }
else else
{ {
SpaceWidth = 4; SpaceWidth = 4;
} }
FixXMoves();
BuildTranslations (luminosity, identity, &TranslationParms[0][0], TotalColors, NULL); BuildTranslations (luminosity, identity, &TranslationParms[0][0], TotalColors, NULL);
// add the untranslated colors to the Ranges tables // add the untranslated colors to the Ranges tables
@ -1632,6 +1841,36 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
delete[] charlumps; delete[] charlumps;
} }
//==========================================================================
//
// FFont :: FixXMoves
//
// If a font has gaps in its characters, set the missing characters'
// XMoves to either SpaceWidth or the uppercase variant's XMove. Missing
// XMoves must be initialized with INT_MIN beforehand.
//
//==========================================================================
void FFont::FixXMoves()
{
for (int i = 0; i <= LastChar - FirstChar; ++i)
{
if (Chars[i].XMove == INT_MIN)
{
if (myislower[i + FirstChar])
{
int upper = i - 32;
if (upper >= 0)
{
Chars[i].XMove = Chars[upper].XMove;
continue;
}
}
Chars[i].XMove = SpaceWidth;
}
}
}
//========================================================================== //==========================================================================
// //

View file

@ -94,11 +94,14 @@ public:
int StringWidth (const BYTE *str) const; int StringWidth (const BYTE *str) const;
inline int StringWidth (const char *str) const { return StringWidth ((const BYTE *)str); } inline int StringWidth (const char *str) const { return StringWidth ((const BYTE *)str); }
int GetCharCode(int code, bool needpic) const;
protected: protected:
FFont (); FFont ();
void BuildTranslations (const double *luminosity, const BYTE *identity, void BuildTranslations (const double *luminosity, const BYTE *identity,
const void *ranges, int total_colors, const PalEntry *palette); const void *ranges, int total_colors, const PalEntry *palette);
void FixXMoves();
static int SimpleTranslation (BYTE *colorsused, BYTE *translation, static int SimpleTranslation (BYTE *colorsused, BYTE *translation,
BYTE *identity, double **luminosity); BYTE *identity, double **luminosity);
@ -110,6 +113,7 @@ protected:
struct CharData struct CharData
{ {
FTexture *Pic; FTexture *Pic;
int XMove;
} *Chars; } *Chars;
int ActiveColors; int ActiveColors;
TArray<FRemapTable> Ranges; TArray<FRemapTable> Ranges;

View file

@ -276,7 +276,7 @@ int FFont::StringWidth (const BYTE *string) const
++string; ++string;
} }
} }
else if (*string != '\0') if (*string != '\0')
{ {
++string; ++string;
} }
@ -317,14 +317,15 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string)
FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) FBrokenLines lines[128]; // Support up to 128 lines (should be plenty)
const BYTE *space = NULL, *start = string; const BYTE *space = NULL, *start = string;
int i, c, w, nw; size_t i, ii;
int c, w, nw;
FString lastcolor, linecolor; FString lastcolor, linecolor;
bool lastWasSpace = false; bool lastWasSpace = false;
int kerning = font->GetDefaultKerning (); int kerning = font->GetDefaultKerning ();
i = w = 0; i = w = 0;
while ( (c = *string++) && i < 128 ) while ( (c = *string++) && i < countof(lines) )
{ {
if (c == TEXTCOLOR_ESCAPE) if (c == TEXTCOLOR_ESCAPE)
{ {
@ -400,7 +401,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string)
} }
// String here is pointing one character after the '\0' // String here is pointing one character after the '\0'
if (i < 128 && --string - start >= 1) if (i < countof(lines) && --string - start >= 1)
{ {
const BYTE *s = start; const BYTE *s = start;
@ -418,11 +419,11 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string)
// Make a copy of the broken lines and return them // Make a copy of the broken lines and return them
FBrokenLines *broken = new FBrokenLines[i+1]; FBrokenLines *broken = new FBrokenLines[i+1];
for (c = 0; c < i; ++c) for (ii = 0; ii < i; ++ii)
{ {
broken[c] = lines[c]; broken[ii] = lines[ii];
} }
broken[c].Width = -1; broken[ii].Width = -1;
return broken; return broken;
} }

View file

@ -1523,7 +1523,7 @@ CCMD (vid_setmode)
void V_Init (void) void V_Init (void)
{ {
char *i; const char *i;
int width, height, bits; int width, height, bits;
atterm (V_Shutdown); atterm (V_Shutdown);

View file

@ -848,6 +848,46 @@ int FWadCollection::FindLump (const char *name, int *lastlump, bool anyns)
return -1; return -1;
} }
//==========================================================================
//
// W_FindLumpMulti
//
// Find a named lump. Specifically allows duplicates for merging of e.g.
// SNDINFO lumps. Returns everything having one of the passed names.
//
//==========================================================================
int FWadCollection::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex)
{
LumpRecord *lump_p;
assert(lastlump != NULL && *lastlump >= 0);
lump_p = &LumpInfo[*lastlump];
while (lump_p < &LumpInfo[NumLumps])
{
FResourceLump *lump = lump_p->lump;
if (anyns || lump->Namespace == ns_global)
{
for(const char **name = names; *name != NULL; name++)
{
if (!strnicmp(*name, lump->Name, 8))
{
int lump = int(lump_p - &LumpInfo[0]);
*lastlump = lump + 1;
if (nameindex != NULL) *nameindex = int(name - names);
return lump;
}
}
}
lump_p++;
}
*lastlump = NumLumps;
return -1;
}
//========================================================================== //==========================================================================
// //
// W_CheckLumpName // W_CheckLumpName
@ -927,6 +967,24 @@ int FWadCollection::GetLumpNamespace (int lump) const
return LumpInfo[lump].lump->Namespace; return LumpInfo[lump].lump->Namespace;
} }
//==========================================================================
//
// FWadCollection :: GetLumpIndexNum
//
// Returns the index number for this lump. This is *not* the lump's position
// in the lump directory, but rather a special value that RFF can associate
// with files. Other archive types will return 0, since they don't have it.
//
//==========================================================================
int FWadCollection::GetLumpIndexNum(int lump) const
{
if ((size_t)lump >= NumLumps)
return 0;
else
return LumpInfo[lump].lump->GetIndexNum();
}
//========================================================================== //==========================================================================
// //
// W_GetLumpFile // W_GetLumpFile

View file

@ -182,6 +182,7 @@ public:
FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication
int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names
bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name
static DWORD LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name static DWORD LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name
@ -194,6 +195,7 @@ public:
FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name
int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump
int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to
int GetLumpIndexNum (int lump) const; // Returns the RFF index number for this lump
bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match
bool IsUncompressedFile(int lump) const; bool IsUncompressedFile(int lump) const;

View file

@ -1935,15 +1935,13 @@ void WI_loadData(void)
} }
else else
{ {
int dummywidth; star = BigFont->GetChar('*', NULL);
star = BigFont->GetChar('*', &dummywidth); // just a dummy to avoid an error if it is being used
bstar = star; bstar = star;
} }
} }
else // Strife needs some handling, too! else // Strife needs some handling, too!
{ {
int dummywidth; star = BigFont->GetChar('*', NULL);
star = BigFont->GetChar('*', &dummywidth); // just a dummy to avoid an error if it is being used
bstar = star; bstar = star;
} }

View file

@ -503,6 +503,71 @@ void __cdecl Writef (HANDLE file, const char *format, ...)
WriteFile (file, buffer, len, &len, NULL); WriteFile (file, buffer, len, &len, NULL);
} }
//==========================================================================
//
// WriteLogFileStreamer
//
// The callback function to stream a Rich Edit's contents to a file.
//
//==========================================================================
static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
{
DWORD didwrite;
LONG p, pp;
// Replace gray foreground color with black.
static const char *badfg = "\\red223\\green223\\blue223;";
// 4321098 765432109 876543210
// 2 1 0
for (p = pp = 0; p < cb; ++p)
{
if (buffer[p] == badfg[pp])
{
++pp;
if (pp == 25)
{
buffer[p - 1] = buffer[p - 2] = buffer[p - 3] =
buffer[p - 9] = buffer[p -10] = buffer[p -11] =
buffer[p -18] = buffer[p -19] = buffer[p -20] = '0';
break;
}
}
else
{
pp = 0;
}
}
if (!WriteFile((HANDLE)cookie, buffer, cb, &didwrite, NULL))
{
return 1;
}
*pcb = didwrite;
return 0;
}
//==========================================================================
//
// WriteLogFile
//
// Writes the contents of a Rich Edit control to a file.
//
//==========================================================================
HANDLE WriteLogFile(HWND edit)
{
HANDLE file;
file = CreateTempFile();
if (file != INVALID_HANDLE_VALUE)
{
EDITSTREAM streamer = { (DWORD_PTR)file, 0, WriteLogFileStreamer };
SendMessage(edit, EM_STREAMOUT, SF_RTF, (LPARAM)&streamer);
}
return file;
}
//========================================================================== //==========================================================================
// //
// CreateCrashLog // CreateCrashLog
@ -511,7 +576,7 @@ void __cdecl Writef (HANDLE file, const char *format, ...)
// //
//========================================================================== //==========================================================================
void CreateCrashLog (char *custominfo, DWORD customsize) void CreateCrashLog (char *custominfo, DWORD customsize, HWND richlog)
{ {
// Do not collect information more than once. // Do not collect information more than once.
if (NumFiles != 0) if (NumFiles != 0)
@ -561,6 +626,10 @@ void CreateCrashLog (char *custominfo, DWORD customsize)
AddFile (file, "local.txt"); AddFile (file, "local.txt");
} }
} }
if (richlog != NULL)
{
AddFile (WriteLogFile(richlog), "log.rtf");
}
CloseHandle (DbgProcess); CloseHandle (DbgProcess);
} }
@ -1984,7 +2053,6 @@ static INT_PTR CALLBACK CrashDlgProc (HWND hDlg, UINT message, WPARAM wParam, LP
static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{ {
HGDIOBJ font;
HWND ctrl; HWND ctrl;
int i, j; int i, j;
@ -1996,15 +2064,9 @@ static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam,
pEnableThemeDialogTexture (hDlg, ETDT_ENABLETAB); pEnableThemeDialogTexture (hDlg, ETDT_ENABLETAB);
} }
// Set up the file contents display: Use a fixed width font, // Set up the file contents display: No undos. The control's
// no undos. The control's userdata stores the index of the // userdata stores the index of the file currently displayed.
// file currently displayed.
ctrl = GetDlgItem (hDlg, IDC_CRASHFILECONTENTS); ctrl = GetDlgItem (hDlg, IDC_CRASHFILECONTENTS);
font = GetStockObject (ANSI_FIXED_FONT);
if (font != INVALID_HANDLE_VALUE)
{
SendMessage (ctrl, WM_SETFONT, (WPARAM)font, FALSE);
}
SendMessage (ctrl, EM_SETUNDOLIMIT, 0, 0); SendMessage (ctrl, EM_SETUNDOLIMIT, 0, 0);
SetWindowLongPtr (ctrl, GWLP_USERDATA, -1); SetWindowLongPtr (ctrl, GWLP_USERDATA, -1);
SetEditControl (ctrl, GetDlgItem(hDlg, IDC_CRASHFILESIZE), 0); SetEditControl (ctrl, GetDlgItem(hDlg, IDC_CRASHFILESIZE), 0);
@ -2178,6 +2240,8 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum)
EDITSTREAM stream; EDITSTREAM stream;
DWORD size; DWORD size;
POINT pt = { 0, 0 }; POINT pt = { 0, 0 };
const char *rtf = NULL;
HGDIOBJ font;
// Don't refresh the control if it's already showing the file we want. // Don't refresh the control if it's already showing the file we want.
if (GetWindowLongPtr (edit, GWLP_USERDATA) == filenum) if (GetWindowLongPtr (edit, GWLP_USERDATA) == filenum)
@ -2201,10 +2265,19 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum)
SetFilePointer (TarFiles[filenum].File, 0, NULL, FILE_BEGIN); SetFilePointer (TarFiles[filenum].File, 0, NULL, FILE_BEGIN);
SendMessage (edit, EM_SETSCROLLPOS, 0, (LPARAM)&pt); SendMessage (edit, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
// Set the font now, in case log.rtf was previously viewed, because
// that file changes it.
font = GetStockObject (ANSI_FIXED_FONT);
if (font != INVALID_HANDLE_VALUE)
{
SendMessage (edit, WM_SETFONT, (WPARAM)font, FALSE);
}
// Text files are streamed in as-is. // Text files are streamed in as-is.
// Binary files are streamed in as color-coded hex dumps. // Binary files are streamed in as color-coded hex dumps.
stream.dwError = 0; stream.dwError = 0;
if (strstr (TarFiles[filenum].Filename, ".txt") != NULL) if (strstr (TarFiles[filenum].Filename, ".txt") != NULL ||
(rtf = strstr (TarFiles[filenum].Filename, ".rtf")) != NULL)
{ {
CHARFORMAT beBlack; CHARFORMAT beBlack;
@ -2215,7 +2288,7 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum)
SendMessage (edit, EM_SETCHARFORMAT, 0, (LPARAM)&beBlack); SendMessage (edit, EM_SETCHARFORMAT, 0, (LPARAM)&beBlack);
stream.dwCookie = (DWORD_PTR)TarFiles[filenum].File; stream.dwCookie = (DWORD_PTR)TarFiles[filenum].File;
stream.pfnCallback = StreamEditText; stream.pfnCallback = StreamEditText;
SendMessage (edit, EM_STREAMIN, SF_TEXT, (LPARAM)&stream); SendMessage (edit, EM_STREAMIN, rtf ? SF_RTF : SF_TEXT | SF_USECODEPAGE | (1252 << 16), (LPARAM)&stream);
} }
else else
{ {

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