- Update to latest version in trunk.

SVN r3890 (scripting)
This commit is contained in:
Randy Heit 2012-10-17 04:24:54 +00:00
commit e7efa1d802
117 changed files with 2261 additions and 788 deletions

View file

@ -30,9 +30,7 @@
#include "dthinker.h" #include "dthinker.h"
// States are tied to finite states are // States are tied to finite states are tied to animation frames.
// tied to animation frames.
// Needs precompiled tables/data structures.
#include "info.h" #include "info.h"
#include "doomdef.h" #include "doomdef.h"
@ -40,6 +38,7 @@
#include "r_data/renderstyle.h" #include "r_data/renderstyle.h"
#include "s_sound.h" #include "s_sound.h"
#include "memarena.h" #include "memarena.h"
#include "g_level.h"
struct subsector_t; struct subsector_t;
class PClassAmmo; class PClassAmmo;
@ -550,15 +549,14 @@ public:
bool AdjustReflectionAngle (AActor *thing, angle_t &angle); bool AdjustReflectionAngle (AActor *thing, angle_t &angle);
// Returns true if this actor is within melee range of its target // Returns true if this actor is within melee range of its target
bool CheckMeleeRange (); bool CheckMeleeRange();
// BeginPlay: Called just after the actor is created virtual void BeginPlay(); // Called immediately after the actor is created
virtual void BeginPlay (); virtual void PostBeginPlay(); // Called immediately before the actor's first tick
virtual void PostBeginPlay (); virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
// LevelSpawned: Called after BeginPlay if this actor was spawned by the world virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.
virtual void LevelSpawned ();
// Translates SpawnFlags into in-game flags. virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching.
virtual void HandleSpawnFlags ();
virtual void Activate (AActor *activator); virtual void Activate (AActor *activator);
virtual void Deactivate (AActor *activator); virtual void Deactivate (AActor *activator);
@ -679,9 +677,20 @@ public:
// Do I hate the other actor? // Do I hate the other actor?
bool IsHostile (AActor *other); bool IsHostile (AActor *other);
inline bool IsNoClip2() const;
// What species am I? // What species am I?
virtual FName GetSpecies(); virtual FName GetSpecies();
fixed_t GetBobOffset(fixed_t ticfrac=0) const
{
if (!(flags2 & MF2_FLOATBOB))
{
return 0;
}
return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8;
}
// Enter the crash state // Enter the crash state
void Crash(); void Crash();
@ -938,6 +947,7 @@ private:
static FSharedStringArena mStringPropertyData; static FSharedStringArena mStringPropertyData;
friend class FActorIterator; friend class FActorIterator;
friend bool P_IsTIDUsed(int tid);
sector_t *LinkToWorldForMapThing (); sector_t *LinkToWorldForMapThing ();
@ -1032,6 +1042,9 @@ public:
} }
}; };
bool P_IsTIDUsed(int tid);
int P_FindUniqueTID(int start_tid, int limit);
inline AActor *Spawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) inline AActor *Spawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)
{ {
return AActor::StaticSpawn (type, x, y, z, allowreplacement); return AActor::StaticSpawn (type, x, y, z, allowreplacement);

View file

@ -173,6 +173,15 @@ CCMD (noclip)
Net_WriteByte (CHT_NOCLIP); Net_WriteByte (CHT_NOCLIP);
} }
CCMD (noclip2)
{
if (CheckCheatmode())
return;
Net_WriteByte (DEM_GENERICCHEAT);
Net_WriteByte (CHT_NOCLIP2);
}
CCMD (powerup) CCMD (powerup)
{ {
if (CheckCheatmode ()) if (CheckCheatmode ())
@ -243,7 +252,7 @@ CCMD (chase)
else else
{ {
// Check if we're allowed to use chasecam. // Check if we're allowed to use chasecam.
if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && CheckCheatmode ())) if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ()))
return; return;
Net_WriteByte (DEM_GENERICCHEAT); Net_WriteByte (DEM_GENERICCHEAT);
@ -947,9 +956,16 @@ CCMD(thaw)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CCMD(nextmap) CCMD(nextmap)
{ {
char * next=NULL; if (netgame)
{
Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextmap"
TEXTCOLOR_NORMAL" is for single-player only.\n");
return;
}
char *next = NULL;
if (*level.nextmap) next = level.nextmap; if (*level.nextmap)
next = level.nextmap;
if (next != NULL && strncmp(next, "enDSeQ", 6)) if (next != NULL && strncmp(next, "enDSeQ", 6))
{ {
@ -968,9 +984,16 @@ CCMD(nextmap)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CCMD(nextsecret) CCMD(nextsecret)
{ {
char * next=NULL; if (netgame)
{
Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextsecret"
TEXTCOLOR_NORMAL" is for single-player only.\n");
return;
}
char *next = NULL;
if (*level.secretmap) next = level.secretmap; if (*level.secretmap)
next = level.secretmap;
if (next != NULL && strncmp(next, "enDSeQ", 6)) if (next != NULL && strncmp(next, "enDSeQ", 6))
{ {

View file

@ -273,7 +273,9 @@ void CT_Drawer (void)
if (players[consoleplayer].camera != NULL && if (players[consoleplayer].camera != NULL &&
(Button_ShowScores.bDown || (Button_ShowScores.bDown ||
players[consoleplayer].camera->health <= 0)) players[consoleplayer].camera->health <= 0) &&
// Don't draw during intermission, since it has its own scoreboard in wi_stuff.cpp.
gamestate != GS_INTERMISSION)
{ {
HU_DrawScores (&players[consoleplayer]); HU_DrawScores (&players[consoleplayer]);
} }

View file

@ -1354,7 +1354,7 @@ static int PatchFrame (int frameNum)
if (keylen == 8 && stricmp (Line1, "Duration") == 0) if (keylen == 8 && stricmp (Line1, "Duration") == 0)
{ {
tics = clamp (val, -1, 65534); tics = clamp (val, -1, SHRT_MAX);
} }
else if (keylen == 9 && stricmp (Line1, "Unknown 1") == 0) else if (keylen == 9 && stricmp (Line1, "Unknown 1") == 0)
{ {

View file

@ -804,17 +804,21 @@ void D_Display ()
if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10) if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10)
{ {
StatusBar->DrawBottomStuff (HUD_None);
if (DrawFSHUD || automapactive) DrawHUD(); if (DrawFSHUD || automapactive) DrawHUD();
StatusBar->DrawTopStuff (HUD_None); StatusBar->DrawTopStuff (HUD_None);
} }
else else
if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10) if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10)
{ {
StatusBar->Draw (DrawFSHUD ? HUD_Fullscreen : HUD_None); EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None;
StatusBar->DrawTopStuff (DrawFSHUD ? HUD_Fullscreen : HUD_None); StatusBar->DrawBottomStuff (state);
StatusBar->Draw (state);
StatusBar->DrawTopStuff (state);
} }
else else
{ {
StatusBar->DrawBottomStuff (HUD_StatusBar);
StatusBar->Draw (HUD_StatusBar); StatusBar->Draw (HUD_StatusBar);
StatusBar->DrawTopStuff (HUD_StatusBar); StatusBar->DrawTopStuff (HUD_StatusBar);
} }
@ -2207,14 +2211,17 @@ void D_DoomMain (void)
// [RH] Load sound environments // [RH] Load sound environments
S_ParseReverbDef (); S_ParseReverbDef ();
// [RH] Parse any SNDINFO lumps
Printf ("S_InitData: Load sound definitions.\n");
S_InitData ();
// [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);
ReadStatistics(); ReadStatistics();
// [RH] Parse any SNDINFO lumps // MUSINFO must be parsed after MAPINFO
Printf ("S_InitData: Load sound definitions.\n"); S_ParseMusInfo();
S_InitData ();
Printf ("Texman.Init: Init texture manager.\n"); Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init(); TexMan.Init();

View file

@ -60,6 +60,7 @@
#include "p_lnspec.h" #include "p_lnspec.h"
#include "v_video.h" #include "v_video.h"
#include "p_spec.h" #include "p_spec.h"
#include "hardware.h"
#include "intermission/intermission.h" #include "intermission/intermission.h"
EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, disableautosave)
@ -135,7 +136,18 @@ static int oldentertics;
extern bool advancedemo; extern bool advancedemo;
CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
// Do not use the separate FPS limit timer if we are limiting FPS with this.
if (self)
{
I_SetFPSLimit(0);
}
else
{
I_SetFPSLimit(-1);
}
}
// [RH] Special "ticcmds" get stored in here // [RH] Special "ticcmds" get stored in here
static struct TicSpecial static struct TicSpecial

View file

@ -65,7 +65,9 @@ struct FPlayerColorSet
BYTE NumExtraRanges; BYTE NumExtraRanges;
ExtraRange Extra[6]; ExtraRange Extra[6];
}; };
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap; typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
typedef TMap<FName, PalEntry> PainFlashList;
class PClassPlayerPawn : public PClassActor class PClassPlayerPawn : public PClassActor
{ {
@ -76,6 +78,8 @@ public:
PClassPlayerPawn(); PClassPlayerPawn();
void EnumColorSets(TArray<int> *out); void EnumColorSets(TArray<int> *out);
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
void SetPainFlash(FName type, PalEntry color);
bool GetPainFlash(FName type, PalEntry *color) const;
FString DisplayName; // Display name (used in menus, etc.) FString DisplayName; // Display name (used in menus, etc.)
FString SoundClass; // Sound class FString SoundClass; // Sound class
@ -88,6 +92,7 @@ public:
BYTE ColorRangeStart; // Skin color range BYTE ColorRangeStart; // Skin color range
BYTE ColorRangeEnd; BYTE ColorRangeEnd;
FPlayerColorSetMap ColorSets; FPlayerColorSetMap ColorSets;
PainFlashList PainFlashes;
}; };
FString GetPrintableDisplayName(PClassPlayerPawn *cls); FString GetPrintableDisplayName(PClassPlayerPawn *cls);
@ -105,6 +110,7 @@ public:
virtual void AddInventory (AInventory *item); virtual void AddInventory (AInventory *item);
virtual void RemoveInventory (AInventory *item); virtual void RemoveInventory (AInventory *item);
virtual bool UseInventory (AInventory *item); virtual bool UseInventory (AInventory *item);
virtual void MarkPrecacheSounds () const;
virtual void PlayIdle (); virtual void PlayIdle ();
virtual void PlayRunning (); virtual void PlayRunning ();
@ -122,7 +128,7 @@ public:
void GiveDefaultInventory (); void GiveDefaultInventory ();
void PlayAttacking (); void PlayAttacking ();
void PlayAttacking2 (); void PlayAttacking2 ();
const char *GetSoundClass (); const char *GetSoundClass () const;
enum EInvulState enum EInvulState
{ {
@ -145,6 +151,8 @@ public:
// [GRB] Player class properties // [GRB] Player class properties
fixed_t JumpZ; fixed_t JumpZ;
fixed_t GruntSpeed;
fixed_t FallingScreamMinSpeed, FallingScreamMaxSpeed;
fixed_t ViewHeight; fixed_t ViewHeight;
fixed_t ForwardMove1, ForwardMove2; fixed_t ForwardMove1, ForwardMove2;
fixed_t SideMove1, SideMove2; fixed_t SideMove1, SideMove2;
@ -221,6 +229,7 @@ typedef enum
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon. CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon.
CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function. CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function.
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
} cheat_t; } cheat_t;
#define WPIECE1 1 #define WPIECE1 1
@ -452,6 +461,14 @@ inline void AActor::SetFriendPlayer(player_t *player)
} }
} }
inline bool AActor::IsNoClip2() const
{
if (player != NULL && player->mo == this)
{
return (player->cheats & CF_NOCLIP2) != 0;
}
return false;
}
#define CROUCHSPEED (FRACUNIT/12) #define CROUCHSPEED (FRACUNIT/12)

View file

@ -218,7 +218,8 @@ enum ECheatCommand
CHT_GIMMIEI, CHT_GIMMIEI,
CHT_GIMMIEJ, CHT_GIMMIEJ,
CHT_GIMMIEZ, CHT_GIMMIEZ,
CHT_BUDDHA CHT_BUDDHA,
CHT_NOCLIP2
}; };
void StartChunk (int id, BYTE **stream); void StartChunk (int id, BYTE **stream);

View file

@ -3367,7 +3367,7 @@ void FParser::SF_RadiusAttack()
if (spot && source) if (spot && source)
{ {
P_RadiusAttack(spot, source, damage, damage, NAME_None, true); P_RadiusAttack(spot, source, damage, damage, NAME_None, RADF_HURTSOURCE);
} }
} }
} }

View file

@ -342,7 +342,7 @@ void T_LoadScripts(MapData *map)
// the default translator is being used. // the default translator is being used.
// Custom translators will not be patched. // Custom translators will not be patched.
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() && if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() &&
level.maptype == MAPTYPE_DOOM && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute) level.maptype == MAPTYPE_DOOM && SimpleLineTranslations.Size() > 272 && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
{ {
FLineTrans t = SimpleLineTranslations[270]; FLineTrans t = SimpleLineTranslations[270];
SimpleLineTranslations[270] = SimpleLineTranslations[272]; SimpleLineTranslations[270] = SimpleLineTranslations[272];

View file

@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack)
target->y - FixedMul (24*FRACUNIT, finesine[an]), target->y - FixedMul (24*FRACUNIT, finesine[an]),
target->z); target->z);
P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, false); P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0);
} }
target->velz = Scale(thrust, 1000, target->Mass); target->velz = Scale(thrust, 1000, target->Mass);
return 0; return 0;

View file

@ -151,7 +151,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom)
spawntype = PClass::FindActor("FatShot"); spawntype = PClass::FindActor("FatShot");
} }
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, !(flags & MSF_DontHurt)); P_RadiusAttack (self, self->target, 128, 128, self->DamageType, (flags & MSF_DontHurt) ? 0 : RADF_HURTSOURCE);
P_CheckSplash(self, 128<<FRACBITS); P_CheckSplash(self, 128<<FRACBITS);
// Now launch mushroom cloud // Now launch mushroom cloud

View file

@ -52,7 +52,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb)
self->z += 32*FRACUNIT; self->z += 32*FRACUNIT;
self->RenderStyle = STYLE_Add; self->RenderStyle = STYLE_Add;
self->alpha = FRACUNIT; self->alpha = FRACUNIT;
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, true); P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE);
P_CheckSplash(self, 128<<FRACBITS); P_CheckSplash(self, 128<<FRACBITS);
return 0; return 0;
} }

View file

@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact)
self->z += 28*FRACUNIT; self->z += 28*FRACUNIT;
//self->velz = 3*FRACUNIT; //self->velz = 3*FRACUNIT;
} }
P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, true); P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, RADF_HURTSOURCE);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
tiny = Spawn("VolcanoTBlast", self->x, self->y, self->z, ALLOW_REPLACE); tiny = Spawn("VolcanoTBlast", self->x, self->y, self->z, ALLOW_REPLACE);

View file

@ -98,8 +98,8 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT (blastflags) { blastflags = 0; } PARAM_INT_OPT (blastflags) { blastflags = 0; }
PARAM_FIXED_OPT (strength) { strength = 255; } PARAM_INT_OPT (strength) { strength = 255; }
PARAM_FIXED_OPT (radius) { radius = 255; } PARAM_INT_OPT (radius) { radius = 255; }
PARAM_FIXED_OPT (speed) { speed = 20; } PARAM_FIXED_OPT (speed) { speed = 20; }
PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); } PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); }
PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; } PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; }

View file

@ -418,7 +418,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage)
int bobIndex; int bobIndex;
P_RadiusAttack (self, self->target, 4, 40, self->DamageType, true); P_RadiusAttack (self, self->target, 4, 40, self->DamageType, RADF_HURTSOURCE);
bobIndex = self->special2; bobIndex = self->special2;
self->z += finesine[bobIndex << BOBTOFINESHIFT] >> 1; self->z += finesine[bobIndex << BOBTOFINESHIFT] >> 1;
self->special2 = (bobIndex + 1) & 63; self->special2 = (bobIndex + 1) & 63;

View file

@ -737,7 +737,14 @@ void G_DoCompleted (void)
if (mode == FINISH_SameHub) if (mode == FINISH_SameHub)
{ // Remember the level's state for re-entry. { // Remember the level's state for re-entry.
G_SnapshotLevel (); if (!(level.flags2 & LEVEL2_FORGETSTATE))
{
G_SnapshotLevel ();
}
else
{ // Make sure we don't have a snapshot lying around from before.
level.info->ClearSnapshot();
}
} }
else else
{ // Forget the states of all existing levels. { // Forget the states of all existing levels.

View file

@ -36,8 +36,8 @@
#include "doomtype.h" #include "doomtype.h"
#include "doomdef.h" #include "doomdef.h"
//#include "autosegs.h"
#include "sc_man.h" #include "sc_man.h"
#include "s_sound.h"
struct level_info_t; struct level_info_t;
struct cluster_info_t; struct cluster_info_t;
@ -179,7 +179,7 @@ enum ELevelFlags
LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1 LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1
LEVEL2_MUSICDEFINED = 0x00000080, // a marker to disable the $map command in SNDINFO for this map /* = 0x00000080, */
LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100, LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100,
LEVEL2_CLIPMIDTEX = 0x00000200, LEVEL2_CLIPMIDTEX = 0x00000200,
LEVEL2_WRAPMIDTEX = 0x00000400, LEVEL2_WRAPMIDTEX = 0x00000400,
@ -211,6 +211,7 @@ enum ELevelFlags
LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected
LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit. LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit.
LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept
LEVEL2_FORGETSTATE = 0x80000000, // forget this map's state in a hub
}; };
@ -325,6 +326,8 @@ struct level_info_t
TArray<FSpecialAction> specialactions; TArray<FSpecialAction> specialactions;
TArray<FSoundID> PrecacheSounds;
level_info_t() level_info_t()
{ {
Reset(); Reset();

View file

@ -61,6 +61,8 @@ static cluster_info_t TheDefaultClusterInfo;
TArray<FEpisode> AllEpisodes; TArray<FEpisode> AllEpisodes;
extern TMap<int, FString> HexenMusic;
//========================================================================== //==========================================================================
// //
// //
@ -269,6 +271,7 @@ void level_info_t::Reset()
teamdamage = 0.f; teamdamage = 0.f;
specialactions.Clear(); specialactions.Clear();
DefaultEnvironment = 0; DefaultEnvironment = 0;
PrecacheSounds.Clear();
} }
@ -917,8 +920,6 @@ DEFINE_MAP_OPTION(music, true)
{ {
parse.ParseAssign(); parse.ParseAssign();
parse.ParseMusic(info->Music, info->musicorder); parse.ParseMusic(info->Music, info->musicorder);
// Flag the level so that the $MAP command doesn't override this.
info->flags2 |= LEVEL2_MUSICDEFINED;
} }
DEFINE_MAP_OPTION(intermusic, true) DEFINE_MAP_OPTION(intermusic, true)
@ -1029,7 +1030,7 @@ DEFINE_MAP_OPTION(specialaction, true)
sa->Action = P_FindLineSpecial(parse.sc.String, &min_arg, &max_arg); sa->Action = P_FindLineSpecial(parse.sc.String, &min_arg, &max_arg);
if (sa->Action == 0 || min_arg < 0) if (sa->Action == 0 || min_arg < 0)
{ {
parse.sc.ScriptError("Unknown specialaction '%s'"); parse.sc.ScriptError("Unknown specialaction '%s'", parse.sc.String);
} }
int j = 0; int j = 0;
while (j < 5 && parse.sc.CheckString(",")) while (j < 5 && parse.sc.CheckString(","))
@ -1040,6 +1041,25 @@ DEFINE_MAP_OPTION(specialaction, true)
if (parse.format_type == parse.FMT_Old) parse.sc.SetCMode(false); if (parse.format_type == parse.FMT_Old) parse.sc.SetCMode(false);
} }
DEFINE_MAP_OPTION(PrecacheSounds, true)
{
parse.ParseAssign();
do
{
parse.sc.MustGetString();
FSoundID snd = parse.sc.String;
if (snd == 0)
{
parse.sc.ScriptMessage("Unknown sound \"%s\"", parse.sc.String);
}
else
{
info->PrecacheSounds.Push(snd);
}
} while (parse.sc.CheckString(","));
}
DEFINE_MAP_OPTION(redirect, true) DEFINE_MAP_OPTION(redirect, true)
{ {
parse.ParseAssign(); parse.ParseAssign();
@ -1244,6 +1264,8 @@ MapFlagHandlers[] =
{ "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 }, { "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 },
{ "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 0 }, { "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 0 },
{ "noautosavehint", MITYPE_SETFLAG2, LEVEL2_NOAUTOSAVEHINT, 0 }, { "noautosavehint", MITYPE_SETFLAG2, LEVEL2_NOAUTOSAVEHINT, 0 },
{ "forgetstate", MITYPE_SETFLAG2, LEVEL2_FORGETSTATE, 0 },
{ "rememberstate", MITYPE_CLRFLAG2, LEVEL2_FORGETSTATE, 0 },
{ "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 }, { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 },
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
{ "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 }, { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 },
@ -1516,6 +1538,14 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo)
// to teleport to maps with standard names without needing a levelnum. // to teleport to maps with standard names without needing a levelnum.
levelinfo->levelnum = GetDefaultLevelNum(levelinfo->mapname); levelinfo->levelnum = GetDefaultLevelNum(levelinfo->mapname);
// Does this map have a song defined via SNDINFO's $map command?
// Set that as this map's default music if it does.
FString *song;
if ((song = HexenMusic.CheckKey(levelinfo->levelnum)) != NULL)
{
levelinfo->Music = *song;
}
return levelinfo; return levelinfo;
} }
@ -1810,7 +1840,6 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
} }
} }
//========================================================================== //==========================================================================
// //
// //

View file

@ -47,12 +47,12 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
} }
if (p->morphTics) if (p->morphTics)
{ // Player is already a beast { // Player is already a beast
if ((p->mo->GetClass() == spawntype) if ((p->mo->GetClass() == spawntype)
&& (p->mo->PlayerFlags & PPF_CANSUPERMORPH) && (p->mo->PlayerFlags & PPF_CANSUPERMORPH)
&& (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE))
&& (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL)) && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL))
{ // Make a super chicken { // Make a super chicken
p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
} }
return false; return false;
} }

View file

@ -505,6 +505,18 @@ void AInventory::Serialize (FArchive &arc)
arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags << Icon << PickupSound << SpawnPointClass; arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags << Icon << PickupSound << SpawnPointClass;
} }
//===========================================================================
//
// AInventory :: MarkPrecacheSounds
//
//===========================================================================
void AInventory::MarkPrecacheSounds() const
{
Super::MarkPrecacheSounds();
PickupSound.MarkUsed();
}
//=========================================================================== //===========================================================================
// //
// AInventory :: SpecialDropAction // AInventory :: SpecialDropAction
@ -532,6 +544,7 @@ bool AInventory::SpecialDropAction (AActor *dropper)
bool AInventory::ShouldRespawn () bool AInventory::ShouldRespawn ()
{ {
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags & DF_RESPAWN_SUPER)) return false; if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags & DF_RESPAWN_SUPER)) return false;
if (ItemFlags & IF_NEVERRESPAWN) return false;
return !!(dmflags & DF_ITEMS_RESPAWN); return !!(dmflags & DF_ITEMS_RESPAWN);
} }

View file

@ -123,6 +123,7 @@ enum
IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE
IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels
IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
}; };
@ -147,6 +148,7 @@ public:
virtual void Touch (AActor *toucher); virtual void Touch (AActor *toucher);
virtual void Serialize (FArchive &arc); virtual void Serialize (FArchive &arc);
virtual void MarkPrecacheSounds() const;
virtual void BeginPlay (); virtual void BeginPlay ();
virtual void Destroy (); virtual void Destroy ();
virtual void Tick (); virtual void Tick ();
@ -296,6 +298,7 @@ public:
bool bAltFire; // Set when this weapon's alternate fire is used. bool bAltFire; // Set when this weapon's alternate fire is used.
virtual void MarkPrecacheSounds() const;
virtual void Serialize (FArchive &arc); virtual void Serialize (FArchive &arc);
virtual bool ShouldStay (); virtual bool ShouldStay ();
virtual void AttachToOwner (AActor *other); virtual void AttachToOwner (AActor *other);

View file

@ -105,6 +105,7 @@ public:
void PostBeginPlay (); void PostBeginPlay ();
void Activate (AActor *activator); void Activate (AActor *activator);
void Deactivate (AActor *activator); void Deactivate (AActor *activator);
void MarkPrecacheSounds () const;
}; };
IMPLEMENT_CLASS (ASoundSequence) IMPLEMENT_CLASS (ASoundSequence)
@ -154,6 +155,18 @@ void ASoundSequence::PostBeginPlay ()
} }
} }
//==========================================================================
//
// ASoundSequence :: MarkPrecacheSounds
//
//==========================================================================
void ASoundSequence::MarkPrecacheSounds() const
{
Super::MarkPrecacheSounds();
SN_MarkPrecacheSounds(args[0], SEQ_ENVIRONMENT);
}
//========================================================================== //==========================================================================
// //
// ASoundSequence :: Activate // ASoundSequence :: Activate
@ -175,4 +188,3 @@ void ASoundSequence::Deactivate (AActor *activator)
{ {
SN_StopSequence (this); SN_StopSequence (this);
} }

View file

@ -85,6 +85,19 @@ void AWeapon::Serialize (FArchive &arc)
<< Crosshair; << Crosshair;
} }
//===========================================================================
//
// AWeapon :: MarkPrecacheSounds
//
//===========================================================================
void AWeapon::MarkPrecacheSounds() const
{
Super::MarkPrecacheSounds();
UpSound.MarkUsed();
ReadySound.MarkUsed();
}
//=========================================================================== //===========================================================================
// //
// AWeapon :: TryPickup // AWeapon :: TryPickup
@ -732,6 +745,7 @@ bool AWeaponGiver::TryPickup(AActor *&toucher)
if (weap != NULL) if (weap != NULL)
{ {
weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only.
weap->flags = (weap->flags & ~MF_DROPPED) | (this->flags & MF_DROPPED);
if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1; if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1;
if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2;
weap->BecomeItem(); weap->BecomeItem();
@ -741,7 +755,11 @@ bool AWeaponGiver::TryPickup(AActor *&toucher)
weap = barrier_cast<AWeapon*>(master); weap = barrier_cast<AWeapon*>(master);
bool res = weap->CallTryPickup(toucher); bool res = weap->CallTryPickup(toucher);
if (res) GoAwayAndDie(); if (res)
{
GoAwayAndDie();
master = NULL;
}
return res; return res;
} }
} }

View file

@ -140,6 +140,9 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h
State = 0; State = 0;
SourceText = copystring (text); SourceText = copystring (text);
Font = font; Font = font;
VisibilityFlags = 0;
Style = STYLE_Translucent;
Alpha = FRACUNIT;
ResetText (SourceText); ResetText (SourceText);
} }
@ -184,6 +187,23 @@ void DHUDMessage::Serialize (FArchive &arc)
Lines = NULL; Lines = NULL;
ResetText (SourceText); ResetText (SourceText);
} }
if (SaveVersion < 3821)
{
VisibilityFlags = 0;
}
else
{
arc << VisibilityFlags;
}
if (SaveVersion < 3824)
{
Style = STYLE_Translucent;
Alpha = FRACUNIT;
}
else
{
arc << Style << Alpha;
}
} }
//============================================================================ //============================================================================
@ -262,7 +282,7 @@ bool DHUDMessage::Tick ()
// //
//============================================================================ //============================================================================
void DHUDMessage::Draw (int bottom) void DHUDMessage::Draw (int bottom, int visibility)
{ {
int xscale, yscale; int xscale, yscale;
int x, y; int x, y;
@ -271,6 +291,12 @@ void DHUDMessage::Draw (int bottom)
bool clean = false; bool clean = false;
int hudheight; int hudheight;
// If any of the visibility flags match, do NOT draw this message.
if (VisibilityFlags & visibility)
{
return;
}
DrawSetup (); DrawSetup ();
int screen_width = SCREENWIDTH; int screen_width = SCREENWIDTH;
@ -395,6 +421,8 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
{ {
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_CleanNoMove, clean, DTA_CleanNoMove, clean,
DTA_Alpha, Alpha,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
else else
@ -402,6 +430,8 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualWidth, SCREENWIDTH/2,
DTA_VirtualHeight, SCREENHEIGHT/2, DTA_VirtualHeight, SCREENHEIGHT/2,
DTA_Alpha, Alpha,
DTA_RenderStyle, Style,
DTA_KeepRatio, true, DTA_KeepRatio, true,
TAG_DONE); TAG_DONE);
} }
@ -411,6 +441,8 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, HUDWidth, DTA_VirtualWidth, HUDWidth,
DTA_VirtualHeight, hudheight, DTA_VirtualHeight, hudheight,
DTA_Alpha, Alpha,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
} }
@ -482,6 +514,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
else else
{ {
fixed_t trans = -(Tics - FadeOutTics) * FRACUNIT / FadeOutTics; fixed_t trans = -(Tics - FadeOutTics) * FRACUNIT / FadeOutTics;
trans = FixedMul(trans, Alpha);
if (hudheight == 0) if (hudheight == 0)
{ {
if (con_scaletext <= 1) if (con_scaletext <= 1)
@ -489,6 +522,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_CleanNoMove, clean, DTA_CleanNoMove, clean,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
else else
@ -497,6 +531,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualWidth, SCREENWIDTH/2,
DTA_VirtualHeight, SCREENHEIGHT/2, DTA_VirtualHeight, SCREENHEIGHT/2,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
DTA_KeepRatio, true, DTA_KeepRatio, true,
TAG_DONE); TAG_DONE);
} }
@ -507,6 +542,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
DTA_VirtualWidth, HUDWidth, DTA_VirtualWidth, HUDWidth,
DTA_VirtualHeight, hudheight, DTA_VirtualHeight, hudheight,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
BorderNeedRefresh = screen->GetPageCount (); BorderNeedRefresh = screen->GetPageCount ();
@ -575,6 +611,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
if (State == 0) if (State == 0)
{ {
fixed_t trans = Tics * FRACUNIT / FadeInTics; fixed_t trans = Tics * FRACUNIT / FadeInTics;
trans = FixedMul(trans, Alpha);
if (hudheight == 0) if (hudheight == 0)
{ {
if (con_scaletext <= 1) if (con_scaletext <= 1)
@ -582,6 +619,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_CleanNoMove, clean, DTA_CleanNoMove, clean,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
else else
@ -590,6 +628,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualWidth, SCREENWIDTH/2,
DTA_VirtualHeight, SCREENHEIGHT/2, DTA_VirtualHeight, SCREENHEIGHT/2,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
DTA_KeepRatio, true, DTA_KeepRatio, true,
TAG_DONE); TAG_DONE);
} }
@ -600,6 +639,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
DTA_VirtualWidth, HUDWidth, DTA_VirtualWidth, HUDWidth,
DTA_VirtualHeight, hudheight, DTA_VirtualHeight, hudheight,
DTA_Alpha, trans, DTA_Alpha, trans,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
BorderNeedRefresh = screen->GetPageCount (); BorderNeedRefresh = screen->GetPageCount ();
@ -753,6 +793,8 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_CleanNoMove, clean, DTA_CleanNoMove, clean,
DTA_TextLen, LineVisible, DTA_TextLen, LineVisible,
DTA_Alpha, Alpha,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
else else
@ -762,6 +804,8 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
DTA_VirtualHeight, SCREENHEIGHT/2, DTA_VirtualHeight, SCREENHEIGHT/2,
DTA_KeepRatio, true, DTA_KeepRatio, true,
DTA_TextLen, LineVisible, DTA_TextLen, LineVisible,
DTA_Alpha, Alpha,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
} }
@ -770,7 +814,9 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, HUDWidth, DTA_VirtualWidth, HUDWidth,
DTA_VirtualHeight, hudheight, DTA_VirtualHeight, hudheight,
DTA_Alpha, Alpha,
DTA_TextLen, LineVisible, DTA_TextLen, LineVisible,
DTA_RenderStyle, Style,
TAG_DONE); TAG_DONE);
} }
} }

View file

@ -66,13 +66,26 @@ public:
virtual void Serialize (FArchive &arc); virtual void Serialize (FArchive &arc);
void Draw (int bottom); void Draw (int bottom, int visibility);
virtual void ResetText (const char *text); virtual void ResetText (const char *text);
virtual void DrawSetup (); virtual void DrawSetup ();
virtual void DoDraw (int linenum, int x, int y, bool clean, int hudheight); virtual void DoDraw (int linenum, int x, int y, bool clean, int hudheight);
virtual bool Tick (); // Returns true to indicate time for removal virtual bool Tick (); // Returns true to indicate time for removal
virtual void ScreenSizeChanged (); virtual void ScreenSizeChanged ();
void SetVisibility(int vis)
{
VisibilityFlags = vis;
}
void SetRenderStyle(ERenderStyle style)
{
Style = style;
}
void SetAlpha(fixed_t alpha)
{
Alpha = alpha;
}
protected: protected:
FBrokenLines *Lines; FBrokenLines *Lines;
int Width, Height, NumLines; int Width, Height, NumLines;
@ -81,9 +94,12 @@ protected:
int HoldTics; int HoldTics;
int Tics; int Tics;
int State; int State;
int VisibilityFlags;
int HUDWidth, HUDHeight; int HUDWidth, HUDHeight;
EColorRange TextColor; EColorRange TextColor;
FFont *Font; FFont *Font;
FRenderStyle Style;
fixed_t Alpha;
DHUDMessage () : SourceText(NULL) {} DHUDMessage () : SourceText(NULL) {}
@ -95,6 +111,14 @@ private:
friend class DBaseStatusBar; friend class DBaseStatusBar;
}; };
// HUD message visibility flags
enum
{
HUDMSG_NotWith3DView = 1,
HUDMSG_NotWithFullMap = 2,
HUDMSG_NotWithOverlayMap = 4,
};
// HUD Message; appear instantly, then fade out type ------------------------ // HUD Message; appear instantly, then fade out type ------------------------
class DHUDMessageFadeOut : public DHUDMessage class DHUDMessageFadeOut : public DHUDMessage
@ -242,6 +266,16 @@ int FindMugShotStateIndex(FName state);
class FTexture; class FTexture;
class AAmmo; class AAmmo;
enum
{
HUDMSGLayer_OverHUD,
HUDMSGLayer_UnderHUD,
HUDMSGLayer_OverMap,
NUM_HUDMSGLAYERS,
HUDMSGLayer_Default = HUDMSGLayer_OverHUD,
};
class DBaseStatusBar : public DObject class DBaseStatusBar : public DObject
{ {
DECLARE_CLASS (DBaseStatusBar, DObject) DECLARE_CLASS (DBaseStatusBar, DObject)
@ -281,11 +315,10 @@ public:
void SetScaled (bool scale, bool force=false); void SetScaled (bool scale, bool force=false);
void AttachMessage (DHUDMessage *msg, uint32 id=0); void AttachMessage (DHUDMessage *msg, uint32 id=0, int layer=HUDMSGLayer_Default);
DHUDMessage *DetachMessage (DHUDMessage *msg); DHUDMessage *DetachMessage (DHUDMessage *msg);
DHUDMessage *DetachMessage (uint32 id); DHUDMessage *DetachMessage (uint32 id);
void DetachAllMessages (); void DetachAllMessages ();
bool CheckMessage (DHUDMessage *msg);
void ShowPlayerName (); void ShowPlayerName ();
fixed_t GetDisplacement () { return Displacement; } fixed_t GetDisplacement () { return Displacement; }
int GetPlayer (); int GetPlayer ();
@ -296,6 +329,7 @@ public:
virtual void Tick (); virtual void Tick ();
virtual void Draw (EHudState state); virtual void Draw (EHudState state);
void DrawBottomStuff (EHudState state);
void DrawTopStuff (EHudState state); void DrawTopStuff (EHudState state);
virtual void FlashItem (const PClass *itemtype); virtual void FlashItem (const PClass *itemtype);
virtual void AttachToPlayer (player_t *player); virtual void AttachToPlayer (player_t *player);
@ -343,6 +377,7 @@ public:
bool Scaled; bool Scaled;
bool Centering; bool Centering;
bool FixedOrigin; bool FixedOrigin;
bool CompleteBorder;
fixed_t CrosshairSize; fixed_t CrosshairSize;
fixed_t Displacement; fixed_t Displacement;
@ -363,10 +398,10 @@ public:
private: private:
DBaseStatusBar() {} DBaseStatusBar() {}
bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const; bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const;
void DrawMessages (int bottom); void DrawMessages (int layer, int bottom);
void DrawConsistancy () const; void DrawConsistancy () const;
TObjPtr<DHUDMessage> Messages; TObjPtr<DHUDMessage> Messages[NUM_HUDMSGLAYERS];
bool ShowLog; bool ShowLog;
}; };

View file

@ -149,6 +149,8 @@ class SBarInfoCommand
virtual void Reset() {} virtual void Reset() {}
virtual void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) {} virtual void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) {}
SBarInfo *GetScript() { return script; }
protected: protected:
void GetCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) void GetCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y)
{ {
@ -798,6 +800,8 @@ void SBarInfo::Init()
spacingAlignment = ALIGN_CENTER; spacingAlignment = ALIGN_CENTER;
resW = 320; resW = 320;
resH = 200; resH = 200;
cleanX = -1;
cleanY = -1;
for(unsigned int i = 0;i < NUMHUDS;i++) for(unsigned int i = 0;i < NUMHUDS;i++)
huds[i] = new SBarInfoMainBlock(this); huds[i] = new SBarInfoMainBlock(this);
@ -978,6 +982,8 @@ public:
} }
invBarOffset = script->Images.Size(); invBarOffset = script->Images.Size();
Images.Init(&patchnames[0], patchnames.Size()); Images.Init(&patchnames[0], patchnames.Size());
CompleteBorder = script->completeBorder;
} }
~DSBarInfo () ~DSBarInfo ()
@ -985,19 +991,22 @@ public:
Images.Uninit(); Images.Uninit();
} }
void ScreenSizeChanged()
{
Super::ScreenSizeChanged();
V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY);
}
void Draw (EHudState state) void Draw (EHudState state)
{ {
DBaseStatusBar::Draw(state); DBaseStatusBar::Draw(state);
if (script->cleanX <= 0)
{ // Calculate cleanX and cleanY
ScreenSizeChanged();
}
int hud = STBAR_NORMAL; int hud = STBAR_NORMAL;
if(state == HUD_StatusBar) if(state == HUD_StatusBar)
{ {
if(script->completeBorder) //Fill the statusbar with the border before we draw.
{
FTexture *b = TexMan[gameinfo.border->b];
V_DrawBorder(viewwindowx, viewwindowy + viewheight + b->GetHeight(), viewwindowx + viewwidth, SCREENHEIGHT);
if(screenblocks == 10)
screen->FlatFill(viewwindowx, viewwindowy + viewheight, viewwindowx + viewwidth, viewwindowy + viewheight + b->GetHeight(), b, true);
}
if(script->automapbar && automapactive) if(script->automapbar && automapactive)
{ {
hud = STBAR_AUTOMAP; hud = STBAR_AUTOMAP;
@ -1250,8 +1259,8 @@ public:
{ {
double rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; double rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX;
double xScale = !hud_scale ? 1.0 : (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; double xScale = !hud_scale ? 1 : script->cleanX;
double yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH; double yScale = !hud_scale ? 1 : script->cleanY;
adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale); adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale);
@ -1283,34 +1292,6 @@ public:
rcy = cy == 0 ? 0 : ry+(((double) cy/FRACUNIT)*yScale); rcy = cy == 0 ? 0 : ry+(((double) cy/FRACUNIT)*yScale);
rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale); rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale);
rcb = cb == 0 ? INT_MAX : ry+h-(((double) cb/FRACUNIT)*yScale); rcb = cb == 0 ? INT_MAX : ry+h-(((double) cb/FRACUNIT)*yScale);
// Fix the clipping for fullscreenoffsets.
/*if(ry < 0)
{
if(rcy != 0)
rcy = hud_scale ? SCREENHEIGHT + (int) (rcy*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcy;
if(rcb != INT_MAX)
rcb = hud_scale ? SCREENHEIGHT + (int) (rcb*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcb;
}
else if(hud_scale)
{
rcy *= (int) (CleanYfac*200.0/script->resH);
if(rcb != INT_MAX)
rcb *= (int) (CleanYfac*200.0/script->resH);
}
if(rx < 0)
{
if(rcx != 0)
rcx = hud_scale ? SCREENWIDTH + (int) (rcx*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcx;
if(rcr != INT_MAX)
rcr = hud_scale ? SCREENWIDTH + (int) (rcr*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcr;
}
else if(hud_scale)
{
rcx *= (int) (CleanXfac*320.0/script->resW);
if(rcr != INT_MAX)
rcr *= (int) (CleanXfac*320.0/script->resW);
}*/
} }
if(clearDontDraw) if(clearDontDraw)
@ -1370,8 +1351,8 @@ public:
{ {
if(hud_scale) if(hud_scale)
{ {
xScale = (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; xScale = script->cleanX;
yScale = (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENWIDTH/(double) script->resW; yScale = script->cleanY;
} }
adjustRelCenter(x.RelCenter(), y.RelCenter(), *x, *y, ax, ay, xScale, yScale); adjustRelCenter(x.RelCenter(), y.RelCenter(), *x, *y, ax, ay, xScale, yScale);
} }

View file

@ -108,6 +108,8 @@ struct SBarInfo
FMugShot MugShot; FMugShot MugShot;
int resW; int resW;
int resH; int resH;
int cleanX;
int cleanY;
int GetGameType() { return gameType; } int GetGameType() { return gameType; }
void ParseSBarInfo(int lump); void ParseSBarInfo(int lump);

View file

@ -61,7 +61,9 @@
#define POWERUPICONSIZE 32 #define POWERUPICONSIZE 32
IMPLEMENT_POINTY_CLASS(DBaseStatusBar) IMPLEMENT_POINTY_CLASS(DBaseStatusBar)
DECLARE_POINTER(Messages) DECLARE_POINTER(Messages[0])
DECLARE_POINTER(Messages[1])
DECLARE_POINTER(Messages[2])
END_POINTERS END_POINTERS
EXTERN_CVAR (Bool, am_showmonsters) EXTERN_CVAR (Bool, am_showmonsters)
@ -70,7 +72,6 @@ EXTERN_CVAR (Bool, am_showitems)
EXTERN_CVAR (Bool, am_showtime) EXTERN_CVAR (Bool, am_showtime)
EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, am_showtotaltime)
EXTERN_CVAR (Bool, noisedebug) EXTERN_CVAR (Bool, noisedebug)
EXTERN_CVAR (Bool, hud_scale)
EXTERN_CVAR (Int, con_scaletext) EXTERN_CVAR (Int, con_scaletext)
DBaseStatusBar *StatusBar; DBaseStatusBar *StatusBar;
@ -216,11 +217,12 @@ void ST_Clear()
DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres)
{ {
CompleteBorder = false;
Centering = false; Centering = false;
FixedOrigin = false; FixedOrigin = false;
CrosshairSize = FRACUNIT; CrosshairSize = FRACUNIT;
RelTop = reltop; RelTop = reltop;
Messages = NULL; memset(Messages, 0, sizeof(Messages));
Displacement = 0; Displacement = 0;
CPlayer = NULL; CPlayer = NULL;
ShowLog = false; ShowLog = false;
@ -238,16 +240,17 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres)
void DBaseStatusBar::Destroy () void DBaseStatusBar::Destroy ()
{ {
DHUDMessage *msg; for (int i = 0; i < countof(Messages); ++i)
msg = Messages;
while (msg)
{ {
DHUDMessage *next = msg->Next; DHUDMessage *msg = Messages[i];
msg->Destroy(); while (msg)
msg = next; {
DHUDMessage *next = msg->Next;
msg->Destroy();
msg = next;
}
Messages[i] = NULL;
} }
Messages = NULL;
Super::Destroy(); Super::Destroy();
} }
@ -339,32 +342,35 @@ void DBaseStatusBar::MultiplayerChanged ()
void DBaseStatusBar::Tick () void DBaseStatusBar::Tick ()
{ {
DHUDMessage *msg = Messages; for (int i = 0; i < countof(Messages); ++i)
DHUDMessage **prev = &Messages;
while (msg)
{ {
DHUDMessage *next = msg->Next; DHUDMessage *msg = Messages[i];
DHUDMessage **prev = &Messages[i];
if (msg->Tick ()) while (msg)
{ {
*prev = next; DHUDMessage *next = msg->Next;
msg->Destroy();
}
else
{
prev = &msg->Next;
}
msg = next;
}
// If the crosshair has been enlarged, shrink it. if (msg->Tick ())
if (CrosshairSize > FRACUNIT) {
{ *prev = next;
CrosshairSize -= XHAIRSHRINKSIZE; msg->Destroy();
if (CrosshairSize < FRACUNIT) }
else
{
prev = &msg->Next;
}
msg = next;
}
// If the crosshair has been enlarged, shrink it.
if (CrosshairSize > FRACUNIT)
{ {
CrosshairSize = FRACUNIT; CrosshairSize -= XHAIRSHRINKSIZE;
if (CrosshairSize < FRACUNIT)
{
CrosshairSize = FRACUNIT;
}
} }
} }
} }
@ -375,7 +381,7 @@ void DBaseStatusBar::Tick ()
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id) void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id, int layer)
{ {
DHUDMessage *old = NULL; DHUDMessage *old = NULL;
DHUDMessage **prev; DHUDMessage **prev;
@ -387,7 +393,13 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id)
old->Destroy(); old->Destroy();
} }
prev = &Messages; // Merge unknown layers into the default layer.
if ((size_t)layer >= countof(Messages))
{
layer = HUDMSGLayer_Default;
}
prev = &Messages[layer];
// The ID serves as a priority, where lower numbers appear in front of // The ID serves as a priority, where lower numbers appear in front of
// higher numbers. (i.e. The list is sorted in descending order, since // higher numbers. (i.e. The list is sorted in descending order, since
@ -412,48 +424,56 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id)
DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg)
{ {
DHUDMessage *probe = Messages; for (int i = 0; i < countof(Messages); ++i)
DHUDMessage **prev = &Messages; {
DHUDMessage *probe = Messages[i];
DHUDMessage **prev = &Messages[i];
while (probe && probe != msg) while (probe && probe != msg)
{
prev = &probe->Next;
probe = probe->Next;
}
if (probe != NULL)
{
*prev = probe->Next;
probe->Next = NULL;
// Redraw the status bar in case it was covered
if (screen != NULL)
{ {
SB_state = screen->GetPageCount(); prev = &probe->Next;
probe = probe->Next;
}
if (probe != NULL)
{
*prev = probe->Next;
probe->Next = NULL;
// Redraw the status bar in case it was covered
if (screen != NULL)
{
SB_state = screen->GetPageCount();
}
return probe;
} }
} }
return probe; return NULL;
} }
DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id)
{ {
DHUDMessage *probe = Messages; for (int i = 0; i < countof(Messages); ++i)
DHUDMessage **prev = &Messages; {
DHUDMessage *probe = Messages[i];
DHUDMessage **prev = &Messages[i];
while (probe && probe->SBarID != id) while (probe && probe->SBarID != id)
{
prev = &probe->Next;
probe = probe->Next;
}
if (probe != NULL)
{
*prev = probe->Next;
probe->Next = NULL;
// Redraw the status bar in case it was covered
if (screen != NULL)
{ {
SB_state = screen->GetPageCount(); prev = &probe->Next;
probe = probe->Next;
}
if (probe != NULL)
{
*prev = probe->Next;
probe->Next = NULL;
// Redraw the status bar in case it was covered
if (screen != NULL)
{
SB_state = screen->GetPageCount();
}
return probe;
} }
} }
return probe; return NULL;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -464,31 +484,18 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id)
void DBaseStatusBar::DetachAllMessages () void DBaseStatusBar::DetachAllMessages ()
{ {
DHUDMessage *probe = Messages; for (int i = 0; i < countof(Messages); ++i)
Messages = NULL;
while (probe != NULL)
{ {
DHUDMessage *next = probe->Next; DHUDMessage *probe = Messages[i];
probe->Destroy();
probe = next;
}
}
//--------------------------------------------------------------------------- Messages[i] = NULL;
// while (probe != NULL)
// PROC CheckMessage {
// DHUDMessage *next = probe->Next;
//--------------------------------------------------------------------------- probe->Destroy();
probe = next;
bool DBaseStatusBar::CheckMessage (DHUDMessage *msg) }
{
DHUDMessage *probe = Messages;
while (probe && probe != msg)
{
probe = probe->Next;
} }
return (probe == msg);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -1037,27 +1044,46 @@ void DBaseStatusBar::RefreshBackground () const
{ {
int x, x2, y, ratio; int x, x2, y, ratio;
if (SCREENWIDTH > 320) ratio = CheckRatio (SCREENWIDTH, SCREENHEIGHT);
x = (!(ratio & 3) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2);
y = x == ST_X && x > 0 ? ST_Y : ::ST_Y;
if(!CompleteBorder)
{ {
ratio = CheckRatio (SCREENWIDTH, SCREENHEIGHT); if(y < SCREENHEIGHT)
x = (!(ratio & 3) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2); {
if (x > 0) V_DrawBorder (x+1, y, SCREENWIDTH, y+1);
V_DrawBorder (x+1, SCREENHEIGHT-1, SCREENWIDTH, SCREENHEIGHT);
}
}
else
{
x = SCREENWIDTH;
}
if (x > 0)
{
if(!CompleteBorder)
{ {
y = x == ST_X ? ST_Y : ::ST_Y;
x2 = !(ratio & 3) || !Scaled ? ST_X+HorizontalResolution : x2 = !(ratio & 3) || !Scaled ? ST_X+HorizontalResolution :
SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2); SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2);
V_DrawBorder (0, y, x, SCREENHEIGHT); }
V_DrawBorder (x2, y, SCREENWIDTH, SCREENHEIGHT); else
{
x2 = SCREENWIDTH;
}
if (setblocks >= 10) V_DrawBorder (0, y, x+1, SCREENHEIGHT);
{ V_DrawBorder (x2-1, y, SCREENWIDTH, SCREENHEIGHT);
const gameborder_t *border = gameinfo.border;
FTexture *p;
p = TexMan[border->b]; if (setblocks >= 10)
screen->FlatFill(0, y, x, y + p->GetHeight(), p, true); {
screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetHeight(), p, true); const gameborder_t *border = gameinfo.border;
} FTexture *p;
p = TexMan[border->b];
screen->FlatFill(0, y, x, y + p->GetHeight(), p, true);
screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetHeight(), p, true);
} }
} }
} }
@ -1172,13 +1198,23 @@ void DBaseStatusBar::FlashCrosshair ()
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void DBaseStatusBar::DrawMessages (int bottom) void DBaseStatusBar::DrawMessages (int layer, int bottom)
{ {
DHUDMessage *msg = Messages; DHUDMessage *msg = Messages[layer];
int visibility = 0;
if (viewactive)
{
visibility |= HUDMSG_NotWith3DView;
}
if (automapactive)
{
visibility |= viewactive ? HUDMSG_NotWithOverlayMap : HUDMSG_NotWithFullMap;
}
while (msg) while (msg)
{ {
DHUDMessage *next = msg->Next; DHUDMessage *next = msg->Next;
msg->Draw (bottom); msg->Draw (bottom, visibility);
msg = next; msg = next;
} }
} }
@ -1426,6 +1462,17 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b
{ {
} }
//---------------------------------------------------------------------------
//
// DrawBottomStuff
//
//---------------------------------------------------------------------------
void DBaseStatusBar::DrawBottomStuff (EHudState state)
{
DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// DrawTopStuff // DrawTopStuff
@ -1443,16 +1490,11 @@ void DBaseStatusBar::DrawTopStuff (EHudState state)
} }
DrawPowerups (); DrawPowerups ();
if (automapactive && !viewactive)
if (state == HUD_StatusBar)
{ {
DrawMessages (::ST_Y); DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
} }
else DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
{
DrawMessages (SCREENHEIGHT);
}
DrawConsistancy (); DrawConsistancy ();
if (ShowLog && MustDrawLog(state)) DrawLog (); if (ShowLog && MustDrawLog(state)) DrawLog ();
@ -1578,7 +1620,18 @@ void DBaseStatusBar::ReceivedWeapon (AWeapon *weapon)
void DBaseStatusBar::Serialize (FArchive &arc) void DBaseStatusBar::Serialize (FArchive &arc)
{ {
arc << Messages; if (SaveVersion < 3821)
{
memset(Messages, 0, sizeof(Messages));
arc << Messages[HUDMSGLayer_Default];
}
else
{
for (int i = 0; i < countof(Messages); ++i)
{
arc << Messages[i];
}
}
} }
void DBaseStatusBar::ScreenSizeChanged () void DBaseStatusBar::ScreenSizeChanged ()
@ -1586,11 +1639,14 @@ void DBaseStatusBar::ScreenSizeChanged ()
st_scale.Callback (); st_scale.Callback ();
SB_state = screen->GetPageCount (); SB_state = screen->GetPageCount ();
DHUDMessage *message = Messages; for (int i = 0; i < countof(Messages); ++i)
while (message != NULL)
{ {
message->ScreenSizeChanged (); DHUDMessage *message = Messages[i];
message = message->Next; while (message != NULL)
{
message->ScreenSizeChanged ();
message = message->Next;
}
} }
} }

View file

@ -89,6 +89,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire)
self->target->health <= 0 || self->target->health <= 0 ||
!P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ||
P_HitFriend(self) || P_HitFriend(self) ||
(self->MissileState == NULL && !self->CheckMeleeRange()) ||
pr_sentinelrefire() < 40) pr_sentinelrefire() < 40)
{ {
self->SetState (self->SeeState); self->SetState (self->SeeState);

View file

@ -721,7 +721,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DropFire)
AActor *drop = Spawn("FireDroplet", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); AActor *drop = Spawn("FireDroplet", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE);
drop->velz = -FRACUNIT; drop->velz = -FRACUNIT;
P_RadiusAttack (self, self, 64, 64, NAME_Fire, false); P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0);
return 0; return 0;
} }

View file

@ -605,7 +605,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BurnArea)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, true); P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE);
return 0; return 0;
} }

View file

@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode512)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
P_RadiusAttack (self, self->target, 512, 512, NAME_None, true); P_RadiusAttack (self, self->target, 512, 512, NAME_None, RADF_HURTSOURCE);
if (self->target != NULL && self->target->player != NULL) if (self->target != NULL && self->target->player != NULL)
{ {
self->target->player->extralight = 5; self->target->player->extralight = 5;

View file

@ -47,6 +47,7 @@
#include "v_palette.h" #include "v_palette.h"
#include "d_player.h" #include "d_player.h"
#include "hu_stuff.h" #include "hu_stuff.h"
#include "gstrings.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -60,7 +61,7 @@
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]); static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
static void HU_DrawTimeRemaining (int y); static void HU_DrawTimeRemaining (int y);
static void HU_DrawPlayer (player_t *, bool, int, int, int, int, int, int, int); static void HU_DrawPlayer (player_t *, bool, int, int, int, int, int, int, int, int);
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -178,10 +179,11 @@ void HU_DrawScores (player_t *player)
// //
//========================================================================== //==========================================================================
void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth) void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheight)
{ {
maxnamewidth = SmallFont->StringWidth("Name"); maxnamewidth = SmallFont->StringWidth("Name");
maxscorewidth = 0; maxscorewidth = 0;
maxiconheight = 0;
for (int i = 0; i < MAXPLAYERS; i++) for (int i = 0; i < MAXPLAYERS; i++)
{ {
@ -195,11 +197,18 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth)
if (players[i].mo->ScoreIcon.isValid()) if (players[i].mo->ScoreIcon.isValid())
{ {
FTexture *pic = TexMan[players[i].mo->ScoreIcon]; FTexture *pic = TexMan[players[i].mo->ScoreIcon];
width = pic->GetWidth() - pic->GetScaledLeftOffset() + 2; width = pic->GetScaledWidth() - pic->GetScaledLeftOffset() + 2;
if (width > maxscorewidth) if (width > maxscorewidth)
{ {
maxscorewidth = width; maxscorewidth = width;
} }
// The icon's top offset does not count toward its height, because
// zdoom.pk3's standard Hexen class icons are designed that way.
int height = pic->GetScaledHeight() - pic->GetScaledTopOffset();
if (height > maxiconheight)
{
maxiconheight = height;
}
} }
} }
} }
@ -214,11 +223,11 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth)
static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYERS]) static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYERS])
{ {
int color; int color;
int height = SmallFont->GetHeight() * CleanYfac; int height, lineheight;
unsigned int i; unsigned int i;
int maxnamewidth, maxscorewidth; int maxnamewidth, maxscorewidth, maxiconheight;
int numTeams = 0; int numTeams = 0;
int x, y, bottom; int x, y, ypadding, bottom;
int col2, col3, col4; int col2, col3, col4;
if (deathmatch) if (deathmatch)
@ -233,7 +242,10 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
color = sb_cooperative_headingcolor; color = sb_cooperative_headingcolor;
} }
HU_GetPlayerWidths(maxnamewidth, maxscorewidth); HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
height = SmallFont->GetHeight() * CleanYfac;
lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2;
bottom = gamestate != GS_INTERMISSION ? ST_Y : SCREENHEIGHT; bottom = gamestate != GS_INTERMISSION ? ST_Y : SCREENHEIGHT;
y = MAX(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2); y = MAX(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2);
@ -299,18 +311,22 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
y += (BigFont->GetHeight() + 8) * CleanYfac; y += (BigFont->GetHeight() + 8) * CleanYfac;
} }
col2 = (SmallFont->StringWidth("Color") + 8) * CleanXfac; const char *text_color = GStrings("SCORE_COLOR"),
col3 = col2 + (SmallFont->StringWidth("Frags") + 8) * CleanXfac; *text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"),
*text_name = GStrings("SCORE_NAME");
col2 = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
col4 = col3 + maxscorewidth * CleanXfac; col4 = col3 + maxscorewidth * CleanXfac;
x = (SCREENWIDTH >> 1) - ((maxnamewidth * CleanXfac + col4) >> 1); x = (SCREENWIDTH >> 1) - ((maxnamewidth * CleanXfac + col4) >> 1);
screen->DrawText (SmallFont, color, x, y, "Color", screen->DrawText (SmallFont, color, x, y, text_color,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText (SmallFont, color, x + col2, y, deathmatch ? "Frags" : "Kills", screen->DrawText (SmallFont, color, x + col2, y, text_frags,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText (SmallFont, color, x + col4, y, "Name", screen->DrawText (SmallFont, color, x + col4, y, text_name,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
y += height + 6 * CleanYfac; y += height + 6 * CleanYfac;
@ -320,8 +336,8 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
{ {
if (playeringame[sortedplayers[i] - players]) if (playeringame[sortedplayers[i] - players])
{ {
HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, height); HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, ypadding, lineheight);
y += height + CleanYfac; y += lineheight + CleanYfac;
} }
} }
} }
@ -365,7 +381,7 @@ static void HU_DrawTimeRemaining (int y)
// //
//========================================================================== //==========================================================================
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int maxnamewidth, int y, int height) static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int maxnamewidth, int y, int ypadding, int height)
{ {
int color; int color;
char str[80]; char str[80];
@ -386,7 +402,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
HU_DrawColorBar(col1, y, height, (int)(player - players)); HU_DrawColorBar(col1, y, height, (int)(player - players));
mysnprintf (str, countof(str), "%d", deathmatch ? player->fragcount : player->killcount); mysnprintf (str, countof(str), "%d", deathmatch ? player->fragcount : player->killcount);
screen->DrawText (SmallFont, color, col2, y, player->playerstate == PST_DEAD && !deathmatch ? "DEAD" : str, screen->DrawText (SmallFont, color, col2, y + ypadding, player->playerstate == PST_DEAD && !deathmatch ? "DEAD" : str,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
if (player->mo->ScoreIcon.isValid()) if (player->mo->ScoreIcon.isValid())
@ -397,13 +413,13 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
TAG_DONE); TAG_DONE);
} }
screen->DrawText (SmallFont, color, col4, y, player->userinfo.netname, screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.netname,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
if (teamplay && Teams[player->userinfo.team].GetLogo ().IsNotEmpty ()) if (teamplay && Teams[player->userinfo.team].GetLogo ().IsNotEmpty ())
{ {
FTexture *pic = TexMan[Teams[player->userinfo.team].GetLogo ().GetChars ()]; FTexture *pic = TexMan[Teams[player->userinfo.team].GetLogo ().GetChars ()];
screen->DrawTexture (pic, col1 - (pic->GetWidth() + 2) * CleanXfac, y, screen->DrawTexture (pic, col1 - (pic->GetScaledWidth() + 2) * CleanXfac, y,
DTA_CleanNoMove, true, TAG_DONE); DTA_CleanNoMove, true, TAG_DONE);
} }
} }

View file

@ -46,7 +46,7 @@ extern int chatmodeon;
// [RH] Draw deathmatch scores // [RH] Draw deathmatch scores
void HU_DrawScores (player_t *me); void HU_DrawScores (player_t *me);
void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth); void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheight);
void HU_DrawColorBar(int x, int y, int height, int playernum); void HU_DrawColorBar(int x, int y, int height, int playernum);
int HU_GetRowColor(player_t *player, bool hightlight); int HU_GetRowColor(player_t *player, bool hightlight);

View file

@ -56,6 +56,7 @@ extern void InitBotStuff();
extern void ClearStrifeTypes(); extern void ClearStrifeTypes();
TArray<PClassActor *> PClassActor::AllActorClasses; TArray<PClassActor *> PClassActor::AllActorClasses;
FRandom FState::pr_statetics;
bool FState::CallAction(AActor *self, AActor *stateowner) bool FState::CallAction(AActor *self, AActor *stateowner)
{ {
@ -505,19 +506,6 @@ void PClassActor::SetPainChance(FName type, int chance)
} }
} }
//==========================================================================
//
//
//==========================================================================
void PClassActor::SetPainFlash(FName type, PalEntry color)
{
if (PainFlashes == NULL)
PainFlashes = new PainFlashList;
PainFlashes->Insert(type, color);
}
//========================================================================== //==========================================================================
// //
// DmgFactors :: CheckFactor // DmgFactors :: CheckFactor

View file

@ -47,6 +47,7 @@
#include "s_sound.h" #include "s_sound.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "m_random.h"
struct Baggage; struct Baggage;
class FScanner; class FScanner;
@ -63,18 +64,19 @@ enum
struct FState struct FState
{ {
FState *NextState;
VMFunction *ActionFunc;
WORD sprite; WORD sprite;
SWORD Tics; SWORD Tics;
int Misc1; // Was changed to SBYTE, reverted to long for MBF compat WORD TicRange;
int Misc2; // Was changed to BYTE, reverted to long for MBF compat
BYTE Frame; BYTE Frame;
BYTE DefineFlags; // Unused byte so let's use it during state creation. BYTE DefineFlags; // Unused byte so let's use it during state creation.
int Misc1; // Was changed to SBYTE, reverted to long for MBF compat
int Misc2; // Was changed to BYTE, reverted to long for MBF compat
short Light; short Light;
BYTE Fullbright:1; // State is fullbright BYTE Fullbright:1; // State is fullbright
BYTE SameFrame:1; // Ignore Frame (except when spawning actor) BYTE SameFrame:1; // Ignore Frame (except when spawning actor)
BYTE Fast:1; BYTE Fast:1;
FState *NextState;
VMFunction *ActionFunc;
inline int GetFrame() const inline int GetFrame() const
{ {
@ -90,7 +92,11 @@ struct FState
} }
inline int GetTics() const inline int GetTics() const
{ {
return Tics; if (TicRange == 0)
{
return Tics;
}
return Tics + pr_statetics.GenRand32() % (TicRange + 1);
} }
inline int GetMisc1() const inline int GetMisc1() const
{ {
@ -112,6 +118,7 @@ struct FState
bool CallAction(AActor *self, AActor *stateowner); bool CallAction(AActor *self, AActor *stateowner);
static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state);
static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info);
static FRandom pr_statetics;
}; };
struct FStateLabels; struct FStateLabels;
@ -143,7 +150,6 @@ struct DmgFactors : public TMap<FName, fixed_t>
fixed_t *CheckFactor(FName type); fixed_t *CheckFactor(FName type);
}; };
typedef TMap<FName, int> PainChanceList; typedef TMap<FName, int> PainChanceList;
typedef TMap<FName, PalEntry> PainFlashList;
struct DamageTypeDefinition struct DamageTypeDefinition
{ {
@ -190,7 +196,6 @@ public:
void SetPainChance(FName type, int chance); void SetPainChance(FName type, int chance);
size_t PropagateMark(); size_t PropagateMark();
void InitializeNativeDefaults(); void InitializeNativeDefaults();
void SetPainFlash(FName type, PalEntry color);
FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindState(int numnames, FName *names, bool exact=false) const;
FState *FindStateByString(const char *name, bool exact=false); FState *FindStateByString(const char *name, bool exact=false);
@ -217,7 +222,6 @@ public:
FStateLabels *StateList; FStateLabels *StateList;
DmgFactors *DamageFactors; DmgFactors *DamageFactors;
PainChanceList *PainChances; PainChanceList *PainChances;
PainFlashList *PainFlashes;
TArray<PClassPlayerPawn *> VisibleToPlayerClass; TArray<PClassPlayerPawn *> VisibleToPlayerClass;
TArray<PClassPlayerPawn *> RestrictedToPlayerClass; TArray<PClassPlayerPawn *> RestrictedToPlayerClass;

View file

@ -45,6 +45,7 @@
#include "d_net.h" #include "d_net.h"
#include "d_dehacked.h" #include "d_dehacked.h"
#include "gi.h" #include "gi.h"
#include "farchive.h"
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
// writes some bytes to the network data stream, and the network code // writes some bytes to the network data stream, and the network code
@ -106,6 +107,20 @@ void cht_DoCheat (player_t *player, int cheat)
msg = GStrings("STSTR_NCOFF"); msg = GStrings("STSTR_NCOFF");
break; break;
case CHT_NOCLIP2:
player->cheats ^= CF_NOCLIP2;
if (player->cheats & CF_NOCLIP2)
{
player->cheats |= CF_NOCLIP;
msg = GStrings("STSTR_NC2ON");
}
else
{
player->cheats &= ~CF_NOCLIP;
msg = GStrings("STSTR_NCOFF");
}
break;
case CHT_NOVELOCITY: case CHT_NOVELOCITY:
player->cheats ^= CF_NOVELOCITY; player->cheats ^= CF_NOVELOCITY;
if (player->cheats & CF_NOVELOCITY) if (player->cheats & CF_NOVELOCITY)
@ -504,8 +519,8 @@ void cht_DoCheat (player_t *player, int cheat)
if (player == &players[consoleplayer]) if (player == &players[consoleplayer])
Printf ("%s\n", msg); Printf ("%s\n", msg);
else else if (cheat != CHT_CHASECAM)
Printf ("%s is a cheater: %s\n", player->userinfo.netname, msg); Printf ("%s cheats: %s\n", player->userinfo.netname, msg);
} }
const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo)
@ -1042,21 +1057,53 @@ void cht_Take (player_t *player, const char *name, int amount)
return; return;
} }
class DSuicider : public DThinker
{
DECLARE_CLASS(DSuicider, DThinker)
HAS_OBJECT_POINTERS;
public:
TObjPtr<APlayerPawn> Pawn;
void Tick()
{
Pawn->flags |= MF_SHOOTABLE;
Pawn->flags2 &= ~MF2_INVULNERABLE;
// Store the player's current damage factor, to restore it later.
fixed_t plyrdmgfact = Pawn->DamageFactor;
Pawn->DamageFactor = 65536;
P_DamageMobj (Pawn, Pawn, Pawn, TELEFRAG_DAMAGE, NAME_Suicide);
Pawn->DamageFactor = plyrdmgfact;
if (Pawn->health <= 0)
{
Pawn->flags &= ~MF_SHOOTABLE;
}
Destroy();
}
// You'll probably never be able to catch this in a save game, but
// just in case, add a proper serializer.
void Serialize(FArchive &arc)
{
Super::Serialize(arc);
arc << Pawn;
}
};
IMPLEMENT_POINTY_CLASS(DSuicider)
DECLARE_POINTER(Pawn)
END_POINTERS
void cht_Suicide (player_t *plyr) void cht_Suicide (player_t *plyr)
{ {
// If this cheat was initiated by the suicide ccmd, and this is a single
// player game, the CHT_SUICIDE will be processed before the tic is run,
// so the console has not gone up yet. Use a temporary thinker to delay
// the suicide until the game ticks so that death noises can be heard on
// the initial tick.
if (plyr->mo != NULL) if (plyr->mo != NULL)
{ {
plyr->mo->flags |= MF_SHOOTABLE; DSuicider *suicide = new DSuicider;
plyr->mo->flags2 &= ~MF2_INVULNERABLE; suicide->Pawn = plyr->mo;
//Store the players current damage factor, to restore it later. GC::WriteBarrier(suicide, suicide->Pawn);
fixed_t plyrdmgfact = plyr->mo->DamageFactor;
plyr->mo->DamageFactor = 65536;
P_DamageMobj (plyr->mo, plyr->mo, plyr->mo, TELEFRAG_DAMAGE, NAME_Suicide);
plyr->mo->DamageFactor = plyrdmgfact;
if (plyr->mo->health <= 0)
{
plyr->mo->flags &= ~MF_SHOOTABLE;
}
} }
} }

View file

@ -340,9 +340,41 @@ FString GetUserFile (const char *file)
struct stat info; struct stat info;
path = NicePath("~/" GAME_DIR "/"); path = NicePath("~/" GAME_DIR "/");
if (stat (path, &info) == -1) if (stat (path, &info) == -1)
{ {
if (mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) struct stat extrainfo;
// Sanity check for ~/.config
FString configPath = NicePath("~/.config/");
if (stat (configPath, &extrainfo) == -1)
{
if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
{
I_FatalError ("Failed to create ~/.config directory:\n%s", strerror(errno));
}
}
else if (!S_ISDIR(extrainfo.st_mode))
{
I_FatalError ("~/.config must be a directory");
}
// This can be removed after a release or two
// Transfer the old zdoom directory to the new location
bool moved = false;
FString oldpath = NicePath("~/.zdoom/");
if (stat (oldpath, &extrainfo) != -1)
{
if (rename(oldpath, path) == -1)
{
I_Error ("Failed to move old zdoom directory (%s) to new location (%s).",
oldpath.GetChars(), path.GetChars());
}
else
moved = true;
}
if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
{ {
I_FatalError ("Failed to create %s directory:\n%s", I_FatalError ("Failed to create %s directory:\n%s",
path.GetChars(), strerror (errno)); path.GetChars(), strerror (errno));
@ -682,7 +714,7 @@ void M_ScreenShot (const char *filename)
if (dirlen == 0) if (dirlen == 0)
{ {
#ifdef unix #ifdef unix
autoname = "~/.zdoom/screenshots/"; autoname = "~/" GAME_DIR "/screenshots/";
#elif defined(__APPLE__) #elif defined(__APPLE__)
char cpath[PATH_MAX]; char cpath[PATH_MAX];
FSRef folder; FSRef folder;
@ -702,7 +734,6 @@ void M_ScreenShot (const char *filename)
} }
else if (dirlen > 0) else if (dirlen > 0)
{ {
autoname = screenshot_dir;
if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\')
{ {
autoname += '/'; autoname += '/';

View file

@ -139,7 +139,6 @@ struct FOptionMenuSettings
EColorRange mFontColorHighlight; EColorRange mFontColorHighlight;
EColorRange mFontColorSelection; EColorRange mFontColorSelection;
int mLinespacing; int mLinespacing;
int mLabelOffset;
}; };
struct FOptionMenuDescriptor : public FMenuDescriptor struct FOptionMenuDescriptor : public FMenuDescriptor

View file

@ -605,7 +605,7 @@ static void ParseOptionSettings(FScanner &sc)
else if (sc.Compare("LabelOffset")) else if (sc.Compare("LabelOffset"))
{ {
sc.MustGetNumber(); sc.MustGetNumber();
OptionSettings.mLabelOffset = sc.Number; // ignored
} }
else else
{ {

View file

@ -214,7 +214,7 @@ void DMessageBoxMenu::Drawer ()
{ {
screen->DrawText(ConFont, OptionSettings.mFontColorSelection, screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
(150 - 160) * CleanXfac + screen->GetWidth() / 2, (150 - 160) * CleanXfac + screen->GetWidth() / 2,
(y + (fontheight + 1) * messageSelection - 100) * CleanYfac + screen->GetHeight() / 2, (y + (fontheight + 1) * messageSelection - 100 + fontheight/2 - 5) * CleanYfac + screen->GetHeight() / 2,
"\xd", "\xd",
DTA_CellX, 8 * CleanXfac, DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac, DTA_CellY, 8 * CleanYfac,
@ -466,19 +466,7 @@ IMPLEMENT_CLASS(DEndGameMenu)
DEndGameMenu::DEndGameMenu(bool playsound) DEndGameMenu::DEndGameMenu(bool playsound)
{ {
int messageindex = gametic % gameinfo.quitmessages.Size(); Init(NULL, GStrings(netgame ? "NETEND" : "ENDGAME"), 0, playsound);
FString EndString = gameinfo.quitmessages[messageindex];
if (netgame)
{
EndString = GStrings("NETEND");
return;
}
EndString = GStrings("ENDGAME");
Init(NULL, EndString, 0, playsound);
} }
//============================================================================= //=============================================================================
@ -492,7 +480,10 @@ void DEndGameMenu::HandleResult(bool res)
if (res) if (res)
{ {
M_ClearMenus (); M_ClearMenus ();
D_StartTitle (); if (!netgame)
{
D_StartTitle ();
}
} }
else else
{ {

View file

@ -58,8 +58,6 @@
void M_DrawConText (int color, int x, int y, const char *str) void M_DrawConText (int color, int x, int y, const char *str)
{ {
int len = (int)strlen(str);
screen->DrawText (ConFont, color, x, y, str, screen->DrawText (ConFont, color, x, y, str,
DTA_CellX, 8 * CleanXfac_1, DTA_CellX, 8 * CleanXfac_1,
DTA_CellY, 8 * CleanYfac_1, DTA_CellY, 8 * CleanYfac_1,
@ -400,8 +398,6 @@ void DOptionMenu::Drawer ()
} }
} }
mDesc->mDrawTop = y; mDesc->mDrawTop = y;
//int labelofs = OptionSettings.mLabelOffset * CleanXfac_1;
//int cursorspace = 14 * CleanXfac_1;
int fontheight = OptionSettings.mLinespacing * CleanYfac_1; int fontheight = OptionSettings.mLinespacing * CleanYfac_1;
y *= CleanYfac_1; y *= CleanYfac_1;
@ -440,7 +436,7 @@ void DOptionMenu::Drawer ()
{ {
if (((DMenu::MenuTime%8) < 6) || DMenu::CurrentMenu != this) if (((DMenu::MenuTime%8) < 6) || DMenu::CurrentMenu != this)
{ {
M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y-CleanYfac_1+OptionSettings.mLabelOffset, "\xd"); M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y+fontheight-9*CleanYfac_1, "\xd");
} }
} }
} }
@ -451,11 +447,11 @@ void DOptionMenu::Drawer ()
if (CanScrollUp) if (CanScrollUp)
{ {
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop + OptionSettings.mLabelOffset, "\x1a"); M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop, "\x1a");
} }
if (CanScrollDown) if (CanScrollDown)
{ {
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1 + OptionSettings.mLabelOffset, "\x1b"); M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1, "\x1b");
} }
Super::Drawer(); Super::Drawer();
} }

View file

@ -407,11 +407,11 @@ public:
C_NameKeys (description, Key1, Key2); C_NameKeys (description, Key1, Key2);
if (description[0]) if (description[0])
{ {
M_DrawConText(CR_WHITE, indent + CURSORSPACE, y-1+OptionSettings.mLabelOffset, description); M_DrawConText(CR_WHITE, indent + CURSORSPACE, y + (OptionSettings.mLinespacing-8)*CleanYfac_1, description);
} }
else else
{ {
screen->DrawText(SmallFont, CR_BLACK, indent + CURSORSPACE, y + OptionSettings.mLabelOffset, "---", screen->DrawText(SmallFont, CR_BLACK, indent + CURSORSPACE, y + (OptionSettings.mLinespacing-8)*CleanYfac_1, "---",
DTA_CleanNoMove_1, true, TAG_DONE); DTA_CleanNoMove_1, true, TAG_DONE);
} }
return indent; return indent;
@ -569,12 +569,13 @@ public:
// //
//============================================================================= //=============================================================================
void DrawSlider (int x, int y, double min, double max, double cur,int fracdigits, int indent) void DrawSlider (int x, int y, double min, double max, double cur, int fracdigits, int indent)
{ {
char textbuf[16]; char textbuf[16];
double range; double range;
int maxlen = 0; int maxlen = 0;
int right = x + (12*8 + 4) * CleanXfac_1; int right = x + (12*8 + 4) * CleanXfac_1;
int cy = y + (OptionSettings.mLinespacing-8)*CleanYfac_1;
range = max - min; range = max - min;
double ccur = clamp(cur, min, max) - min; double ccur = clamp(cur, min, max) - min;
@ -589,14 +590,14 @@ public:
if (!mSliderShort) if (!mSliderShort)
{ {
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12"); M_DrawConText(CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12");
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 78) / range)) * CleanXfac_1), y, "\x13"); M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 78) / range)) * CleanXfac_1), cy, "\x13");
} }
else else
{ {
// On 320x200 we need a shorter slider // On 320x200 we need a shorter slider
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x12"); M_DrawConText(CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x12");
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), y, "\x13"); M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), cy, "\x13");
right -= 5*8*CleanXfac_1; right -= 5*8*CleanXfac_1;
} }
@ -613,7 +614,7 @@ public:
{ {
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor); drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor);
mDrawX = indent + CURSORSPACE; mDrawX = indent + CURSORSPACE;
DrawSlider (mDrawX, y + OptionSettings.mLabelOffset, mMin, mMax, GetValue(), mShowValue, indent); DrawSlider (mDrawX, y, mMin, mMax, GetValue(), mShowValue, indent);
return indent; return indent;
} }
@ -777,8 +778,8 @@ public:
if (mCVar != NULL) if (mCVar != NULL)
{ {
int box_x = indent + CURSORSPACE; int box_x = indent + CURSORSPACE;
int box_y = y + OptionSettings.mLabelOffset * CleanYfac_1 / 2; int box_y = y + CleanYfac_1;
screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + (SmallFont->GetHeight() - 1) * CleanYfac_1, screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + OptionSettings.mLinespacing*CleanYfac_1,
-1, (uint32)*mCVar | 0xff000000); -1, (uint32)*mCVar | 0xff000000);
} }
return indent; return indent;

View file

@ -590,8 +590,8 @@ void FListMenuItemPlayerDisplay::Drawer(bool selected)
if (mTranslate) trans = translationtables[TRANSLATION_Players](MAXPLAYERS); if (mTranslate) trans = translationtables[TRANSLATION_Players](MAXPLAYERS);
screen->DrawTexture (tex, screen->DrawTexture (tex,
x + 36*CleanXfac, y + 71*CleanYfac, x + 36*CleanXfac, y + 71*CleanYfac,
DTA_DestWidth, MulScale16 (tex->GetWidth() * CleanXfac, scaleX), DTA_DestWidth, MulScale16 (tex->GetScaledWidth() * CleanXfac, scaleX),
DTA_DestHeight, MulScale16 (tex->GetHeight() * CleanYfac, scaleY), DTA_DestHeight, MulScale16 (tex->GetScaledHeight() * CleanYfac, scaleY),
DTA_Translation, trans, DTA_Translation, trans,
DTA_FlipX, sprframe->Flip & (1 << mRotation), DTA_FlipX, sprframe->Flip & (1 << mRotation),
TAG_DONE); TAG_DONE);

View file

@ -99,7 +99,7 @@ CUSTOM_CVAR (Int, menu_screenratios, -1, CVAR_ARCHIVE)
} }
} }
CUSTOM_CVAR (Bool, vid_tft, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Bool, vid_tft, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ {
FOptionMenuDescriptor *opt = GetVideoModeMenu(); FOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL) if (opt != NULL)
@ -316,6 +316,7 @@ void M_InitVideoModesMenu ()
size_t currval = 0; size_t currval = 0;
M_RefreshModesList(); M_RefreshModesList();
vid_tft.Callback();
for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++) for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++)
{ {

View file

@ -86,10 +86,24 @@ FRandom pr_acs ("ACS");
#define STACK_SIZE 4096 #define STACK_SIZE 4096
#define CLAMPCOLOR(c) (EColorRange)((unsigned)(c) >= NUM_TEXT_COLORS ? CR_UNTRANSLATED : (c)) #define CLAMPCOLOR(c) (EColorRange)((unsigned)(c) >= NUM_TEXT_COLORS ? CR_UNTRANSLATED : (c))
#define HUDMSG_LOG (0x80000000)
#define HUDMSG_COLORSTRING (0x40000000)
#define LANGREGIONMASK MAKE_ID(0,0,0xff,0xff) #define LANGREGIONMASK MAKE_ID(0,0,0xff,0xff)
// HUD message flags
#define HUDMSG_LOG (0x80000000)
#define HUDMSG_COLORSTRING (0x40000000)
#define HUDMSG_ADDBLEND (0x20000000)
#define HUDMSG_ALPHA (0x10000000)
// HUD message layers; these are not flags
#define HUDMSG_LAYER_SHIFT 12
#define HUDMSG_LAYER_MASK (0x0000F000)
// See HUDMSGLayer enumerations in sbar.h
// HUD message visibility flags
#define HUDMSG_VISIBILITY_SHIFT 16
#define HUDMSG_VISIBILITY_MASK (0x00070000)
// See HUDMSG visibility enumerations in sbar.h
// Flags for ReplaceTextures // Flags for ReplaceTextures
#define NOT_BOTTOM 1 #define NOT_BOTTOM 1
#define NOT_MIDDLE 2 #define NOT_MIDDLE 2
@ -99,13 +113,12 @@ FRandom pr_acs ("ACS");
struct CallReturn struct CallReturn
{ {
CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard, FString &str) CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard)
: ReturnFunction(func), : ReturnFunction(func),
ReturnModule(module), ReturnModule(module),
ReturnLocals(locals), ReturnLocals(locals),
ReturnAddress(pc), ReturnAddress(pc),
bDiscardResult(discard), bDiscardResult(discard)
StringBuilder(str)
{} {}
ScriptFunction *ReturnFunction; ScriptFunction *ReturnFunction;
@ -113,7 +126,6 @@ struct CallReturn
SDWORD *ReturnLocals; SDWORD *ReturnLocals;
int ReturnAddress; int ReturnAddress;
int bDiscardResult; int bDiscardResult;
FString StringBuilder;
}; };
static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module, static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module,
@ -157,8 +169,8 @@ TArray<FString>
ACS_StringsOnTheFly, ACS_StringsOnTheFly,
ACS_StringBuilderStack; ACS_StringBuilderStack;
#define STRINGBUILDER_START(Builder) if (*Builder.GetChars() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; } #define STRINGBUILDER_START(Builder) if (Builder.IsNotEmpty() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; }
#define STRINGBUILDER_FINISH(Builder) if (!ACS_StringBuilderStack.Pop(Builder)) Builder = ""; #define STRINGBUILDER_FINISH(Builder) if (!ACS_StringBuilderStack.Pop(Builder)) { Builder = ""; }
//============================================================================ //============================================================================
// //
@ -3362,6 +3374,11 @@ enum EACSFunctions
ACSF_ACS_NamedLockedExecuteDoor, ACSF_ACS_NamedLockedExecuteDoor,
ACSF_ACS_NamedExecuteWithResult, ACSF_ACS_NamedExecuteWithResult,
ACSF_ACS_NamedExecuteAlways, ACSF_ACS_NamedExecuteAlways,
ACSF_UniqueTID,
ACSF_IsTIDUsed,
ACSF_Sqrt,
ACSF_FixedSqrt,
ACSF_VectorLength,
// ZDaemon // ZDaemon
ACSF_GetTeamScore = 19620, ACSF_GetTeamScore = 19620,
@ -3874,6 +3891,23 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
} }
break; break;
case ACSF_UniqueTID:
return P_FindUniqueTID(argCount > 0 ? args[0] : 0, argCount > 1 ? args[1] : 0);
break;
case ACSF_IsTIDUsed:
return P_IsTIDUsed(args[0]);
break;
case ACSF_Sqrt:
return xs_FloorToInt(sqrt(double(args[0])));
case ACSF_FixedSqrt:
return FLOAT2FIXED(sqrt(FIXED2DBL(args[0])));
case ACSF_VectorLength:
return FLOAT2FIXED(TVector2<double>(FIXED2DBL(args[0]), FIXED2DBL(args[1])).Length());
default: default:
break; break;
} }
@ -4295,7 +4329,7 @@ int DLevelScript::RunScript ()
} }
sp += i; sp += i;
::new(&Stack[sp]) CallReturn(activeBehavior->PC2Ofs(pc), activeFunction, ::new(&Stack[sp]) CallReturn(activeBehavior->PC2Ofs(pc), activeFunction,
activeBehavior, mylocals, pcd == PCD_CALLDISCARD, work); activeBehavior, mylocals, pcd == PCD_CALLDISCARD);
sp += (sizeof(CallReturn) + sizeof(int) - 1) / sizeof(int); sp += (sizeof(CallReturn) + sizeof(int) - 1) / sizeof(int);
pc = module->Ofs2PC (func->Address); pc = module->Ofs2PC (func->Address);
activeFunction = func; activeFunction = func;
@ -4334,7 +4368,6 @@ int DLevelScript::RunScript ()
{ {
Stack[sp++] = value; Stack[sp++] = value;
} }
work = ret->StringBuilder;
ret->~CallReturn(); ret->~CallReturn();
} }
break; break;
@ -5655,6 +5688,7 @@ scriptwait:
float x = FIXED2FLOAT(Stack[optstart-3]); float x = FIXED2FLOAT(Stack[optstart-3]);
float y = FIXED2FLOAT(Stack[optstart-2]); float y = FIXED2FLOAT(Stack[optstart-2]);
float holdTime = FIXED2FLOAT(Stack[optstart-1]); float holdTime = FIXED2FLOAT(Stack[optstart-1]);
fixed_t alpha;
DHUDMessage *msg; DHUDMessage *msg;
if (type & HUDMSG_COLORSTRING) if (type & HUDMSG_COLORSTRING)
@ -5666,14 +5700,16 @@ scriptwait:
color = CLAMPCOLOR(Stack[optstart-4]); color = CLAMPCOLOR(Stack[optstart-4]);
} }
switch (type & 0xFFFF) switch (type & 0xFF)
{ {
default: // normal default: // normal
alpha = (optstart < sp) ? Stack[optstart] : FRACUNIT;
msg = new DHUDMessage (activefont, work, x, y, hudwidth, hudheight, color, holdTime); msg = new DHUDMessage (activefont, work, x, y, hudwidth, hudheight, color, holdTime);
break; break;
case 1: // fade out case 1: // fade out
{ {
float fadeTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.5f; float fadeTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.5f;
alpha = (optstart < sp-1) ? Stack[optstart+1] : FRACUNIT;
msg = new DHUDMessageFadeOut (activefont, work, x, y, hudwidth, hudheight, color, holdTime, fadeTime); msg = new DHUDMessageFadeOut (activefont, work, x, y, hudwidth, hudheight, color, holdTime, fadeTime);
} }
break; break;
@ -5681,6 +5717,7 @@ scriptwait:
{ {
float typeTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.05f; float typeTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.05f;
float fadeTime = (optstart < sp-1) ? FIXED2FLOAT(Stack[optstart+1]) : 0.5f; float fadeTime = (optstart < sp-1) ? FIXED2FLOAT(Stack[optstart+1]) : 0.5f;
alpha = (optstart < sp-2) ? Stack[optstart+2] : FRACUNIT;
msg = new DHUDMessageTypeOnFadeOut (activefont, work, x, y, hudwidth, hudheight, color, typeTime, holdTime, fadeTime); msg = new DHUDMessageTypeOnFadeOut (activefont, work, x, y, hudwidth, hudheight, color, typeTime, holdTime, fadeTime);
} }
break; break;
@ -5688,11 +5725,22 @@ scriptwait:
{ {
float inTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.5f; float inTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.5f;
float outTime = (optstart < sp-1) ? FIXED2FLOAT(Stack[optstart+1]) : 0.5f; float outTime = (optstart < sp-1) ? FIXED2FLOAT(Stack[optstart+1]) : 0.5f;
alpha = (optstart < sp-2) ? Stack[optstart+2] : FRACUNIT;
msg = new DHUDMessageFadeInOut (activefont, work, x, y, hudwidth, hudheight, color, holdTime, inTime, outTime); msg = new DHUDMessageFadeInOut (activefont, work, x, y, hudwidth, hudheight, color, holdTime, inTime, outTime);
} }
break; break;
} }
StatusBar->AttachMessage (msg, id ? 0xff000000|id : 0); msg->SetVisibility((type & HUDMSG_VISIBILITY_MASK) >> HUDMSG_VISIBILITY_SHIFT);
if (type & HUDMSG_ALPHA)
{
msg->SetAlpha(alpha);
}
if (type & HUDMSG_ADDBLEND)
{
msg->SetRenderStyle(STYLE_Add);
}
StatusBar->AttachMessage (msg, id ? 0xff000000|id : 0,
(type & HUDMSG_LAYER_MASK) >> HUDMSG_LAYER_SHIFT);
if (type & HUDMSG_LOG) if (type & HUDMSG_LOG)
{ {
static const char bar[] = TEXTCOLOR_ORANGE "\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36" static const char bar[] = TEXTCOLOR_ORANGE "\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36"
@ -6340,7 +6388,18 @@ scriptwait:
case PCD_GETACTORZ: case PCD_GETACTORZ:
{ {
AActor *actor = SingleActorFromTID(STACK(1), activator); AActor *actor = SingleActorFromTID(STACK(1), activator);
STACK(1) = actor == NULL ? 0 : (&actor->x)[pcd - PCD_GETACTORX]; if (actor == NULL)
{
STACK(1) = 0;
}
else if (pcd == PCD_GETACTORZ)
{
STACK(1) = actor->z + actor->GetBobOffset();
}
else
{
STACK(1) = (&actor->x)[pcd - PCD_GETACTORX];
}
} }
break; break;
@ -6482,6 +6541,25 @@ scriptwait:
} }
break; break;
case PCD_TRANSLATIONRANGE3:
{ // translation using desaturation
int start = STACK(8);
int end = STACK(7);
fixed_t r1 = STACK(6);
fixed_t g1 = STACK(5);
fixed_t b1 = STACK(4);
fixed_t r2 = STACK(3);
fixed_t g2 = STACK(2);
fixed_t b2 = STACK(1);
sp -= 8;
if (translation != NULL)
translation->AddDesaturation(start, end,
FIXED2DBL(r1), FIXED2DBL(g1), FIXED2DBL(b1),
FIXED2DBL(r2), FIXED2DBL(g2), FIXED2DBL(b2));
}
break;
case PCD_ENDTRANSLATION: case PCD_ENDTRANSLATION:
// This might be useful for hardware rendering, but // This might be useful for hardware rendering, but
// for software it is superfluous. // for software it is superfluous.
@ -6886,7 +6964,8 @@ scriptwait:
} }
else else
{ {
userinfo_t *userinfo = &players[STACK(2)].userinfo; player_t *pl = &players[STACK(2)];
userinfo_t *userinfo = &pl->userinfo;
switch (STACK(1)) switch (STACK(1))
{ {
case PLAYERINFO_TEAM: STACK(2) = userinfo->team; break; case PLAYERINFO_TEAM: STACK(2) = userinfo->team; break;
@ -6897,6 +6976,8 @@ scriptwait:
case PLAYERINFO_MOVEBOB: STACK(2) = userinfo->MoveBob; break; case PLAYERINFO_MOVEBOB: STACK(2) = userinfo->MoveBob; break;
case PLAYERINFO_STILLBOB: STACK(2) = userinfo->StillBob; break; case PLAYERINFO_STILLBOB: STACK(2) = userinfo->StillBob; break;
case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->PlayerClass; break; case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->PlayerClass; break;
case PLAYERINFO_DESIREDFOV: STACK(2) = (int)pl->DesiredFOV; break;
case PLAYERINFO_FOV: STACK(2) = (int)pl->FOV; break;
default: STACK(2) = 0; break; default: STACK(2) = 0; break;
} }
} }
@ -7519,6 +7600,3 @@ void DACSThinker::DumpScriptStatus ()
script = script->next; script = script->next;
} }
} }
#undef STRINGBUILDER_START
#undef STRINGBUILDER_FINISH

View file

@ -601,8 +601,9 @@ public:
PCD_PUSHFUNCTION, // from Eternity PCD_PUSHFUNCTION, // from Eternity
/*360*/ PCD_CALLSTACK, // from Eternity /*360*/ PCD_CALLSTACK, // from Eternity
PCD_SCRIPTWAITNAMED, PCD_SCRIPTWAITNAMED,
PCD_TRANSLATIONRANGE3,
/*361*/ PCODE_COMMAND_COUNT /*363*/ PCODE_COMMAND_COUNT
}; };
// Some constants used by ACS scripts // Some constants used by ACS scripts
@ -664,7 +665,9 @@ public:
PLAYERINFO_NEVERSWITCH, PLAYERINFO_NEVERSWITCH,
PLAYERINFO_MOVEBOB, PLAYERINFO_MOVEBOB,
PLAYERINFO_STILLBOB, PLAYERINFO_STILLBOB,
PLAYERINFO_PLAYERCLASS PLAYERINFO_PLAYERCLASS,
PLAYERINFO_FOV,
PLAYERINFO_DESIREDFOV,
}; };
enum EScriptState enum EScriptState

View file

@ -926,7 +926,6 @@ public:
const char *speakerName; const char *speakerName;
int x, y, linesize; int x, y, linesize;
int width, fontheight; int width, fontheight;
int labelofs;
player_t *cp = &players[consoleplayer]; player_t *cp = &players[consoleplayer];
@ -1015,8 +1014,6 @@ public:
} }
y = mYpos; y = mYpos;
labelofs = OptionSettings.mLabelOffset;
y -= labelofs;
fontheight = OptionSettings.mLinespacing; fontheight = OptionSettings.mLinespacing;
int response = 0; int response = 0;
@ -1041,7 +1038,7 @@ public:
int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY; int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY;
x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2;
int yy = (y-1+labelofs - 100) * CleanYfac + screen->GetHeight() / 2; int yy = (y + fontheight/2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2;
screen->DrawText (ConFont, color, x, yy, "\xd", screen->DrawText (ConFont, color, x, yy, "\xd",
DTA_CellX, 8 * CleanXfac, DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac, DTA_CellY, 8 * CleanYfac,

View file

@ -1670,7 +1670,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
// [RC] Well, let's let special monsters with this flag active be able to see // [RC] Well, let's let special monsters with this flag active be able to see
// the player then, eh? // the player then, eh?
if(!(actor->flags & MF6_SEEINVISIBLE)) if(!(actor->flags6 & MF6_SEEINVISIBLE))
{ {
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
player->mo->flags3 & MF3_GHOST) player->mo->flags3 & MF3_GHOST)
@ -3210,7 +3210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Detonate)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
int damage = self->GetMissileDamage(0, 1); int damage = self->GetMissileDamage(0, 1);
P_RadiusAttack (self, self->target, damage, damage, self->DamageType, true); P_RadiusAttack (self, self->target, damage, damage, self->DamageType, RADF_HURTSOURCE);
P_CheckSplash(self, damage<<FRACBITS); P_CheckSplash(self, damage<<FRACBITS);
return 0; return 0;
} }

View file

@ -1088,7 +1088,7 @@ static FString GetCachePath()
path += "/zdoom/cache"; path += "/zdoom/cache";
#else #else
// Don't use GAME_DIR and such so that ZDoom and its child ports can share the node cache. // Don't use GAME_DIR and such so that ZDoom and its child ports can share the node cache.
path = NicePath("~/.zdoom/cache"); path = NicePath("~/.config/zdoom/cache");
#endif #endif
return path; return path;
} }

View file

@ -86,7 +86,9 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher)
{ {
fixed_t delta = special->z - toucher->z; fixed_t delta = special->z - toucher->z;
if (delta > toucher->height || delta < -32*FRACUNIT) // The pickup is at or above the toucher's feet OR
// The pickup is below the toucher.
if (delta > toucher->height || delta < MIN(-32*FRACUNIT, -special->height))
{ // out of reach { // out of reach
return; return;
} }

View file

@ -483,8 +483,15 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner);
void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec);
// [RH] Means of death // [RH] Means of death
enum
{
RADF_HURTSOURCE = 1,
RADF_NOIMPACTDAMAGE = 2,
RADF_SOURCEISSPOT = 4,
RADF_NODAMAGE = 8,
};
void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance,
FName damageType, bool hurtSelf, bool dodamage=true, int fulldamagedistance=0, bool noimpactdamage=false); FName damageType, int flags, int fulldamagedistance=0);
void P_DelSector_List(); void P_DelSector_List();
void P_DelSeclist(msecnode_t *); // phares 3/16/98 void P_DelSeclist(msecnode_t *); // phares 3/16/98

View file

@ -501,7 +501,11 @@ int P_GetFriction (const AActor *mo, int *frictionfactor)
const msecnode_t *m; const msecnode_t *m;
const sector_t *sec; const sector_t *sec;
if (mo->flags2 & MF2_FLY && mo->flags & MF_NOGRAVITY) if (mo->IsNoClip2())
{
// The default values are fine for noclip2 mode
}
else if (mo->flags2 & MF2_FLY && mo->flags & MF_NOGRAVITY)
{ {
friction = FRICTION_FLY; friction = FRICTION_FLY;
} }
@ -938,8 +942,11 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
|| ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE)) || ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE))
) && (level.maptime > thing->lastbump)) // Leave the bumper enough time to go away ) && (level.maptime > thing->lastbump)) // Leave the bumper enough time to go away
{ {
if (P_ActivateThingSpecial(thing, tm.thing)) if (tm.thing->player == NULL || !(tm.thing->player->cheats & CF_PREDICTING))
thing->lastbump = level.maptime + TICRATE; {
if (P_ActivateThingSpecial(thing, tm.thing))
thing->lastbump = level.maptime + TICRATE;
}
} }
// Check for skulls slamming into things // Check for skulls slamming into things
@ -1298,7 +1305,7 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, b
#ifdef _3DFLOORS #ifdef _3DFLOORS
//Check 3D floors //Check 3D floors
if(newsec->e->XFloor.ffloors.Size()) if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size())
{ {
F3DFloor* rover; F3DFloor* rover;
fixed_t delta1; fixed_t delta1;
@ -1605,7 +1612,7 @@ void P_FakeZMovement (AActor *mo)
mo->z += mo->FloatSpeed; mo->z += mo->FloatSpeed;
} }
} }
if (mo->player && mo->flags&MF_NOGRAVITY && (mo->z > mo->floorz)) if (mo->player && mo->flags&MF_NOGRAVITY && (mo->z > mo->floorz) && !mo->IsNoClip2())
{ {
mo->z += finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8; mo->z += finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8;
} }
@ -4440,7 +4447,7 @@ CUSTOM_CVAR (Float, splashfactor, 1.f, CVAR_SERVERINFO)
//========================================================================== //==========================================================================
void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod, void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod,
bool DamageSource, bool bombdodamage, int fulldamagedistance, bool noimpactdamage) int flags, int fulldamagedistance)
{ {
if (bombdistance <= 0) if (bombdistance <= 0)
return; return;
@ -4454,6 +4461,11 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
FBlockThingsIterator it(FBoundingBox(bombspot->x, bombspot->y, bombdistance<<FRACBITS)); FBlockThingsIterator it(FBoundingBox(bombspot->x, bombspot->y, bombdistance<<FRACBITS));
AActor *thing; AActor *thing;
if (flags & RADF_SOURCEISSPOT)
{ // The source is actually the same as the spot, even if that wasn't what we receized.
bombsource = bombspot;
}
while ((thing = it.Next())) while ((thing = it.Next()))
{ {
// Vulnerable actors can be damaged by radius attacks even if not shootable // Vulnerable actors can be damaged by radius attacks even if not shootable
@ -4466,7 +4478,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG))
continue; continue;
if (!DamageSource && (thing == bombsource || thing == bombspot)) if (!(flags & RADF_HURTSOURCE) && (thing == bombsource || thing == bombspot))
{ // don't damage the source of the explosion { // don't damage the source of the explosion
continue; continue;
} }
@ -4486,7 +4498,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
// them far too "active." BossBrains also use the old code // them far too "active." BossBrains also use the old code
// because some user levels require they have a height of 16, // because some user levels require they have a height of 16,
// which can make them near impossible to hit with the new code. // which can make them near impossible to hit with the new code.
if (!bombdodamage || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)) if ((flags & RADF_NODAMAGE) || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG))
{ {
// [RH] New code. The bounding box only covers the // [RH] New code. The bounding box only covers the
// height of the thing and not the height of the map. // height of the thing and not the height of the map.
@ -4545,14 +4557,17 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
double thrust; double thrust;
int damage = (int)points; int damage = (int)points;
if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); if (!(flags & RADF_NODAMAGE))
else if (thing->player == NULL && !noimpactdamage) thing->flags2 |= MF2_BLASTED; P_DamageMobj (thing, bombspot, bombsource, damage, bombmod);
else if (thing->player == NULL && !(flags & RADF_NOIMPACTDAMAGE))
thing->flags2 |= MF2_BLASTED;
if (!(thing->flags & MF_ICECORPSE)) if (!(thing->flags & MF_ICECORPSE))
{ {
if (bombdodamage && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed (damage, thing, bombspot); if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT))
P_TraceBleed (damage, thing, bombspot);
if (!bombdodamage || !(bombspot->flags2 & MF2_NODMGTHRUST)) if (!(flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST))
{ {
if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST))
{ {
@ -4573,7 +4588,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
angle_t ang = R_PointToAngle2 (bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; angle_t ang = R_PointToAngle2 (bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT;
thing->velx += fixed_t (finecosine[ang] * thrust); thing->velx += fixed_t (finecosine[ang] * thrust);
thing->vely += fixed_t (finesine[ang] * thrust); thing->vely += fixed_t (finesine[ang] * thrust);
if (bombdodamage) if (!(flags & RADF_NODAMAGE))
thing->velz += (fixed_t)velz; // this really doesn't work well thing->velz += (fixed_t)velz; // this really doesn't work well
} }
} }

View file

@ -37,6 +37,7 @@
#include "doomstat.h" #include "doomstat.h"
#include "v_video.h" #include "v_video.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "c_dispatch.h"
#include "b_bot.h" //Added by MC: #include "b_bot.h" //Added by MC:
#include "stats.h" #include "stats.h"
#include "a_hexenglobal.h" #include "a_hexenglobal.h"
@ -107,6 +108,7 @@ static FRandom pr_missiledamage ("MissileDamage");
FRandom pr_slam ("SkullSlam"); FRandom pr_slam ("SkullSlam");
static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_multiclasschoice ("MultiClassChoice");
static FRandom pr_rockettrail("RocketTrail"); static FRandom pr_rockettrail("RocketTrail");
static FRandom pr_uniquetid("UniqueTID");
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
@ -1158,6 +1160,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
} }
mo->velx = mo->vely = mo->velz = 0; mo->velx = mo->vely = mo->velz = 0;
mo->effects = 0; // [RH] mo->effects = 0; // [RH]
mo->flags &= ~MF_SHOOTABLE;
FState *nextstate=NULL; FState *nextstate=NULL;
@ -1983,7 +1986,9 @@ explode:
} }
if (mo->z > mo->floorz && !(mo->flags2 & MF2_ONMOBJ) && if (mo->z > mo->floorz && !(mo->flags2 & MF2_ONMOBJ) &&
(!(mo->flags2 & MF2_FLY) || !(mo->flags & MF_NOGRAVITY)) && !mo->waterlevel) !mo->IsNoClip2() &&
(!(mo->flags2 & MF2_FLY) || !(mo->flags & MF_NOGRAVITY)) &&
!mo->waterlevel)
{ // [RH] Friction when falling is available for larger aircontrols { // [RH] Friction when falling is available for larger aircontrols
if (player != NULL && level.airfriction != FRACUNIT) if (player != NULL && level.airfriction != FRACUNIT)
{ {
@ -2226,7 +2231,10 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
} }
if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->z > mo->floorz)) if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->z > mo->floorz))
{ {
mo->z += finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8; if (!mo->IsNoClip2())
{
mo->z += finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8;
}
mo->velz = FixedMul (mo->velz, FRICTION_FLY); mo->velz = FixedMul (mo->velz, FRICTION_FLY);
} }
if (mo->waterlevel && !(mo->flags & MF_NOGRAVITY)) if (mo->waterlevel && !(mo->flags & MF_NOGRAVITY))
@ -2474,7 +2482,7 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj)
{ {
grunted = false; grunted = false;
// Why should this number vary by gravity? // Why should this number vary by gravity?
if (mo->velz < (fixed_t)(800.f /*level.gravity * mo->Sector->gravity*/ * -983.04f) && mo->health > 0) if (mo->health > 0 && mo->velz < -mo->player->mo->GruntSpeed)
{ {
S_Sound (mo, CHAN_VOICE, "*grunt", 1, ATTN_NORM); S_Sound (mo, CHAN_VOICE, "*grunt", 1, ATTN_NORM);
grunted = true; grunted = true;
@ -2613,10 +2621,7 @@ AActor *AActor::TIDHash[128];
void AActor::ClearTIDHashes () void AActor::ClearTIDHashes ()
{ {
int i; memset(TIDHash, NULL, sizeof(TIDHash));
for (i = 0; i < 128; i++)
TIDHash[i] = NULL;
} }
// //
@ -2667,6 +2672,92 @@ void AActor::RemoveFromHash ()
tid = 0; tid = 0;
} }
//==========================================================================
//
// P_IsTIDUsed
//
// Returns true if there is at least one actor with the specified TID
// (dead or alive).
//
//==========================================================================
bool P_IsTIDUsed(int tid)
{
AActor *probe = AActor::TIDHash[tid & 127];
while (probe != NULL)
{
if (probe->tid == tid)
{
return true;
}
probe = probe->inext;
}
return false;
}
//==========================================================================
//
// P_FindUniqueTID
//
// Returns an unused TID. If start_tid is 0, then a random TID will be
// chosen. Otherwise, it will perform a linear search starting from
// start_tid. If limit is non-0, then it will not check more than <limit>
// number of TIDs. Returns 0 if no suitable TID was found.
//
//==========================================================================
int P_FindUniqueTID(int start_tid, int limit)
{
int tid;
if (start_tid != 0)
{ // Do a linear search.
limit = start_tid + limit - 1;
if (limit < start_tid)
{ // If it overflowed, clamp to INT_MAX
limit = INT_MAX;
}
for (tid = start_tid; tid <= limit; ++tid)
{
if (tid != 0 && !P_IsTIDUsed(tid))
{
return tid;
}
}
// Nothing free found.
return 0;
}
// Do a random search. To try and be a bit more performant, this
// actually does several linear searches. In the case of *very*
// dense TID usage, this could potentially perform worse than doing
// a complete linear scan starting at 1. However, you would need
// to use an absolutely ridiculous number of actors before this
// becomes a real concern.
if (limit == 0)
{
limit = INT_MAX;
}
for (int i = 0; i < limit; i += 5)
{
// Use a positive starting TID.
tid = pr_uniquetid.GenRand32() & INT_MAX;
tid = P_FindUniqueTID(tid == 0 ? 1 : tid, 5);
if (tid != 0)
{
return tid;
}
}
// Nothing free found.
return 0;
}
CCMD(utid)
{
Printf("%d\n",
P_FindUniqueTID(argv.argc() > 1 ? atoi(argv[1]) : 0,
argv.argc() > 2 ? atoi(argv[2]) : 0));
}
//========================================================================== //==========================================================================
// //
// AActor :: GetMissileDamage // AActor :: GetMissileDamage
@ -3363,8 +3454,11 @@ void AActor::Tick ()
|| ((onmo->activationtype & THINGSPEC_MissileTrigger) && (flags & MF_MISSILE)) || ((onmo->activationtype & THINGSPEC_MissileTrigger) && (flags & MF_MISSILE))
) && (level.maptime > onmo->lastbump)) // Leave the bumper enough time to go away ) && (level.maptime > onmo->lastbump)) // Leave the bumper enough time to go away
{ {
if (P_ActivateThingSpecial(onmo, this)) if (player == NULL || !(player->cheats & CF_PREDICTING))
onmo->lastbump = level.maptime + TICRATE; {
if (P_ActivateThingSpecial(onmo, this))
onmo->lastbump = level.maptime + TICRATE;
}
} }
if (velz != 0 && (BounceFlags & BOUNCE_Actors)) if (velz != 0 && (BounceFlags & BOUNCE_Actors))
{ {
@ -3902,6 +3996,19 @@ void AActor::PostBeginPlay ()
PrevAngle = angle; PrevAngle = angle;
} }
void AActor::MarkPrecacheSounds() const
{
SeeSound.MarkUsed();
AttackSound.MarkUsed();
PainSound.MarkUsed();
DeathSound.MarkUsed();
ActiveSound.MarkUsed();
UseSound.MarkUsed();
BounceSound.MarkUsed();
WallBounceSound.MarkUsed();
CrushPainSound.MarkUsed();
}
bool AActor::isFast() bool AActor::isFast()
{ {
if (flags5&MF5_ALWAYSFAST) return true; if (flags5&MF5_ALWAYSFAST) return true;
@ -4734,13 +4841,16 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
// Moved out of the blood actor so that replacing blood is easier // Moved out of the blood actor so that replacing blood is easier
if (gameinfo.gametype & GAME_DoomStrifeChex) if (gameinfo.gametype & GAME_DoomStrifeChex)
{ {
FState *state = th->FindState(NAME_Spray);
if (gameinfo.gametype == GAME_Strife) if (gameinfo.gametype == GAME_Strife)
{ {
if (damage > 13) if (damage > 13)
{ {
FState *state = th->FindState(NAME_Spray); FState *state = th->FindState(NAME_Spray);
if (state != NULL) th->SetState (state); if (state != NULL)
{
th->SetState (state);
goto statedone;
}
} }
else damage += 2; else damage += 2;
} }
@ -4758,14 +4868,15 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
while (cls != RUNTIME_CLASS(AActor)) while (cls != RUNTIME_CLASS(AActor))
{ {
int checked_advance = advance;
if (cls->OwnsState(th->SpawnState)) if (cls->OwnsState(th->SpawnState))
{ {
for (; advance > 0; --advance) for (; checked_advance > 0; --checked_advance)
{ {
// [RH] Do not set to a state we do not own. // [RH] Do not set to a state we do not own.
if (!cls->OwnsState(th->SpawnState + advance)) if (cls->OwnsState(th->SpawnState + checked_advance))
{ {
th->SetState(th->SpawnState + advance); th->SetState(th->SpawnState + checked_advance);
goto statedone; goto statedone;
} }
} }
@ -5295,7 +5406,7 @@ static fixed_t GetDefaultSpeed(PClassActor *type)
AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner)
{ {
return P_SpawnMissileXYZ (source->x, source->y, source->z + 32*FRACUNIT, return P_SpawnMissileXYZ (source->x, source->y, source->z + 32*FRACUNIT + source->GetBobOffset(),
source, dest, type, true, owner); source, dest, type, true, owner);
} }
@ -5417,7 +5528,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct
AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type,
angle_t angle, fixed_t velz) angle_t angle, fixed_t velz)
{ {
return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT, return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT + source->GetBobOffset(),
type, angle, velz, GetDefaultSpeed (type)); type, angle, velz, GetDefaultSpeed (type));
} }
@ -5460,7 +5571,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassAct
AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type,
angle_t angle, fixed_t velz, fixed_t speed) angle_t angle, fixed_t velz, fixed_t speed)
{ {
return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT, return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT + source->GetBobOffset(),
type, angle, velz, speed); type, angle, velz, speed);
} }
@ -5985,25 +6096,25 @@ void PrintMiscActorInfo(AActor *query)
Printf("\n\tflags6: %x", query->flags6); Printf("\n\tflags6: %x", query->flags6);
for (flagi = 0; flagi < 31; flagi++) for (flagi = 0; flagi < 31; flagi++)
if (query->flags6 & 1<<flagi) Printf(" %s", FLAG_NAME(1<<flagi, flags6)); if (query->flags6 & 1<<flagi) Printf(" %s", FLAG_NAME(1<<flagi, flags6));
Printf("\nIts bounce style and factors are %x and f:%f, w:%f; its bounce flags are:\n\tflagsb: %x", Printf("\nBounce style: %x\nBounce factors: f:%f, w:%f\nBounce flags: %x",
query->BounceFlags, FIXED2FLOAT(query->bouncefactor), query->BounceFlags, FIXED2FLOAT(query->bouncefactor),
FIXED2FLOAT(query->wallbouncefactor), query->BounceFlags); FIXED2FLOAT(query->wallbouncefactor), query->BounceFlags);
/*for (flagi = 0; flagi < 31; flagi++) /*for (flagi = 0; flagi < 31; flagi++)
if (query->BounceFlags & 1<<flagi) Printf(" %s", flagnamesb[flagi]);*/ if (query->BounceFlags & 1<<flagi) Printf(" %s", flagnamesb[flagi]);*/
Printf("\nIts render style is %i:%s with alpha %f and the following render flags:\n\tflagsr: %x", Printf("\nRender style = %i:%s, alpha %f\nRender flags: %x",
querystyle, (querystyle < STYLE_Count ? renderstyles[querystyle] : "Unknown"), querystyle, (querystyle < STYLE_Count ? renderstyles[querystyle] : "Unknown"),
FIXED2FLOAT(query->alpha), query->renderflags); FIXED2FLOAT(query->alpha), query->renderflags);
/*for (flagi = 0; flagi < 31; flagi++) /*for (flagi = 0; flagi < 31; flagi++)
if (query->renderflags & 1<<flagi) Printf(" %s", flagnamesr[flagi]);*/ if (query->renderflags & 1<<flagi) Printf(" %s", flagnamesr[flagi]);*/
Printf("\nIts thing special and arguments are %s(%i, %i, %i, %i, %i), and its specials are %i and %i.", Printf("\nSpecial+args: %s(%i, %i, %i, %i, %i)\nspecial1: %i, special2: %i.",
(query->special ? LineSpecialsInfo[query->special]->name : "None"), (query->special ? LineSpecialsInfo[query->special]->name : "None"),
query->args[0], query->args[1], query->args[2], query->args[3], query->args[0], query->args[1], query->args[2], query->args[3],
query->args[4], query->special1, query->special2); query->args[4], query->special1, query->special2);
Printf("\nTID is %d", query->tid); Printf("\nTID: %d", query->tid);
Printf("\nIts coordinates are x: %f, y: %f, z:%f, floor:%f, ceiling:%f.", Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.",
FIXED2FLOAT(query->x), FIXED2FLOAT(query->y), FIXED2FLOAT(query->z), FIXED2FLOAT(query->x), FIXED2FLOAT(query->y), FIXED2FLOAT(query->z),
FIXED2FLOAT(query->floorz), FIXED2FLOAT(query->ceilingz)); FIXED2FLOAT(query->floorz), FIXED2FLOAT(query->ceilingz));
Printf("\nIts speed is %f and velocity is x:%f, y:%f, z:%f, combined:%f.\n", Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n",
FIXED2FLOAT(query->Speed), FIXED2FLOAT(query->velx), FIXED2FLOAT(query->vely), FIXED2FLOAT(query->velz), FIXED2FLOAT(query->Speed), FIXED2FLOAT(query->velx), FIXED2FLOAT(query->vely), FIXED2FLOAT(query->velz),
sqrt(pow(FIXED2FLOAT(query->velx), 2) + pow(FIXED2FLOAT(query->vely), 2) + pow(FIXED2FLOAT(query->velz), 2))); sqrt(pow(FIXED2FLOAT(query->velx), 2) + pow(FIXED2FLOAT(query->vely), 2) + pow(FIXED2FLOAT(query->velz), 2)));
} }

View file

@ -909,7 +909,6 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
{ {
FState *realstates = new FState[count]; FState *realstates = new FState[count];
int i; int i;
int currange;
memcpy(realstates, &StateArray[0], count*sizeof(FState)); memcpy(realstates, &StateArray[0], count*sizeof(FState));
actor->OwnedStates = realstates; actor->OwnedStates = realstates;
@ -917,12 +916,15 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
// adjust the state pointers // adjust the state pointers
// In the case new states are added these must be adjusted, too! // In the case new states are added these must be adjusted, too!
FixStatePointers (actor, StateLabels); FixStatePointers(actor, StateLabels);
for(i = currange = 0; i < count; i++) // Fix state pointers that are gotos
ResolveGotoLabels(actor, defaults, StateLabels);
for (i = 0; i < count; i++)
{ {
// resolve labels and jumps // resolve labels and jumps
switch(realstates[i].DefineFlags) switch (realstates[i].DefineFlags)
{ {
case SDF_STOP: // stop case SDF_STOP: // stop
realstates[i].NextState = NULL; realstates[i].NextState = NULL;
@ -946,10 +948,11 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
} }
} }
} }
else
// Fix state pointers that are gotos {
ResolveGotoLabels(actor, defaults, StateLabels); // Fix state pointers that are gotos
ResolveGotoLabels(actor, defaults, StateLabels);
}
return count; return count;
} }

View file

@ -137,6 +137,10 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog)
source->PrevX = x; source->PrevX = x;
source->PrevY = y; source->PrevY = y;
source->PrevZ = z; source->PrevZ = z;
if (source == players[consoleplayer].camera)
{
R_ResetViewInterpolation();
}
return true; return true;
} }
else else

View file

@ -471,6 +471,29 @@ void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
} }
//==========================================================================
//
//
//==========================================================================
bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const
{
const PClassPlayerPawn *info = this;
while (info != NULL)
{
const PalEntry *flash = info->PainFlashes.CheckKey(type);
if (flash != NULL)
{
*color = *flash;
return true;
}
// Try parent class
info = dyn_cast<PClassPlayerPawn>(info->ParentClass);
}
return false;
}
//=========================================================================== //===========================================================================
// //
// player_t :: SendPitchLimits // player_t :: SendPitchLimits
@ -523,6 +546,28 @@ void APlayerPawn::Serialize (FArchive &arc)
<< DamageFade << DamageFade
<< PlayerFlags << PlayerFlags
<< FlechetteType; << FlechetteType;
if (SaveVersion < 3829)
{
GruntSpeed = 12*FRACUNIT;
FallingScreamMinSpeed = 35*FRACUNIT;
FallingScreamMaxSpeed = 40*FRACUNIT;
}
else
{
arc << GruntSpeed << FallingScreamMinSpeed << FallingScreamMaxSpeed;
}
}
//===========================================================================
//
// APlayerPawn :: MarkPrecacheSounds
//
//===========================================================================
void APlayerPawn::MarkPrecacheSounds() const
{
Super::MarkPrecacheSounds();
S_MarkPlayerSounds(GetSoundClass());
} }
//=========================================================================== //===========================================================================
@ -1018,7 +1063,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
// //
//=========================================================================== //===========================================================================
const char *APlayerPawn::GetSoundClass () const char *APlayerPawn::GetSoundClass() const
{ {
if (player != NULL && if (player != NULL &&
(player->mo == NULL || !(player->mo->flags4 &MF4_NOSKIN)) && (player->mo == NULL || !(player->mo->flags4 &MF4_NOSKIN)) &&
@ -1679,7 +1724,11 @@ void P_CalcHeight (player_t *player)
// it causes bobbing jerkiness when the player moves from ice to non-ice, // it causes bobbing jerkiness when the player moves from ice to non-ice,
// and vice-versa. // and vice-versa.
if ((player->mo->flags & MF_NOGRAVITY) && !onground) if (player->cheats & CF_NOCLIP2)
{
player->bob = 0;
}
else if ((player->mo->flags & MF_NOGRAVITY) && !onground)
{ {
player->bob = FRACUNIT / 2; player->bob = FRACUNIT / 2;
} }
@ -1804,7 +1853,7 @@ void P_MovePlayer (player_t *player)
mo->angle += cmd->ucmd.yaw << 16; mo->angle += cmd->ucmd.yaw << 16;
} }
onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF); onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF) || (player->cheats & CF_NOCLIP2);
// killough 10/98: // killough 10/98:
// //
@ -2185,7 +2234,11 @@ void P_PlayerThink (player_t *player)
player->inventorytics--; player->inventorytics--;
} }
// No-clip cheat // No-clip cheat
if (player->cheats & CF_NOCLIP || (player->mo->GetDefault()->flags & MF_NOCLIP)) if ((player->cheats & (CF_NOCLIP | CF_NOCLIP2)) == CF_NOCLIP2)
{ // No noclip2 without noclip
player->cheats &= ~CF_NOCLIP2;
}
if (player->cheats & (CF_NOCLIP | CF_NOCLIP2) || (player->mo->GetDefault()->flags & MF_NOCLIP))
{ {
player->mo->flags |= MF_NOCLIP; player->mo->flags |= MF_NOCLIP;
} }
@ -2193,6 +2246,14 @@ void P_PlayerThink (player_t *player)
{ {
player->mo->flags &= ~MF_NOCLIP; player->mo->flags &= ~MF_NOCLIP;
} }
if (player->cheats & CF_NOCLIP2)
{
player->mo->flags |= MF_NOGRAVITY;
}
else if (!(player->mo->flags2 & MF2_FLY) && !(player->mo->GetDefault()->flags & MF_NOGRAVITY))
{
player->mo->flags &= ~MF_NOGRAVITY;
}
cmd = &player->cmd; cmd = &player->cmd;
// Make unmodified copies for ACS's GetPlayerInput. // Make unmodified copies for ACS's GetPlayerInput.
@ -2413,7 +2474,7 @@ void P_PlayerThink (player_t *player)
{ {
cmd->ucmd.upmove = ksgn (cmd->ucmd.upmove) * 0x300; cmd->ucmd.upmove = ksgn (cmd->ucmd.upmove) * 0x300;
} }
if (player->mo->waterlevel >= 2 || (player->mo->flags2 & MF2_FLY)) if (player->mo->waterlevel >= 2 || (player->mo->flags2 & MF2_FLY) || (player->cheats & CF_NOCLIP2))
{ {
player->mo->velz = cmd->ucmd.upmove << 9; player->mo->velz = cmd->ucmd.upmove << 9;
if (player->mo->waterlevel < 2 && !(player->mo->flags & MF_NOGRAVITY)) if (player->mo->waterlevel < 2 && !(player->mo->flags & MF_NOGRAVITY))
@ -2447,8 +2508,8 @@ void P_PlayerThink (player_t *player)
P_PlayerInSpecialSector (player); P_PlayerInSpecialSector (player);
} }
P_PlayerOnSpecialFlat (player, P_GetThingFloorType (player->mo)); P_PlayerOnSpecialFlat (player, P_GetThingFloorType (player->mo));
if (player->mo->velz <= -35*FRACUNIT && if (player->mo->velz <= -player->mo->FallingScreamMinSpeed &&
player->mo->velz >= -40*FRACUNIT && !player->morphTics && player->mo->velz >= -player->mo->FallingScreamMaxSpeed && !player->morphTics &&
player->mo->waterlevel == 0) player->mo->waterlevel == 0)
{ {
int id = S_FindSkinnedSound (player->mo, "*falling"); int id = S_FindSkinnedSound (player->mo, "*falling");
@ -2531,7 +2592,7 @@ void P_PlayerThink (player_t *player)
{ {
if (player->mo->waterlevel < 3 || if (player->mo->waterlevel < 3 ||
(player->mo->flags2 & MF2_INVULNERABLE) || (player->mo->flags2 & MF2_INVULNERABLE) ||
(player->cheats & CF_GODMODE)) (player->cheats & (CF_GODMODE | CF_NOCLIP2)))
{ {
player->mo->ResetAirSupply (); player->mo->ResetAirSupply ();
} }
@ -2763,6 +2824,14 @@ void player_t::Serialize (FArchive &arc)
{ {
cheats &= ~(1 << 17); // make sure old CF_REGENERATION bit is cleared cheats &= ~(1 << 17); // make sure old CF_REGENERATION bit is cleared
} }
if (SaveVersion >= 3780)
{
arc << settings_controller;
}
else
{
settings_controller = (this - players == Net_Arbitrator);
}
if (isbot) if (isbot)
{ {

View file

@ -1185,7 +1185,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetTexture(sector_t::floor), frontsector->GetTexture(sector_t::floor),
floorlightlevel + r_actualextralight, // killough 3/16/98 floorlightlevel + r_actualextralight, // killough 3/16/98
frontsector->GetAlpha(sector_t::floor), frontsector->GetAlpha(sector_t::floor),
!!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE), !!(fakeFloor->flags & FF_ADDITIVETRANS),
frontsector->GetXOffset(position), // killough 3/7/98 frontsector->GetXOffset(position), // killough 3/7/98
frontsector->GetYOffset(position), // killough 3/7/98 frontsector->GetYOffset(position), // killough 3/7/98
frontsector->GetXScale(position), frontsector->GetXScale(position),
@ -1250,7 +1250,7 @@ void R_Subsector (subsector_t *sub)
frontsector->GetTexture(sector_t::ceiling), frontsector->GetTexture(sector_t::ceiling),
ceilinglightlevel + r_actualextralight, // killough 4/11/98 ceilinglightlevel + r_actualextralight, // killough 4/11/98
frontsector->GetAlpha(sector_t::ceiling), frontsector->GetAlpha(sector_t::ceiling),
!!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE), !!(fakeFloor->flags & FF_ADDITIVETRANS),
frontsector->GetXOffset(position), // killough 3/7/98 frontsector->GetXOffset(position), // killough 3/7/98
frontsector->GetYOffset(position), // killough 3/7/98 frontsector->GetYOffset(position), // killough 3/7/98
frontsector->GetXScale(position), frontsector->GetXScale(position),

View file

@ -403,14 +403,22 @@ void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, in
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void FRemapTable::AddDesaturation(int start, int end, float r1,float g1, float b1, float r2, float g2, float b2) void FRemapTable::AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2)
{ {
r1 = clamp(r1, 0.0f, 2.0f); r1 = clamp(r1, 0.0, 2.0);
g1 = clamp(g1, 0.0f, 2.0f); g1 = clamp(g1, 0.0, 2.0);
b1 = clamp(b1, 0.0f, 2.0f); b1 = clamp(b1, 0.0, 2.0);
r2 = clamp(r2, 0.0f, 2.0f); r2 = clamp(r2, 0.0, 2.0);
g2 = clamp(g2, 0.0f, 2.0f); g2 = clamp(g2, 0.0, 2.0);
b2 = clamp(b2, 0.0f, 2.0f); b2 = clamp(b2, 0.0, 2.0);
if (start > end)
{
swapvalues(start, end);
swapvalues(r1, r2);
swapvalues(g1, g2);
swapvalues(b1, b2);
}
r2 -= r1; r2 -= r1;
g2 -= g1; g2 -= g1;
@ -419,7 +427,7 @@ void FRemapTable::AddDesaturation(int start, int end, float r1,float g1, float b
g1 *= 255; g1 *= 255;
b1 *= 255; b1 *= 255;
for(int c = start; c < end; c++) for(int c = start; c <= end; c++)
{ {
double intensity = (GPalette.BaseColors[c].r * 77 + double intensity = (GPalette.BaseColors[c].r * 77 +
GPalette.BaseColors[c].g * 143 + GPalette.BaseColors[c].g * 143 +
@ -443,7 +451,7 @@ void FRemapTable::AddDesaturation(int start, int end, float r1,float g1, float b
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void FRemapTable::AddToTranslation(const char * range) void FRemapTable::AddToTranslation(const char *range)
{ {
int start,end; int start,end;
bool desaturated = false; bool desaturated = false;
@ -515,39 +523,39 @@ void FRemapTable::AddToTranslation(const char * range)
else if (sc.TokenType == '%') else if (sc.TokenType == '%')
{ {
// translation using RGB values // translation using RGB values
float r1,g1,b1,r2,g2,b2; double r1,g1,b1,r2,g2,b2;
sc.MustGetToken('['); sc.MustGetToken('[');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
r1 = float(sc.Float); r1 = sc.Float;
sc.MustGetToken(','); sc.MustGetToken(',');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
g1 = float(sc.Float); g1 = sc.Float;
sc.MustGetToken(','); sc.MustGetToken(',');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
b1 = float(sc.Float); b1 = sc.Float;
sc.MustGetToken(']'); sc.MustGetToken(']');
sc.MustGetToken(':'); sc.MustGetToken(':');
sc.MustGetToken('['); sc.MustGetToken('[');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
r2 = float(sc.Float); r2 = sc.Float;
sc.MustGetToken(','); sc.MustGetToken(',');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
g2 = float(sc.Float); g2 = sc.Float;
sc.MustGetToken(','); sc.MustGetToken(',');
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst);
b2 = float(sc.Float); b2 = sc.Float;
sc.MustGetToken(']'); sc.MustGetToken(']');
AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); AddDesaturation(start, end, r1, g1, b1, r2, g2, b2);

View file

@ -38,7 +38,7 @@ struct FRemapTable
void Serialize(FArchive &ar); void Serialize(FArchive &ar);
void AddIndexRange(int start, int end, int pal1, int pal2); void AddIndexRange(int start, int end, int pal1, int pal2);
void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2);
void AddDesaturation(int start, int end, float r1,float g1, float b1, float r2, float g2, float b2); void AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2);
void AddToTranslation(const char * range); void AddToTranslation(const char * range);
int StoreTranslation(); int StoreTranslation();

View file

@ -423,6 +423,10 @@ static void R_ExtendSpriteFrames(spritedef_t &spr, int frame)
// at all, so we can tack the new frames directly on to the end // at all, so we can tack the new frames directly on to the end
// of the SpriteFrames array. // of the SpriteFrames array.
newstart = SpriteFrames.Reserve(frame - spr.numframes); newstart = SpriteFrames.Reserve(frame - spr.numframes);
if (spr.numframes == 0)
{
spr.spriteframes = WORD(newstart);
}
} }
else else
{ // We need to allocate space for all the sprite's frames and copy { // We need to allocate space for all the sprite's frames and copy
@ -439,7 +443,6 @@ static void R_ExtendSpriteFrames(spritedef_t &spr, int frame)
// Initialize all new frames to 0. // Initialize all new frames to 0.
memset(&SpriteFrames[newstart], 0, sizeof(spriteframe_t)*(frame - spr.numframes)); memset(&SpriteFrames[newstart], 0, sizeof(spriteframe_t)*(frame - spr.numframes));
spr.numframes = frame; spr.numframes = frame;
spr.spriteframes = newstart;
} }
//========================================================================== //==========================================================================

View file

@ -71,7 +71,7 @@ TDeletingArray<FVoxelDef *> VoxelDefs;
struct VoxelOptions struct VoxelOptions
{ {
VoxelOptions() VoxelOptions()
: DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(0) : DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(ANGLE_90)
{} {}
int DroppedSpin; int DroppedSpin;
@ -332,7 +332,7 @@ FVoxelDef *R_LoadVoxelDef(int lumpnum, int spin)
voxdef->Voxel = vox; voxdef->Voxel = vox;
voxdef->Scale = FRACUNIT; voxdef->Scale = FRACUNIT;
voxdef->DroppedSpin = voxdef->PlacedSpin = spin; voxdef->DroppedSpin = voxdef->PlacedSpin = spin;
voxdef->AngleOffset = 0; voxdef->AngleOffset = ANGLE_90;
Voxels.Push(vox); Voxels.Push(vox);
VoxelDefs.Push(voxdef); VoxelDefs.Push(voxdef);
@ -508,7 +508,7 @@ static void VOX_ReadOptions(FScanner &sc, VoxelOptions &opts)
{ {
sc.TokenMustBe(TK_FloatConst); sc.TokenMustBe(TK_FloatConst);
} }
opts.AngleOffset = angle_t(sc.Float * ANGLE_180 / 180.0); opts.AngleOffset = ANGLE_90 + angle_t(sc.Float * ANGLE_180 / 180.0);
} }
else else
{ {

View file

@ -38,8 +38,8 @@
#include "dthinker.h" #include "dthinker.h"
#define MAXWIDTH 2880 #define MAXWIDTH 5760
#define MAXHEIGHT 1800 #define MAXHEIGHT 3600
const WORD NO_INDEX = 0xffffu; const WORD NO_INDEX = 0xffffu;
const DWORD NO_SIDE = 0xffffffffu; const DWORD NO_SIDE = 0xffffffffu;
@ -832,11 +832,11 @@ struct side_t
void SetTextureXScale(int which, fixed_t scale) void SetTextureXScale(int which, fixed_t scale)
{ {
textures[which].xscale = scale <= 0? FRACUNIT : scale; textures[which].xscale = scale == 0 ? FRACUNIT : scale;
} }
void SetTextureXScale(fixed_t scale) void SetTextureXScale(fixed_t scale)
{ {
textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale <= 0? FRACUNIT : scale; textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale;
} }
fixed_t GetTextureXScale(int which) const fixed_t GetTextureXScale(int which) const
{ {
@ -850,11 +850,11 @@ struct side_t
void SetTextureYScale(int which, fixed_t scale) void SetTextureYScale(int which, fixed_t scale)
{ {
textures[which].yscale = scale <= 0? FRACUNIT : scale; textures[which].yscale = scale == 0 ? FRACUNIT : scale;
} }
void SetTextureYScale(fixed_t scale) void SetTextureYScale(fixed_t scale)
{ {
textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale <= 0? FRACUNIT : scale; textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale;
} }
fixed_t GetTextureYScale(int which) const fixed_t GetTextureYScale(int which) const
{ {

View file

@ -79,6 +79,8 @@ void (*R_DrawSpan)(void);
void (*R_DrawSpanMasked)(void); void (*R_DrawSpanMasked)(void);
void (*R_DrawSpanTranslucent)(void); void (*R_DrawSpanTranslucent)(void);
void (*R_DrawSpanMaskedTranslucent)(void); void (*R_DrawSpanMaskedTranslucent)(void);
void (*R_DrawSpanAddClamp)(void);
void (*R_DrawSpanMaskedAddClamp)(void);
void (STACK_ARGS *rt_map4cols)(int,int,int); void (STACK_ARGS *rt_map4cols)(int,int,int);
// //
@ -1324,6 +1326,152 @@ void R_DrawSpanMaskedTranslucentP_C (void)
} }
} }
void R_DrawSpanAddClampP_C (void)
{
dsfixed_t xfrac;
dsfixed_t yfrac;
dsfixed_t xstep;
dsfixed_t ystep;
BYTE* dest;
const BYTE* source = ds_source;
const BYTE* colormap = ds_colormap;
int count;
int spot;
DWORD *fg2rgb = dc_srcblend;
DWORD *bg2rgb = dc_destblend;
xfrac = ds_xfrac;
yfrac = ds_yfrac;
dest = ylookup[ds_y] + ds_x1 + dc_destorg;
count = ds_x2 - ds_x1 + 1;
xstep = ds_xstep;
ystep = ds_ystep;
if (ds_xbits == 6 && ds_ybits == 6)
{
// 64x64 is the most common case by far, so special case it.
do
{
spot = ((xfrac>>(32-6-6))&(63*64)) + (yfrac>>(32-6));
DWORD a = fg2rgb[colormap[source[spot]]] + bg2rgb[*dest];
DWORD b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
*dest++ = RGB32k[0][0][a & (a>>15)];
xfrac += xstep;
yfrac += ystep;
} while (--count);
}
else
{
BYTE yshift = 32 - ds_ybits;
BYTE xshift = yshift - ds_xbits;
int xmask = ((1 << ds_xbits) - 1) << ds_ybits;
do
{
spot = ((xfrac >> xshift) & xmask) + (yfrac >> yshift);
DWORD a = fg2rgb[colormap[source[spot]]] + bg2rgb[*dest];
DWORD b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
*dest++ = RGB32k[0][0][a & (a>>15)];
xfrac += xstep;
yfrac += ystep;
} while (--count);
}
}
void R_DrawSpanMaskedAddClampP_C (void)
{
dsfixed_t xfrac;
dsfixed_t yfrac;
dsfixed_t xstep;
dsfixed_t ystep;
BYTE* dest;
const BYTE* source = ds_source;
const BYTE* colormap = ds_colormap;
int count;
int spot;
DWORD *fg2rgb = dc_srcblend;
DWORD *bg2rgb = dc_destblend;
xfrac = ds_xfrac;
yfrac = ds_yfrac;
dest = ylookup[ds_y] + ds_x1 + dc_destorg;
count = ds_x2 - ds_x1 + 1;
xstep = ds_xstep;
ystep = ds_ystep;
if (ds_xbits == 6 && ds_ybits == 6)
{
// 64x64 is the most common case by far, so special case it.
do
{
BYTE texdata;
spot = ((xfrac>>(32-6-6))&(63*64)) + (yfrac>>(32-6));
texdata = source[spot];
if (texdata != 0)
{
DWORD a = fg2rgb[colormap[texdata]] + bg2rgb[*dest];
DWORD b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
*dest = RGB32k[0][0][a & (a>>15)];
}
dest++;
xfrac += xstep;
yfrac += ystep;
} while (--count);
}
else
{
BYTE yshift = 32 - ds_ybits;
BYTE xshift = yshift - ds_xbits;
int xmask = ((1 << ds_xbits) - 1) << ds_ybits;
do
{
BYTE texdata;
spot = ((xfrac >> xshift) & xmask) + (yfrac >> yshift);
texdata = source[spot];
if (texdata != 0)
{
DWORD a = fg2rgb[colormap[texdata]] + bg2rgb[*dest];
DWORD b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
*dest = RGB32k[0][0][a & (a>>15)];
}
dest++;
xfrac += xstep;
yfrac += ystep;
} while (--count);
}
}
// [RH] Just fill a span with a color // [RH] Just fill a span with a color
void R_FillSpan (void) void R_FillSpan (void)
{ {
@ -2005,6 +2153,14 @@ void tmvline4_revsubclamp ()
const BYTE *R_GetColumn (FTexture *tex, int col) const BYTE *R_GetColumn (FTexture *tex, int col)
{ {
int width;
// If the texture's width isn't a power of 2, then we need to make it a
// positive offset for proper clamping.
if (col < 0 && (width = tex->GetWidth()) != (1 << tex->WidthBits))
{
col = width + (col % width);
}
return tex->GetColumn (col, NULL); return tex->GetColumn (col, NULL);
} }
@ -2040,6 +2196,8 @@ void R_InitColumnDrawers ()
#endif #endif
R_DrawSpanTranslucent = R_DrawSpanTranslucentP_C; R_DrawSpanTranslucent = R_DrawSpanTranslucentP_C;
R_DrawSpanMaskedTranslucent = R_DrawSpanMaskedTranslucentP_C; R_DrawSpanMaskedTranslucent = R_DrawSpanMaskedTranslucentP_C;
R_DrawSpanAddClamp = R_DrawSpanAddClampP_C;
R_DrawSpanMaskedAddClamp = R_DrawSpanMaskedAddClampP_C;
} }
// [RH] Choose column drawers in a single place // [RH] Choose column drawers in a single place

View file

@ -106,6 +106,12 @@ extern void (*R_DrawSpanTranslucent)(void);
// Span drawing for masked, translucent textures. // Span drawing for masked, translucent textures.
extern void (*R_DrawSpanMaskedTranslucent)(void); extern void (*R_DrawSpanMaskedTranslucent)(void);
// Span drawing for translucent, additive textures.
extern void (*R_DrawSpanAddClamp)(void);
// Span drawing for masked, translucent, additive textures.
extern void (*R_DrawSpanMaskedAddClamp)(void);
// [RH] Span blit into an interleaved intermediate buffer // [RH] Span blit into an interleaved intermediate buffer
extern void (*R_DrawColumnHoriz)(void); extern void (*R_DrawColumnHoriz)(void);
void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans); void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans);

View file

@ -596,7 +596,6 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
else sky = 0; // not skyflatnum so it can't be a sky else sky = 0; // not skyflatnum so it can't be a sky
skybox = NULL; skybox = NULL;
alpha = FRACUNIT; alpha = FRACUNIT;
additive = false;
} }
// New visplane algorithm uses hash table -- killough // New visplane algorithm uses hash table -- killough
@ -1047,7 +1046,7 @@ void R_DrawHeightPlanes(fixed_t height)
viewy = pl->viewy; viewy = pl->viewy;
viewangle = pl->viewangle; viewangle = pl->viewangle;
MirrorFlags = pl->MirrorFlags; MirrorFlags = pl->MirrorFlags;
R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, false, true); R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, pl->Additive, true);
} }
} }
} }
@ -1528,16 +1527,24 @@ void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske
else else
plane_shade = true; plane_shade = true;
// Additive not supported yet because the drawer function doesn't look like it can handle it.
if (spanfunc != R_FillSpan) if (spanfunc != R_FillSpan)
{ {
if (masked) if (masked)
{ {
if (alpha < OPAQUE) if (alpha < OPAQUE || additive)
{ {
spanfunc = R_DrawSpanMaskedTranslucent; if (!additive)
dc_srcblend = Col2RGB8[alpha>>10]; {
dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10]; spanfunc = R_DrawSpanMaskedTranslucent;
dc_srcblend = Col2RGB8[alpha>>10];
dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10];
}
else
{
spanfunc = R_DrawSpanMaskedAddClamp;
dc_srcblend = Col2RGB8_LessPrecision[alpha>>10];
dc_destblend = Col2RGB8_LessPrecision[FRACUNIT>>10];
}
} }
else else
{ {
@ -1546,11 +1553,20 @@ void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske
} }
else else
{ {
if (alpha < OPAQUE) if (alpha < OPAQUE || additive)
{ {
spanfunc = R_DrawSpanTranslucent; if (!additive)
dc_srcblend = Col2RGB8[alpha>>10]; {
dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10]; spanfunc = R_DrawSpanTranslucent;
dc_srcblend = Col2RGB8[alpha>>10];
dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10];
}
else
{
spanfunc = R_DrawSpanAddClamp;
dc_srcblend = Col2RGB8_LessPrecision[alpha>>10];
dc_destblend = Col2RGB8_LessPrecision[FRACUNIT>>10];
}
} }
else else
{ {

View file

@ -1965,7 +1965,7 @@ void R_NewWall (bool needlights)
} }
if (midtexture->bWorldPanning) if (midtexture->bWorldPanning)
{ {
rw_midtexturemid = MulScale16(rowoffset, yrepeat); rw_midtexturemid += MulScale16(rowoffset, yrepeat);
} }
else else
{ {
@ -2769,6 +2769,7 @@ int WallMost (short *mostbuf, const secplane_t &plane)
static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat) static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat)
{ {
// fix for rounding errors // fix for rounding errors
walxrepeat = abs(walxrepeat);
fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0; fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
int x; int x;
@ -2803,7 +2804,7 @@ static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat)
void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat) void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
{ // swall = scale, lwall = texturecolumn { // swall = scale, lwall = texturecolumn
double top, bot, i; double top, bot, i;
double xrepeat = walxrepeat; double xrepeat = fabs((double)walxrepeat);
i = WallSX1 - centerx; i = WallSX1 - centerx;
top = WallUoverZorg + WallUoverZstep * i; top = WallUoverZorg + WallUoverZstep * i;
@ -2812,7 +2813,14 @@ void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
for (int x = WallSX1; x < WallSX2; x++) for (int x = WallSX1; x < WallSX2; x++)
{ {
double frac = top / bot; double frac = top / bot;
lwall[x] = xs_RoundToInt(frac * xrepeat); if (walxrepeat < 0)
{
lwall[x] = xs_RoundToInt(xrepeat - frac * xrepeat);
}
else
{
lwall[x] = xs_RoundToInt(frac * xrepeat);
}
swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg); swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg);
top += WallUoverZstep; top += WallUoverZstep;
bot += WallInvZstep; bot += WallInvZstep;
@ -2823,7 +2831,7 @@ void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat)
void PrepLWall (fixed_t *lwall, fixed_t walxrepeat) void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
{ // lwall = texturecolumn { // lwall = texturecolumn
double top, bot, i; double top, bot, i;
double xrepeat = walxrepeat; double xrepeat = fabs((double)walxrepeat);
double topstep; double topstep;
i = WallSX1 - centerx; i = WallSX1 - centerx;
@ -2835,7 +2843,14 @@ void PrepLWall (fixed_t *lwall, fixed_t walxrepeat)
for (int x = WallSX1; x < WallSX2; x++) for (int x = WallSX1; x < WallSX2; x++)
{ {
lwall[x] = xs_RoundToInt(top / bot); if (walxrepeat < 0)
{
lwall[x] = xs_RoundToInt(xrepeat - top / bot);
}
else
{
lwall[x] = xs_RoundToInt(top / bot);
}
top += topstep; top += topstep;
bot += WallInvZstep; bot += WallInvZstep;
} }

View file

@ -514,13 +514,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
// [RH] Interpolate the sprite's position to make it look smooth // [RH] Interpolate the sprite's position to make it look smooth
fx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX); fx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX);
fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY); fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY);
fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ); fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ) + thing->GetBobOffset(r_TicFrac);
// [RH] Make floatbobbing a renderer-only effect.
if (thing->flags2 & MF2_FLOATBOB)
{
fz += finesine[(Scale(thing->FloatBobPhase + level.maptime, FINEANGLES, 64) + r_TicFrac * ((FINEANGLES/64) / 1000)) & FINEMASK] * 8;
}
// transform the origin point // transform the origin point
tr_x = fx - viewx; tr_x = fx - viewx;

View file

@ -100,6 +100,7 @@ public:
void AddSound (int player_sound_id, int sfx_id); void AddSound (int player_sound_id, int sfx_id);
int LookupSound (int player_sound_id); int LookupSound (int player_sound_id);
FPlayerSoundHashTable &operator= (const FPlayerSoundHashTable &other); FPlayerSoundHashTable &operator= (const FPlayerSoundHashTable &other);
void MarkUsed();
protected: protected:
struct Entry struct Entry
@ -122,7 +123,7 @@ struct FAmbientSound
int periodmax; // max # of tics for random ambients int periodmax; // max # of tics for random ambients
float volume; // relative volume of sound float volume; // relative volume of sound
float attenuation; float attenuation;
FString sound; // Logical name of sound to play FSoundID sound; // Sound to play
}; };
TMap<int, FAmbientSound> Ambients; TMap<int, FAmbientSound> Ambients;
@ -219,6 +220,7 @@ extern int sfx_empty;
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
TArray<sfxinfo_t> S_sfx (128); TArray<sfxinfo_t> S_sfx (128);
TMap<int, FString> HexenMusic;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -830,6 +832,25 @@ int FPlayerSoundHashTable::LookupSound (int player_sound_id)
return entry != NULL ? entry->SfxID : 0; return entry != NULL ? entry->SfxID : 0;
} }
//==========================================================================
//
// FPlayerSoundHashTable :: Mark
//
// Marks all sounds defined for this class/gender as used.
//
//==========================================================================
void FPlayerSoundHashTable::MarkUsed()
{
for (size_t i = 0; i < NUM_BUCKETS; ++i)
{
for (Entry *probe = Buckets[i]; probe != NULL; probe = probe->Next)
{
S_sfx[probe->SfxID].bUsed = true;
}
}
}
//========================================================================== //==========================================================================
// //
// S_ClearSoundData // S_ClearSoundData
@ -866,6 +887,7 @@ static void S_ClearSoundData()
DefPlayerClassName = ""; DefPlayerClassName = "";
MusicAliases.Clear(); MusicAliases.Clear();
MidiDevices.Clear(); MidiDevices.Clear();
HexenMusic.Clear();
} }
//========================================================================== //==========================================================================
@ -984,10 +1006,10 @@ static void S_AddSNDINFO (int lump)
ambient->periodmax = 0; ambient->periodmax = 0;
ambient->volume = 0; ambient->volume = 0;
ambient->attenuation = 0; ambient->attenuation = 0;
ambient->sound = ""; ambient->sound = 0;
sc.MustGetString (); sc.MustGetString ();
ambient->sound = sc.String; ambient->sound = FSoundID(S_FindSoundTentative(sc.String));
ambient->attenuation = 0; ambient->attenuation = 0;
sc.MustGetString (); sc.MustGetString ();
@ -1064,16 +1086,14 @@ static void S_AddSNDINFO (int lump)
case SI_Map: { case SI_Map: {
// Hexen-style $MAP command // Hexen-style $MAP command
level_info_t *info; int mapnum;
char temp[16];
sc.MustGetNumber (); sc.MustGetNumber();
mysnprintf (temp, countof(temp), "MAP%02d", sc.Number); mapnum = sc.Number;
info = FindLevelInfo (temp); sc.MustGetString();
sc.MustGetString (); if (mapnum != 0)
if (info->mapname[0] && (!(info->flags2 & LEVEL2_MUSICDEFINED)))
{ {
info->Music = sc.String; HexenMusic[mapnum] = sc.String;
} }
} }
break; break;
@ -1899,6 +1919,44 @@ bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time)
return true; return true;
} }
//==========================================================================
//
// sfxinfo_t :: MarkUsed
//
// Marks this sound for precaching.
//
//==========================================================================
void sfxinfo_t::MarkUsed()
{
bUsed = true;
}
//==========================================================================
//
// S_MarkPlayerSounds
//
// Marks all sounds from a particular player class for precaching.
//
//==========================================================================
void S_MarkPlayerSounds (const char *playerclass)
{
int classidx = S_FindPlayerClass(playerclass);
if (classidx < 0)
{
classidx = DefPlayerClass;
}
for (int g = 0; g < 3; ++g)
{
int listidx = PlayerClassLookups[classidx].ListIndex[0];
if (listidx != 0xffff)
{
PlayerSounds[listidx].MarkUsed();
}
}
}
//========================================================================== //==========================================================================
// //
// CCMD soundlist // CCMD soundlist
@ -2014,6 +2072,7 @@ class AAmbientSound : public AActor
public: public:
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void MarkPrecacheSounds () const;
void BeginPlay (); void BeginPlay ();
void Tick (); void Tick ();
void Activate (AActor *activator); void Activate (AActor *activator);
@ -2040,6 +2099,22 @@ void AAmbientSound::Serialize (FArchive &arc)
arc << bActive << NextCheck; arc << bActive << NextCheck;
} }
//==========================================================================
//
// AmbientSound :: MarkPrecacheSounds
//
//==========================================================================
void AAmbientSound::MarkPrecacheSounds() const
{
Super::MarkPrecacheSounds();
FAmbientSound *ambient = Ambients.CheckKey(args[0]);
if (ambient != NULL)
{
ambient->sound.MarkUsed();
}
}
//========================================================================== //==========================================================================
// //
// AmbientSound :: Tick // AmbientSound :: Tick
@ -2067,7 +2142,7 @@ void AAmbientSound::Tick ()
loop = CHAN_LOOP; loop = CHAN_LOOP;
} }
if (ambient->sound.IsNotEmpty()) if (ambient->sound != 0)
{ {
// The second argument scales the ambient sound's volume. // The second argument scales the ambient sound's volume.
// 0 and 100 are normal volume. The maximum volume level // 0 and 100 are normal volume. The maximum volume level

View file

@ -760,7 +760,7 @@ static void AddSequence (int curseq, FName seqname, FName slot, int stopsound, c
Sequences[curseq] = (FSoundSequence *)M_Malloc (sizeof(FSoundSequence) + sizeof(DWORD)*ScriptTemp.Size()); Sequences[curseq] = (FSoundSequence *)M_Malloc (sizeof(FSoundSequence) + sizeof(DWORD)*ScriptTemp.Size());
Sequences[curseq]->SeqName = seqname; Sequences[curseq]->SeqName = seqname;
Sequences[curseq]->Slot = slot; Sequences[curseq]->Slot = slot;
Sequences[curseq]->StopSound = stopsound; Sequences[curseq]->StopSound = FSoundID(stopsound);
memcpy (Sequences[curseq]->Script, &ScriptTemp[0], sizeof(DWORD)*ScriptTemp.Size()); memcpy (Sequences[curseq]->Script, &ScriptTemp[0], sizeof(DWORD)*ScriptTemp.Size());
Sequences[curseq]->Script[ScriptTemp.Size()] = MakeCommand(SS_CMD_END, 0); Sequences[curseq]->Script[ScriptTemp.Size()] = MakeCommand(SS_CMD_END, 0);
} }
@ -1311,6 +1311,32 @@ FName SN_GetSequenceSlot (int sequence, seqtype_t type)
return NAME_None; return NAME_None;
} }
//==========================================================================
//
// SN_MarkPrecacheSounds
//
// Marks all sounds played by this sequence for precaching.
//
//==========================================================================
void SN_MarkPrecacheSounds(int sequence, seqtype_t type)
{
if (TwiddleSeqNum(sequence, type))
{
FSoundSequence *seq = Sequences[sequence];
seq->StopSound.MarkUsed();
for (int i = 0; GetCommand(seq->Script[i]) != SS_CMD_END; ++i)
{
int cmd = GetCommand(seq->Script[i]);
if (cmd == SS_CMD_PLAY || cmd == SS_CMD_PLAYREPEAT || cmd == SS_CMD_PLAYLOOP)
{
FSoundID(GetData(seq->Script[i])).MarkUsed();
}
}
}
}
//========================================================================== //==========================================================================
// //
// SN_ChangeNodeData // SN_ChangeNodeData

View file

@ -71,10 +71,10 @@ void SN_StopAllSequences (void);
struct FSoundSequence struct FSoundSequence
{ {
FName SeqName; FName SeqName;
FName Slot; FName Slot;
int StopSound; FSoundID StopSound;
SDWORD Script[1]; // + more until end of sequence script SDWORD Script[1]; // + more until end of sequence script
}; };
void S_ParseSndSeq (int levellump); void S_ParseSndSeq (int levellump);
@ -98,6 +98,7 @@ void SN_DoStop (void *);
void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics,
float volume, int currentSoundID); float volume, int currentSoundID);
FName SN_GetSequenceSlot (int sequence, seqtype_t type); FName SN_GetSequenceSlot (int sequence, seqtype_t type);
void SN_MarkPrecacheSounds (int sequence, seqtype_t type);
bool SN_IsMakingLoopingSound (sector_t *sector); bool SN_IsMakingLoopingSound (sector_t *sector);
#endif //__S_SNDSEQ_H__ #endif //__S_SNDSEQ_H__

View file

@ -326,7 +326,6 @@ void S_InitData ()
LastLocalSndInfo = LastLocalSndSeq = ""; LastLocalSndInfo = LastLocalSndSeq = "";
S_ParseSndInfo (false); S_ParseSndInfo (false);
S_ParseSndSeq (-1); S_ParseSndSeq (-1);
S_ParseMusInfo();
} }
//========================================================================== //==========================================================================
@ -477,14 +476,15 @@ void S_PrecacheLevel ()
AActor *actor; AActor *actor;
TThinkerIterator<AActor> iterator; TThinkerIterator<AActor> iterator;
while ( (actor = iterator.Next ()) != NULL ) // Precache all sounds known to be used by the currently spawned actors.
while ( (actor = iterator.Next()) != NULL )
{ {
S_sfx[actor->SeeSound].bUsed = true; actor->MarkPrecacheSounds();
S_sfx[actor->AttackSound].bUsed = true; }
S_sfx[actor->PainSound].bUsed = true; // Precache all extra sounds requested by this map.
S_sfx[actor->DeathSound].bUsed = true; for (i = 0; i < level.info->PrecacheSounds.Size(); ++i)
S_sfx[actor->ActiveSound].bUsed = true; {
S_sfx[actor->UseSound].bUsed = true; level.info->PrecacheSounds[i].MarkUsed();
} }
for (i = 1; i < S_sfx.Size(); ++i) for (i = 1; i < S_sfx.Size(); ++i)
@ -1764,7 +1764,7 @@ void S_SetSoundPaused (int state)
S_ResumeSound(true); S_ResumeSound(true);
if (GSnd != NULL) if (GSnd != NULL)
{ {
GSnd->SetInactive(false); GSnd->SetInactive(SoundRenderer::INACTIVE_Active);
} }
if (!netgame if (!netgame
#ifdef _DEBUG #ifdef _DEBUG
@ -1783,7 +1783,9 @@ void S_SetSoundPaused (int state)
S_PauseSound(false, true); S_PauseSound(false, true);
if (GSnd != NULL) if (GSnd != NULL)
{ {
GSnd->SetInactive(true); GSnd->SetInactive(gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL ?
SoundRenderer::INACTIVE_Complete :
SoundRenderer::INACTIVE_Mute);
} }
if (!netgame if (!netgame
#ifdef _DEBUG #ifdef _DEBUG

View file

@ -65,6 +65,8 @@ struct sfxinfo_t
FRolloffInfo Rolloff; FRolloffInfo Rolloff;
float Attenuation; // Multiplies the attenuation passed to S_Sound. float Attenuation; // Multiplies the attenuation passed to S_Sound.
void MarkUsed(); // Marks this sound as used.
}; };
// Rolloff types // Rolloff types
@ -132,6 +134,10 @@ public:
{ {
return ID ? S_sfx[ID].name.GetChars() : NULL; return ID ? S_sfx[ID].name.GetChars() : NULL;
} }
void MarkUsed() const
{
S_sfx[ID].MarkUsed();
}
private: private:
int ID; int ID;
protected: protected:
@ -351,6 +357,7 @@ int S_AddSoundLump (const char *logicalname, int lump); // Add sound by lump ind
int S_AddPlayerSound (const char *playerclass, const int gender, int refid, const char *lumpname); int S_AddPlayerSound (const char *playerclass, const int gender, int refid, const char *lumpname);
int S_AddPlayerSound (const char *playerclass, const int gender, int refid, int lumpnum, bool fromskin=false); int S_AddPlayerSound (const char *playerclass, const int gender, int refid, int lumpnum, bool fromskin=false);
int S_AddPlayerSoundExisting (const char *playerclass, const int gender, int refid, int aliasto, bool fromskin=false); int S_AddPlayerSoundExisting (const char *playerclass, const int gender, int refid, int aliasto, bool fromskin=false);
void S_MarkPlayerSounds (const char *playerclass);
void S_ShrinkPlayerSoundLists (); void S_ShrinkPlayerSoundLists ();
void S_UnloadSound (sfxinfo_t *sfx); void S_UnloadSound (sfxinfo_t *sfx);
sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); sfxinfo_t *S_LoadSound(sfxinfo_t *sfx);

View file

@ -177,6 +177,10 @@ void I_ClosestResolution (int *width, int *height, int bits)
} }
} }
void I_SetFPSLimit(int limit)
{
}
extern int NewWidth, NewHeight, NewBits, DisplayBits; extern int NewWidth, NewHeight, NewBits, DisplayBits;
CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)

View file

@ -59,6 +59,8 @@ void I_InitGraphics ();
void I_ShutdownGraphics (); void I_ShutdownGraphics ();
void I_CreateRenderer(); void I_CreateRenderer();
void I_SetFPSLimit(int limit);
extern IVideo *Video; extern IVideo *Video;
#endif // __HARDWARE_H__ #endif // __HARDWARE_H__

View file

@ -672,6 +672,7 @@ bool FMODSoundRenderer::Init()
PrevEnvironment = DefaultEnvironments[0]; PrevEnvironment = DefaultEnvironments[0];
DSPClock.AsOne = 0; DSPClock.AsOne = 0;
ChannelGroupTargetUnit = NULL; ChannelGroupTargetUnit = NULL;
ChannelGroupTargetUnitOutput = NULL;
SfxReverbHooked = false; SfxReverbHooked = false;
SfxReverbPlaceholder = NULL; SfxReverbPlaceholder = NULL;
OutputPlugin = 0; OutputPlugin = 0;
@ -1155,6 +1156,15 @@ bool FMODSoundRenderer::Init()
{ {
ChannelGroupTargetUnit = NULL; ChannelGroupTargetUnit = NULL;
} }
else
{
FMOD::DSP *dontcare;
result = ChannelGroupTargetUnit->getOutput(0, &dontcare, &ChannelGroupTargetUnitOutput);
if (result != FMOD_OK)
{
ChannelGroupTargetUnitOutput = NULL;
}
}
} }
} }
@ -1598,6 +1608,7 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
FMOD::Sound *stream; FMOD::Sound *stream;
FMOD_RESULT result; FMOD_RESULT result;
bool url; bool url;
FString patches;
InitCreateSoundExInfo(&exinfo); InitCreateSoundExInfo(&exinfo);
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
@ -1614,7 +1625,20 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
exinfo.fileoffset = offset; exinfo.fileoffset = offset;
if ((*snd_midipatchset)[0] != '\0') if ((*snd_midipatchset)[0] != '\0')
{ {
exinfo.dlsname = snd_midipatchset; #ifdef _WIN32
// If the path does not contain any path separators, automatically
// prepend $PROGDIR to the path.
if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset))
{
patches << "$PROGDIR/" << snd_midipatchset;
patches = NicePath(patches);
}
else
#endif
{
patches = NicePath(snd_midipatchset);
}
exinfo.dlsname = patches;
} }
url = (offset == 0 && length == 0 && strstr(filename_or_data, "://") > filename_or_data); url = (offset == 0 && length == 0 && strstr(filename_or_data, "://") > filename_or_data);
@ -2109,11 +2133,33 @@ void FMODSoundRenderer::SetSfxPaused(bool paused, int slot)
// //
//========================================================================== //==========================================================================
void FMODSoundRenderer::SetInactive(bool inactive) void FMODSoundRenderer::SetInactive(SoundRenderer::EInactiveState inactive)
{ {
float mix;
bool active;
if (inactive == INACTIVE_Active)
{
mix = 1;
active = true;
}
else if (inactive == INACTIVE_Complete)
{
mix = 1;
active = false;
}
else // inactive == INACTIVE_Mute
{
mix = 0;
active = true;
}
if (ChannelGroupTargetUnitOutput != NULL)
{
ChannelGroupTargetUnitOutput->setMix(mix);
}
if (ChannelGroupTargetUnit != NULL) if (ChannelGroupTargetUnit != NULL)
{ {
ChannelGroupTargetUnit->setActive(!inactive); ChannelGroupTargetUnit->setActive(active);
} }
} }

View file

@ -49,7 +49,7 @@ public:
void SetSfxPaused (bool paused, int slot); void SetSfxPaused (bool paused, int slot);
// Pauses or resumes *every* channel, including environmental reverb. // Pauses or resumes *every* channel, including environmental reverb.
void SetInactive (bool inactive); void SetInactive (EInactiveState inactive);
// Updates the position of a sound channel. // Updates the position of a sound channel.
void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel);
@ -107,6 +107,7 @@ private:
FMOD::ChannelGroup *MusicGroup; FMOD::ChannelGroup *MusicGroup;
FMOD::DSP *WaterLP, *WaterReverb; FMOD::DSP *WaterLP, *WaterReverb;
FMOD::DSPConnection *SfxConnection; FMOD::DSPConnection *SfxConnection;
FMOD::DSPConnection *ChannelGroupTargetUnitOutput;
FMOD::DSP *ChannelGroupTargetUnit; FMOD::DSP *ChannelGroupTargetUnit;
FMOD::DSP *SfxReverbPlaceholder; FMOD::DSP *SfxReverbPlaceholder;
bool SfxReverbHooked; bool SfxReverbHooked;

View file

@ -199,7 +199,7 @@ public:
} }
// Pauses or resumes *every* channel, including environmental reverb. // Pauses or resumes *every* channel, including environmental reverb.
void SetInactive(bool inactive) void SetInactive(SoundRenderer::EInactiveState inactive)
{ {
} }

View file

@ -126,7 +126,13 @@ public:
virtual void SetSfxPaused (bool paused, int slot) = 0; virtual void SetSfxPaused (bool paused, int slot) = 0;
// Pauses or resumes *every* channel, including environmental reverb. // Pauses or resumes *every* channel, including environmental reverb.
virtual void SetInactive(bool inactive) = 0; enum EInactiveState
{
INACTIVE_Active, // sound is active
INACTIVE_Complete, // sound is completely paused
INACTIVE_Mute // sound is only muted
};
virtual void SetInactive(EInactiveState inactive) = 0;
// Updates the volume, separation, and pitch of a sound channel. // Updates the volume, separation, and pitch of a sound channel.
virtual void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) = 0; virtual void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) = 0;

View file

@ -42,6 +42,7 @@
#include "m_swap.h" #include "m_swap.h"
#include "w_wad.h" #include "w_wad.h"
#include "v_text.h" #include "v_text.h"
#include "cmdlib.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -471,7 +472,21 @@ int FluidSynthMIDIDevice::LoadPatchSets(const char *patches)
count = 0; count = 0;
while (tok != NULL) while (tok != NULL)
{ {
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, tok, count == 0)) FString path;
#ifdef _WIN32
// If the path does not contain any path separators, automatically
// prepend $PROGDIR to the path.
if (strcspn(tok, ":/\\") == strlen(tok))
{
path << "$PROGDIR/" << tok;
path = NicePath(path);
}
else
#endif
{
path = NicePath(tok);
}
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, path, count == 0))
{ {
DPrintf("Loaded patch set %s.\n", tok); DPrintf("Loaded patch set %s.\n", tok);
count++; count++;

View file

@ -944,7 +944,13 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time)
if (Restarting) if (Restarting)
{ {
Restarting = false; Restarting = false;
events = WriteStopNotes(events); // Stop all notes in case any were left hanging. // Reset the tempo to the inital value.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID
events[2] = (MEVT_TEMPO << 24) | InitialTempo; // dwEvent
events += 3;
// Stop all notes in case any were left hanging.
events = WriteStopNotes(events);
DoRestart(); DoRestart();
} }
events = MakeEvents(events, max_event_p, max_time); events = MakeEvents(events, max_event_p, max_time);
@ -1130,7 +1136,7 @@ void MIDIStreamer::Precache()
void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit) void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
{ {
DWORD delay = 0; DWORD delay = 0;
BYTE running_status = 0; BYTE running_status = 255;
// Always create songs aimed at GM devices. // Always create songs aimed at GM devices.
CheckCaps(MOD_MIDIPORT); CheckCaps(MOD_MIDIPORT);
@ -1163,6 +1169,7 @@ void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
file.Push(BYTE(tempo >> 16)); file.Push(BYTE(tempo >> 16));
file.Push(BYTE(tempo >> 8)); file.Push(BYTE(tempo >> 8));
file.Push(BYTE(tempo)); file.Push(BYTE(tempo));
running_status = 255;
} }
else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG)
{ {
@ -1176,6 +1183,7 @@ void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
file.Push(MIDI_SYSEX); file.Push(MIDI_SYSEX);
WriteVarLen(file, len); WriteVarLen(file, len);
memcpy(&file[file.Reserve(len - 1)], bytes, len); memcpy(&file[file.Reserve(len - 1)], bytes, len);
running_status = 255;
} }
} }
else if (MEVT_EVENTTYPE(event[2]) == 0) else if (MEVT_EVENTTYPE(event[2]) == 0)

View file

@ -608,10 +608,11 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota
} }
else else
{ {
info.blendcolor[3] = b.a * FRACUNIT / 255; fixed_t blendalpha = b.a * FRACUNIT / 255;
info.blendcolor[0] = b.r * (FRACUNIT-info.blendcolor[3]); info.blendcolor[0] = b.r * blendalpha;
info.blendcolor[1] = b.g * (FRACUNIT-info.blendcolor[3]); info.blendcolor[1] = b.g * blendalpha;
info.blendcolor[2] = b.b * (FRACUNIT-info.blendcolor[3]); info.blendcolor[2] = b.b * blendalpha;
info.blendcolor[3] = FRACUNIT - blendalpha;
info.blend = BLEND_OVERLAY; info.blend = BLEND_OVERLAY;
} }
} }

View file

@ -197,6 +197,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
if (type->NumOwnedStates == 1) if (type->NumOwnedStates == 1)
{ {
type->OwnedStates->Tics = -1; type->OwnedStates->Tics = -1;
type->OwnedStates->TicRange = 0;
type->OwnedStates->Misc1 = 0; type->OwnedStates->Misc1 = 0;
} }
else else
@ -224,6 +225,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
else else
{ {
type->OwnedStates[i].Tics = -1; type->OwnedStates[i].Tics = -1;
type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
} }
@ -274,6 +276,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
else else
{ {
type->OwnedStates[i].Tics = -1; type->OwnedStates[i].Tics = -1;
type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
} }
@ -308,12 +311,14 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
} }
type->OwnedStates[i].NextState = &type->OwnedStates[type->NumOwnedStates-1]; type->OwnedStates[i].NextState = &type->OwnedStates[type->NumOwnedStates-1];
type->OwnedStates[i].Tics = 5; type->OwnedStates[i].Tics = 5;
type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function);
i = type->NumOwnedStates - 1; i = type->NumOwnedStates - 1;
type->OwnedStates[i].NextState = &type->OwnedStates[i]; type->OwnedStates[i].NextState = &type->OwnedStates[i];
type->OwnedStates[i].Tics = 1; type->OwnedStates[i].Tics = 1;
type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function);
bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]);
@ -672,6 +677,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray<FState> &states, FScann
} }
state.Tics = rate; state.Tics = rate;
state.TicRange = 0;
while (*token) while (*token)
{ {

View file

@ -170,7 +170,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par
// //
//========================================================================== //==========================================================================
void SetReplacement(PClassActor *info, FName replaceName) void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName)
{ {
// Check for "replaces" // Check for "replaces"
if (replaceName != NAME_None) if (replaceName != NAME_None)
@ -180,7 +180,8 @@ void SetReplacement(PClassActor *info, FName replaceName)
if (replacee == NULL) if (replacee == NULL)
{ {
I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), info->TypeName.GetChars()); sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->TypeName.GetChars());
return;
} }
if (replacee != NULL) if (replacee != NULL)
{ {

View file

@ -211,7 +211,7 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name);
//========================================================================== //==========================================================================
PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native);
void SetReplacement(PClassActor *info, FName replaceName); void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName);
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);
void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag);

View file

@ -355,9 +355,9 @@ static void DoAttack (AActor *self, bool domelee, bool domissile,
else if (domissile && MissileType != NULL) else if (domissile && MissileType != NULL)
{ {
// This seemingly senseless code is needed for proper aiming. // This seemingly senseless code is needed for proper aiming.
self->z += MissileHeight - 32*FRACUNIT; self->z += MissileHeight + self->GetBobOffset() - 32*FRACUNIT;
AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, MissileType, false); AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, MissileType, false);
self->z -= MissileHeight - 32*FRACUNIT; self->z -= MissileHeight + self->GetBobOffset() - 32*FRACUNIT;
if (missile) if (missile)
{ {
@ -663,6 +663,42 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower)
return numret; return numret;
} }
//==========================================================================
//
// State jump function
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange)
{
PARAM_ACTION_PROLOGUE;
PARAM_STATE(jump);
if (!self->CheckMeleeRange())
{
ACTION_JUMP(jump);
}
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
return numret;
}
//==========================================================================
//
// State jump function
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange)
{
PARAM_ACTION_PROLOGUE;
PARAM_STATE(jump);
if (self->CheckMeleeRange())
{
ACTION_JUMP(jump);
}
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
return numret;
}
//========================================================================== //==========================================================================
// //
// State jump function // State jump function
@ -799,12 +835,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType)
// //
//========================================================================== //==========================================================================
enum
{
XF_HURTSOURCE = 1,
XF_NOTMISSILE = 4,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT (damage) { damage = -1; } PARAM_INT_OPT (damage) { damage = -1; }
PARAM_INT_OPT (distance) { distance = -1; } PARAM_INT_OPT (distance) { distance = -1; }
PARAM_BOOL_OPT (hurtSource) { hurtSource = true; } PARAM_INT_OPT (flags) { flags = XF_HURTSOURCE; }
PARAM_BOOL_OPT (alert) { alert = false; } PARAM_BOOL_OPT (alert) { alert = false; }
PARAM_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; } PARAM_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; }
PARAM_INT_OPT (nails) { nails = 0; } PARAM_INT_OPT (nails) { nails = 0; }
@ -815,11 +857,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
{ {
damage = self->GetClass()->ExplosionDamage; damage = self->GetClass()->ExplosionDamage;
distance = self->GetClass()->ExplosionRadius; distance = self->GetClass()->ExplosionRadius;
if (distance < 0) flags = !self->GetClass()->DontHurtShooter;
{
distance = damage;
}
hurtSource = !self->GetClass()->DontHurtShooter;
alert = false; alert = false;
} }
else else
@ -842,7 +880,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
} }
} }
P_RadiusAttack (self, self->target, damage, distance, self->DamageType, hurtSource, true, fulldmgdistance); P_RadiusAttack (self, self->target, damage, distance, self->DamageType, flags, fulldmgdistance);
P_CheckSplash(self, distance<<FRACBITS); P_CheckSplash(self, distance<<FRACBITS);
if (alert && self->target != NULL && self->target->player != NULL) if (alert && self->target != NULL && self->target->player != NULL)
{ {
@ -852,43 +890,41 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
return 0; return 0;
} }
enum
{
RTF_AFFECTSOURCE = 1,
RTF_NOIMPACTDAMAGE = 2,
};
//========================================================================== //==========================================================================
// //
// A_RadiusThrust // A_RadiusThrust
// //
//========================================================================== //==========================================================================
enum
{
RTF_AFFECTSOURCE = 1,
RTF_NOIMPACTDAMAGE = 2,
RTF_NOTMISSILE = 4,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT (force) { force = 128; } PARAM_INT_OPT (force) { force = 128; }
PARAM_INT_OPT (distance) { distance = -1; } PARAM_INT_OPT (distance) { distance = -1; }
PARAM_INT_OPT (thrustFlags) { thrustFlags = RTF_AFFECTSOURCE; } PARAM_INT_OPT (flags) { flags = RTF_AFFECTSOURCE; }
PARAM_INT_OPT (fullthrustdistance) { fullthrustdistance = 0; } PARAM_INT_OPT (fullthrustdistance) { fullthrustdistance = 0; }
bool affectSource = !!(thrustFlags & RTF_AFFECTSOURCE);
bool noimpactdamage = !!(thrustFlags & RTF_NOIMPACTDAMAGE);
bool sourcenothrust = false; bool sourcenothrust = false;
if (force <= 0) force = 128; if (force <= 0) force = 128;
if (distance <= 0) distance = force; if (distance <= 0) distance = force;
// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless. // Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
if (self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST) if (!(flags & RTF_NOTMISSILE) && self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST)
{ {
sourcenothrust = true; sourcenothrust = true;
self->target->flags2 &= ~MF2_NODMGTHRUST; self->target->flags2 &= ~MF2_NODMGTHRUST;
} }
int sourceflags2 = self->target != NULL ? self->target->flags2 : 0; int sourceflags2 = self->target != NULL ? self->target->flags2 : 0;
P_RadiusAttack (self, self->target, force, distance, self->DamageType, affectSource, false, fullthrustdistance, noimpactdamage); P_RadiusAttack (self, self->target, force, distance, self->DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
P_CheckSplash(self, distance << FRACBITS); P_CheckSplash(self, distance << FRACBITS);
if (sourcenothrust) if (sourcenothrust)
@ -959,7 +995,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT;
fixed_t x = spawnofs_xy * finecosine[ang]; fixed_t x = spawnofs_xy * finecosine[ang];
fixed_t y = spawnofs_xy * finesine[ang]; fixed_t y = spawnofs_xy * finesine[ang];
fixed_t z = spawnheight - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0); fixed_t z = spawnheight + self->GetBobOffset() - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0);
switch (aimmode) switch (aimmode)
{ {
@ -976,14 +1012,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
break; break;
case 1: case 1:
missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z+spawnheight, self, self->target, ti, false); missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z + self->GetBobOffset() + spawnheight, self, self->target, ti, false);
break; break;
case 2: case 2:
self->x += x; self->x += x;
self->y += y; self->y += y;
missile = P_SpawnMissileAngleZSpeed(self, self->z+spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); missile = P_SpawnMissileAngleZSpeed(self, self->z + self->GetBobOffset() + spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false);
self->x -= x; self->x -= x;
self->y -= y; self->y -= y;
flags |= CMF_ABSOLUTEPITCH; flags |= CMF_ABSOLUTEPITCH;
@ -1210,9 +1246,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack)
else if (ti) else if (ti)
{ {
// This seemingly senseless code is needed for proper aiming. // This seemingly senseless code is needed for proper aiming.
self->z += spawnheight - 32*FRACUNIT; self->z += spawnheight + self->GetBobOffset() - 32*FRACUNIT;
AActor *missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false);
self->z -= spawnheight - 32*FRACUNIT; self->z -= spawnheight + self->GetBobOffset() - 32*FRACUNIT;
if (missile) if (missile)
{ {
@ -1951,7 +1987,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem)
AActor *mo = Spawn(missile, AActor *mo = Spawn(missile,
self->x + FixedMul(distance, finecosine[self->angle>>ANGLETOFINESHIFT]), self->x + FixedMul(distance, finecosine[self->angle>>ANGLETOFINESHIFT]),
self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]), self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]),
self->z - self->floorclip + zheight, ALLOW_REPLACE); self->z - self->floorclip + self->GetBobOffset() + zheight, ALLOW_REPLACE);
int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0);
bool res = InitSpawnedItem(self, mo, flags); bool res = InitSpawnedItem(self, mo, flags);
@ -2024,7 +2060,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx)
xvel = newxvel; xvel = newxvel;
} }
AActor *mo = Spawn(missile, x, y, self->z - self->floorclip + zofs, ALLOW_REPLACE); AActor * mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE);
bool res = InitSpawnedItem(self, mo, flags); bool res = InitSpawnedItem(self, mo, flags);
ACTION_SET_RESULT(res); // for an inventory item's use state ACTION_SET_RESULT(res); // for an inventory item's use state
if (mo) if (mo)
@ -2073,7 +2109,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade)
AActor *bo; AActor *bo;
bo = Spawn(missile, self->x, self->y, bo = Spawn(missile, self->x, self->y,
self->z - self->floorclip + zheight + 35*FRACUNIT + (self->player ? self->player->crouchoffset : 0), self->z - self->floorclip + self->GetBobOffset() + zheight + 35*FRACUNIT + (self->player? self->player->crouchoffset : 0),
ALLOW_REPLACE); ALLOW_REPLACE);
if (bo) if (bo)
{ {
@ -2435,7 +2471,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris)
{ {
mo = Spawn(debris, self->x+((pr_spawndebris()-128)<<12), mo = Spawn(debris, self->x+((pr_spawndebris()-128)<<12),
self->y+((pr_spawndebris()-128)<<12), self->y+((pr_spawndebris()-128)<<12),
self->z+(pr_spawndebris()*self->height/256), ALLOW_REPLACE); self->z+(pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE);
if (mo && transfer_translation) if (mo && transfer_translation)
{ {
mo->Translation = self->Translation; mo->Translation = self->Translation;
@ -2760,7 +2796,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst)
mo = Spawn(chunk, mo = Spawn(chunk,
self->x + (((pr_burst()-128)*self->radius)>>7), self->x + (((pr_burst()-128)*self->radius)>>7),
self->y + (((pr_burst()-128)*self->radius)>>7), self->y + (((pr_burst()-128)*self->radius)>>7),
self->z + (pr_burst()*self->height/255), ALLOW_REPLACE); self->z + (pr_burst()*self->height/255 + self->GetBobOffset()), ALLOW_REPLACE);
if (mo) if (mo)
{ {
@ -4712,3 +4748,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
return 0; return 0;
} }
//==========================================================================
//
// A_SetTics
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT(tics_to_set);
self->tics = tics_to_set;
return 0;
}

View file

@ -276,6 +276,7 @@ static FFlagDef ActorFlags[]=
DEFINE_DUMMY_FLAG(NONETID), // netcode-based DEFINE_DUMMY_FLAG(NONETID), // netcode-based
DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), // netcode-based DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), // netcode-based
DEFINE_DUMMY_FLAG(CLIENTSIDEONLY), // netcode-based DEFINE_DUMMY_FLAG(CLIENTSIDEONLY), // netcode-based
DEFINE_DUMMY_FLAG(SERVERSIDEONLY), // netcode-based
DEFINE_DUMMY_FLAG(EXPLODEONDEATH), // seems useless DEFINE_DUMMY_FLAG(EXPLODEONDEATH), // seems useless
}; };
@ -297,6 +298,7 @@ static FFlagDef InventoryFlags[] =
DEFINE_FLAG(IF, NOATTENPICKUPSOUND, AInventory, ItemFlags), DEFINE_FLAG(IF, NOATTENPICKUPSOUND, AInventory, ItemFlags),
DEFINE_FLAG(IF, PERSISTENTPOWER, AInventory, ItemFlags), DEFINE_FLAG(IF, PERSISTENTPOWER, AInventory, ItemFlags),
DEFINE_FLAG(IF, RESTRICTABSOLUTELY, AInventory, ItemFlags), DEFINE_FLAG(IF, RESTRICTABSOLUTELY, AInventory, ItemFlags),
DEFINE_FLAG(IF, NEVERRESPAWN, AInventory, ItemFlags),
DEFINE_DEPRECATED_FLAG(PICKUPFLASH), DEFINE_DEPRECATED_FLAG(PICKUPFLASH),
DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP),

View file

@ -1124,7 +1124,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag)
info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1;
info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum);
SetReplacement(info, replaceName); SetReplacement(sc, info, replaceName);
ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast<PClassActor *>(info->ParentClass)); ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast<PClassActor *>(info->ParentClass));
bag->Info = info; bag->Info = info;

View file

@ -2280,6 +2280,26 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, jumpz, F, PlayerPawn)
defaults->JumpZ = z; defaults->JumpZ = z;
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, GruntSpeed, F, PlayerPawn)
{
PROP_FIXED_PARM(z, 0);
defaults->GruntSpeed = z;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, FallingScreamSpeed, FF, PlayerPawn)
{
PROP_FIXED_PARM(minz, 0);
PROP_FIXED_PARM(maxz, 0);
defaults->FallingScreamMinSpeed = minz;
defaults->FallingScreamMaxSpeed = maxz;
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -2454,7 +2474,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn)
PROP_STRING_PARM(type, 3); PROP_STRING_PARM(type, 3);
color.a = BYTE(255 * clamp(a, 0.f, 1.f)); color.a = BYTE(255 * clamp(a, 0.f, 1.f));
info->SetPainFlash(type, color); assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn)));
static_cast<PClassPlayerPawn *>(info)->PainFlashes.Insert(type, color);
} }
} }

View file

@ -56,6 +56,7 @@
#include "colormatcher.h" #include "colormatcher.h"
#include "thingdef_exp.h" #include "thingdef_exp.h"
#include "version.h" #include "version.h"
#include "templates.h"
TDeletingArray<FStateTempCall *> StateTempCalls; TDeletingArray<FStateTempCall *> StateTempCalls;
@ -223,12 +224,34 @@ do_stop:
sc.MustGetString(); sc.MustGetString();
statestring = sc.String; statestring = sc.String;
sc.MustGetNumber();
state.Tics = clamp<int>(sc.Number, -1, 32767);
if (tcall == NULL) if (tcall == NULL)
{ {
tcall = new FStateTempCall; tcall = new FStateTempCall;
} }
if (sc.CheckString("RANDOM"))
{
int min, max;
sc.MustGetStringName("(");
sc.MustGetNumber();
min = clamp<int>(sc.Number, -1, SHRT_MAX);
sc.MustGetStringName(",");
sc.MustGetNumber();
max = clamp<int>(sc.Number, -1, SHRT_MAX);
sc.MustGetStringName(")");
if (min > max)
{
swapvalues(min, max);
}
state.Tics = min;
state.TicRange = max - min;
}
else
{
sc.MustGetNumber();
state.Tics = clamp<int>(sc.Number, -1, SHRT_MAX);
state.TicRange = 0;
}
while (sc.GetString() && !sc.Crossed) while (sc.GetString() && !sc.Crossed)
{ {

View file

@ -120,15 +120,8 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
BPART(gameinfo.pickupcolor)/255.f, cnt > 128 ? 0.5f : cnt / 255.f, blend); BPART(gameinfo.pickupcolor)/255.f, cnt > 128 ? 0.5f : cnt / 255.f, blend);
} }
PainFlashList * pfl = CPlayer->mo->GetClass()->PainFlashes;
PalEntry painFlash = CPlayer->mo->DamageFade; PalEntry painFlash = CPlayer->mo->DamageFade;
CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash);
if (pfl)
{
PalEntry * color = pfl->CheckKey(CPlayer->mo->DamageTypeReceived);
if (color) painFlash = *color;
}
if (painFlash.a != 0) if (painFlash.a != 0)
{ {

View file

@ -837,10 +837,10 @@ void DCanvas::FillBorder (FTexture *img)
} }
else else
{ {
Clear (0, 0, Width, bordtop, 0, 0); // Top Clear (0, 0, Width, bordtop, GPalette.BlackIndex, 0); // Top
Clear (0, bordtop, bordleft, Height - bordbottom, 0, 0); // Left Clear (0, bordtop, bordleft, Height - bordbottom, GPalette.BlackIndex, 0); // Left
Clear (Width - bordright, bordtop, Width, Height - bordbottom, 0, 0); // Right Clear (Width - bordright, bordtop, Width, Height - bordbottom, GPalette.BlackIndex, 0); // Right
Clear (0, Height - bordbottom, Width, Height, 0, 0); // Bottom Clear (0, Height - bordbottom, Width, Height, GPalette.BlackIndex, 0); // Bottom
} }
} }

View file

@ -124,16 +124,26 @@ public:
FSingleLumpFont (const char *fontname, int lump); FSingleLumpFont (const char *fontname, int lump);
protected: protected:
void CheckFON1Chars (int lump, const BYTE *data, double *luminosity); void CheckFON1Chars (double *luminosity);
void BuildTranslations2 (); void BuildTranslations2 ();
void FixupPalette (BYTE *identity, double *luminosity, const BYTE *palette, void FixupPalette (BYTE *identity, double *luminosity, const BYTE *palette,
bool rescale, PalEntry *out_palette); bool rescale, PalEntry *out_palette);
void LoadTranslations ();
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 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); static int STACK_ARGS BMFCompare(const void *a, const void *b);
enum
{
FONT1,
FONT2,
BMFFONT
} FontType;
BYTE PaletteData[768];
bool RescalePalette;
}; };
class FSinglePicFont : public FFont class FSinglePicFont : public FFont
@ -153,16 +163,22 @@ protected:
class FSpecialFont : public FFont class FSpecialFont : public FFont
{ {
public: public:
FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate); FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump);
void LoadTranslations();
protected:
bool notranslate[256];
}; };
// This is a font character that loads a texture and recolors it. // This is a font character that loads a texture and recolors it.
class FFontChar1 : public FTexture class FFontChar1 : public FTexture
{ {
public: public:
FFontChar1 (FTexture *sourcelump, const BYTE *sourceremap); FFontChar1 (FTexture *sourcelump);
const BYTE *GetColumn (unsigned int column, const Span **spans_out); const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels (); const BYTE *GetPixels ();
void SetSourceRemap(const BYTE *sourceremap);
void Unload (); void Unload ();
~FFontChar1 (); ~FFontChar1 ();
@ -178,11 +194,12 @@ protected:
class FFontChar2 : public FTexture class FFontChar2 : public FTexture
{ {
public: public:
FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs=0, int topofs=0); FFontChar2 (int sourcelump, 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);
const BYTE *GetPixels (); const BYTE *GetPixels ();
void SetSourceRemap(const BYTE *sourceremap);
void Unload (); void Unload ();
protected: protected:
@ -322,18 +339,17 @@ FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font)
// //
//========================================================================== //==========================================================================
FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start) FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth)
{ {
int i; int i;
FTextureID lump; FTextureID lump;
char buffer[12]; char buffer[12];
FTexture **charlumps; FTexture **charlumps;
BYTE usedcolors[256], identity[256];
double *luminosity;
int maxyoffs; int maxyoffs;
bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false;
bool stcfn121 = false; bool stcfn121 = false;
Lump = fdlump;
Chars = new CharData[count]; Chars = new CharData[count];
charlumps = new FTexture *[count]; charlumps = new FTexture *[count];
PatchRemap = new BYTE[256]; PatchRemap = new BYTE[256];
@ -341,7 +357,6 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
LastChar = first + count - 1; LastChar = first + count - 1;
FontHeight = 0; FontHeight = 0;
GlobalKerning = false; GlobalKerning = false;
memset (usedcolors, 0, 256);
Name = copystring (name); Name = copystring (name);
Next = FirstFont; Next = FirstFont;
FirstFont = this; FirstFont = this;
@ -392,18 +407,12 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
{ {
FontHeight = height; FontHeight = height;
} }
RecordTextureColors (pic, usedcolors);
} }
} }
}
ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity);
for (i = 0; i < count; i++)
{
if (charlumps[i] != NULL) if (charlumps[i] != NULL)
{ {
Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap); Chars[i].Pic = new FFontChar1 (charlumps[i]);
Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); Chars[i].XMove = Chars[i].Pic->GetScaledWidth();
} }
else else
@ -413,7 +422,11 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
} }
} }
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL) if (spacewidth != -1)
{
SpaceWidth = spacewidth;
}
else if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL)
{ {
SpaceWidth = (Chars['N' - first].XMove + 1) / 2; SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
} }
@ -424,9 +437,8 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
FixXMoves(); FixXMoves();
BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); LoadTranslations();
delete[] luminosity;
delete[] charlumps; delete[] charlumps;
} }
@ -803,6 +815,42 @@ int FFont::GetCharWidth (int code) const
return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove; return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove;
} }
//==========================================================================
//
// FFont :: LoadTranslations
//
//==========================================================================
void FFont::LoadTranslations()
{
unsigned int count = LastChar - FirstChar + 1;
BYTE usedcolors[256], identity[256];
double *luminosity;
memset (usedcolors, 0, 256);
for (unsigned int i = 0; i < count; i++)
{
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].Pic);
if(pic)
{
pic->SetSourceRemap(NULL); // Force the FFontChar1 to return the same pixels as the base texture
RecordTextureColors (pic, usedcolors);
}
}
ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity);
for (unsigned int i = 0; i < count; i++)
{
if(Chars[i].Pic)
static_cast<FFontChar1 *>(Chars[i].Pic)->SetSourceRemap(PatchRemap);
}
BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL);
delete[] luminosity;
}
//========================================================================== //==========================================================================
// //
// FFont :: Preload // FFont :: Preload
@ -854,8 +902,9 @@ void FFont::StaticPreloadFonts()
// //
//========================================================================== //==========================================================================
FFont::FFont () FFont::FFont (int lump)
{ {
Lump = lump;
Chars = NULL; Chars = NULL;
PatchRemap = NULL; PatchRemap = NULL;
Name = NULL; Name = NULL;
@ -869,7 +918,7 @@ FFont::FFont ()
// //
//========================================================================== //==========================================================================
FSingleLumpFont::FSingleLumpFont (const char *name, int lump) FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
{ {
assert(lump >= 0); assert(lump >= 0);
@ -927,6 +976,51 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
ActiveColors = 0; ActiveColors = 0;
} }
//==========================================================================
//
// FSingleLumpFont :: LoadTranslations
//
//==========================================================================
void FSingleLumpFont::LoadTranslations()
{
double luminosity[256];
BYTE identity[256];
PalEntry local_palette[256];
bool useidentity = true;
bool usepalette = false;
const void* ranges;
unsigned int count = LastChar - FirstChar + 1;
switch(FontType)
{
case FONT1:
useidentity = false;
ranges = &TranslationParms[1][0];
CheckFON1Chars (luminosity);
break;
case BMFFONT:
case FONT2:
usepalette = true;
FixupPalette (identity, luminosity, PaletteData, RescalePalette, local_palette);
ranges = &TranslationParms[0][0];
break;
default:
break;
}
for(unsigned int i = 0;i < count;++i)
{
if(Chars[i].Pic)
static_cast<FFontChar2*>(Chars[i].Pic)->SetSourceRemap(PatchRemap);
}
BuildTranslations (luminosity, useidentity ? identity : NULL, ranges, ActiveColors, usepalette ? local_palette : NULL);
}
//========================================================================== //==========================================================================
// //
// FSingleLumpFont :: LoadFON1 // FSingleLumpFont :: LoadFON1
@ -937,7 +1031,6 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data) void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data)
{ {
double luminosity[256];
int w, h; int w, h;
Chars = new CharData[256]; Chars = new CharData[256];
@ -945,6 +1038,7 @@ void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data)
w = data[4] + data[5]*256; w = data[4] + data[5]*256;
h = data[6] + data[7]*256; h = data[6] + data[7]*256;
FontType = FONT1;
FontHeight = h; FontHeight = h;
SpaceWidth = w; SpaceWidth = w;
FirstChar = 0; FirstChar = 0;
@ -952,8 +1046,10 @@ void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data)
GlobalKerning = 0; GlobalKerning = 0;
PatchRemap = new BYTE[256]; PatchRemap = new BYTE[256];
CheckFON1Chars (lump, data, luminosity); for(unsigned int i = 0;i < 256;++i)
BuildTranslations (luminosity, NULL, &TranslationParms[1][0], ActiveColors, NULL); Chars[i].Pic = NULL;
LoadTranslations();
} }
//========================================================================== //==========================================================================
@ -969,17 +1065,17 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
{ {
int count, i, totalwidth; int count, i, totalwidth;
int *widths2; int *widths2;
BYTE identity[256];
double luminosity[256];
PalEntry local_palette[256];
WORD *widths; WORD *widths;
const BYTE *palette; const BYTE *palette;
const BYTE *data_p; const BYTE *data_p;
FontType = FONT2;
FontHeight = data[4] + data[5]*256; FontHeight = data[4] + data[5]*256;
FirstChar = data[6]; FirstChar = data[6];
LastChar = data[7]; LastChar = data[7];
ActiveColors = data[10]; ActiveColors = data[10];
PatchRemap = NULL;
RescalePalette = data[9] == 0;
count = LastChar - FirstChar + 1; count = LastChar - FirstChar + 1;
Chars = new CharData[count]; Chars = new CharData[count];
@ -1029,7 +1125,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
SpaceWidth = totalwidth * 2 / (3 * count); SpaceWidth = totalwidth * 2 / (3 * count);
} }
FixupPalette (identity, luminosity, palette, data[9] == 0, local_palette); memcpy(PaletteData, palette, (ActiveColors+1)*3);
data_p = palette + (ActiveColors+1)*3; data_p = palette + (ActiveColors+1)*3;
@ -1043,7 +1139,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
} }
else else
{ {
Chars[i].Pic = new FFontChar2 (lump, NULL, int(data_p - data), widths2[i], FontHeight); Chars[i].Pic = new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight);
do do
{ {
SBYTE code = *data_p++; SBYTE code = *data_p++;
@ -1066,7 +1162,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data)
} }
} }
BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, local_palette); LoadTranslations();
delete[] widths2; delete[] widths2;
} }
@ -1087,15 +1183,14 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data)
int i, chari; int i, chari;
BYTE raw_palette[256*3]; BYTE raw_palette[256*3];
PalEntry sort_palette[256]; PalEntry sort_palette[256];
PalEntry local_palette[256];
double luminosity[256];
BYTE identity[256];
FontType = BMFFONT;
FontHeight = data[5]; FontHeight = data[5];
GlobalKerning = (SBYTE)data[8]; GlobalKerning = (SBYTE)data[8];
ActiveColors = data[16]; ActiveColors = data[16];
SpaceWidth = -1; SpaceWidth = -1;
nwidth = -1; nwidth = -1;
RescalePalette = true;
infolen = data[17 + ActiveColors*3]; infolen = data[17 + ActiveColors*3];
chardata = data + 18 + ActiveColors*3 + infolen; chardata = data + 18 + ActiveColors*3 + infolen;
@ -1160,7 +1255,7 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data)
PatchRemap[sort_palette[i].a] = i; PatchRemap[sort_palette[i].a] = i;
} }
FixupPalette(identity, luminosity, raw_palette, true, local_palette); memcpy(PaletteData, raw_palette, 768);
// Now scan through the characters again, creating glyphs for each one. // 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]) for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2])
@ -1180,7 +1275,7 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data)
{ // Empty character: skip it. { // Empty character: skip it.
continue; continue;
} }
Chars[chardata[chari] - FirstChar].Pic = new FFontChar2(lump, PatchRemap, int(chardata + chari + 6 - data), Chars[chardata[chari] - FirstChar].Pic = new FFontChar2(lump, int(chardata + chari + 6 - data),
chardata[chari+1], // width chardata[chari+1], // width
chardata[chari+2], // height chardata[chari+2], // height
-(SBYTE)chardata[chari+3], // x offset -(SBYTE)chardata[chari+3], // x offset
@ -1202,7 +1297,7 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data)
} }
FixXMoves(); FixXMoves();
BuildTranslations(luminosity, identity, &TranslationParms[0][0], ActiveColors, local_palette); LoadTranslations();
} }
//========================================================================== //==========================================================================
@ -1232,8 +1327,11 @@ int STACK_ARGS FSingleLumpFont::BMFCompare(const void *a, const void *b)
// //
//========================================================================== //==========================================================================
void FSingleLumpFont::CheckFON1Chars (int lump, const BYTE *data, double *luminosity) void FSingleLumpFont::CheckFON1Chars (double *luminosity)
{ {
FMemLump memLump = Wads.ReadLump(Lump);
const BYTE* data = (const BYTE*) memLump.GetMem();
BYTE used[256], reverse[256]; BYTE used[256], reverse[256];
const BYTE *data_p; const BYTE *data_p;
int i, j; int i, j;
@ -1245,8 +1343,11 @@ 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); if(!Chars[i].Pic)
Chars[i].XMove = SpaceWidth; {
Chars[i].Pic = new FFontChar2 (Lump, 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
@ -1304,7 +1405,7 @@ void FSingleLumpFont::FixupPalette (BYTE *identity, double *luminosity, const BY
identity[0] = 0; identity[0] = 0;
palette += 3; // Skip the transparent color palette += 3; // Skip the transparent color
for (i = 1; i <= ActiveColors; ++i, palette += 3) for (i = 1; i < ActiveColors; ++i, palette += 3)
{ {
int r = palette[0]; int r = palette[0];
int g = palette[1]; int g = palette[1];
@ -1331,7 +1432,7 @@ void FSingleLumpFont::FixupPalette (BYTE *identity, double *luminosity, const BY
{ {
diver = 1.0 / 255.0; diver = 1.0 / 255.0;
} }
for (i = 1; i <= ActiveColors; ++i) for (i = 1; i < ActiveColors; ++i)
{ {
luminosity[i] = (luminosity[i] - minlum) * diver; luminosity[i] = (luminosity[i] - minlum) * diver;
} }
@ -1347,7 +1448,8 @@ void FSingleLumpFont::FixupPalette (BYTE *identity, double *luminosity, const BY
// //
//========================================================================== //==========================================================================
FSinglePicFont::FSinglePicFont(const char *picname) FSinglePicFont::FSinglePicFont(const char *picname) :
FFont(-1) // Since lump is only needed for priority information we don't need to worry about this here.
{ {
FTextureID picnum = TexMan.CheckForTexture (picname, FTexture::TEX_Any); FTextureID picnum = TexMan.CheckForTexture (picname, FTexture::TEX_Any);
@ -1413,8 +1515,8 @@ int FSinglePicFont::GetCharWidth (int code) const
// //
//========================================================================== //==========================================================================
FFontChar1::FFontChar1 (FTexture *sourcelump, const BYTE *sourceremap) FFontChar1::FFontChar1 (FTexture *sourcelump)
: SourceRemap (sourceremap) : SourceRemap (NULL)
{ {
UseType = FTexture::TEX_FontChar; UseType = FTexture::TEX_FontChar;
BaseTexture = sourcelump; BaseTexture = sourcelump;
@ -1453,9 +1555,16 @@ void FFontChar1::MakeTexture ()
Pixels = new BYTE[Width*Height]; Pixels = new BYTE[Width*Height];
const BYTE *pix = BaseTexture->GetPixels(); const BYTE *pix = BaseTexture->GetPixels();
for (int x = 0; x < Width*Height; ++x) if (!SourceRemap)
{ {
Pixels[x] = SourceRemap[pix[x]]; memcpy(Pixels, pix, Width*Height);
}
else
{
for (int x = 0; x < Width*Height; ++x)
{
Pixels[x] = SourceRemap[pix[x]];
}
} }
} }
@ -1476,6 +1585,18 @@ const BYTE *FFontChar1::GetColumn (unsigned int column, const Span **spans_out)
return Pixels + column*Height; return Pixels + column*Height;
} }
//==========================================================================
//
// FFontChar1 :: SetSourceRemap
//
//==========================================================================
void FFontChar1::SetSourceRemap(const BYTE *sourceremap)
{
Unload();
SourceRemap = sourceremap;
}
//========================================================================== //==========================================================================
// //
// FFontChar1 :: Unload // FFontChar1 :: Unload
@ -1510,8 +1631,8 @@ FFontChar1::~FFontChar1 ()
// //
//========================================================================== //==========================================================================
FFontChar2::FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs, int topofs) FFontChar2::FFontChar2 (int sourcelump, 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(NULL)
{ {
UseType = TEX_FontChar; UseType = TEX_FontChar;
Width = width; Width = width;
@ -1594,6 +1715,18 @@ const BYTE *FFontChar2::GetColumn (unsigned int column, const Span **spans_out)
return Pixels + column*Height; return Pixels + column*Height;
} }
//==========================================================================
//
// FFontChar2 :: SetSourceRemap
//
//==========================================================================
void FFontChar2::SetSourceRemap(const BYTE *sourceremap)
{
Unload();
SourceRemap = sourceremap;
}
//========================================================================== //==========================================================================
// //
// FFontChar2 :: MakeTexture // FFontChar2 :: MakeTexture
@ -1730,16 +1863,15 @@ void FFontChar2::MakeTexture ()
// //
//========================================================================== //==========================================================================
FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate) FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump) : FFont(lump)
{ {
int i, j; int i;
FTexture **charlumps; FTexture **charlumps;
BYTE usedcolors[256], identity[256];
double *luminosity;
int maxyoffs; int maxyoffs;
int TotalColors;
FTexture *pic; FTexture *pic;
memcpy(this->notranslate, notranslate, 256*sizeof(bool));
Name = copystring(name); Name = copystring(name);
Chars = new CharData[count]; Chars = new CharData[count];
charlumps = new FTexture*[count]; charlumps = new FTexture*[count];
@ -1748,7 +1880,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
LastChar = first + count - 1; LastChar = first + count - 1;
FontHeight = 0; FontHeight = 0;
GlobalKerning = false; GlobalKerning = false;
memset (usedcolors, 0, 256);
Next = FirstFont; Next = FirstFont;
FirstFont = this; FirstFont = this;
@ -1771,7 +1902,58 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
{ {
FontHeight = height; FontHeight = height;
} }
}
if (charlumps[i] != NULL)
{
Chars[i].Pic = new FFontChar1 (charlumps[i]);
Chars[i].XMove = Chars[i].Pic->GetScaledWidth();
}
else
{
Chars[i].Pic = NULL;
Chars[i].XMove = INT_MIN;
}
}
// Special fonts normally don't have all characters so be careful here!
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL)
{
SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
}
else
{
SpaceWidth = 4;
}
FixXMoves();
LoadTranslations();
delete[] charlumps;
}
//==========================================================================
//
// FSpecialFont :: LoadTranslations
//
//==========================================================================
void FSpecialFont::LoadTranslations()
{
int count = LastChar - FirstChar + 1;
BYTE usedcolors[256], identity[256];
double *luminosity;
int TotalColors;
int i, j;
memset (usedcolors, 0, 256);
for (i = 0; i < count; i++)
{
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].Pic);
if(pic)
{
pic->SetSourceRemap(NULL); // Force the FFontChar1 to return the same pixels as the base texture
RecordTextureColors (pic, usedcolors); RecordTextureColors (pic, usedcolors);
} }
} }
@ -1802,30 +1984,10 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
if (charlumps[i] != NULL) if(Chars[i].Pic)
{ static_cast<FFontChar1 *>(Chars[i].Pic)->SetSourceRemap(PatchRemap);
Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap);
Chars[i].XMove = Chars[i].Pic->GetScaledWidth();
}
else
{
Chars[i].Pic = NULL;
Chars[i].XMove = INT_MIN;
}
} }
// Special fonts normally don't have all characters so be careful here!
if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL)
{
SpaceWidth = (Chars['N' - first].XMove + 1) / 2;
}
else
{
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
@ -1845,7 +2007,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
ActiveColors = TotalColors; ActiveColors = TotalColors;
delete[] luminosity; delete[] luminosity;
delete[] charlumps;
} }
//========================================================================== //==========================================================================
@ -1899,6 +2060,7 @@ void V_InitCustomFonts()
int start; int start;
int first; int first;
int count; int count;
int spacewidth;
char cursor = '_'; char cursor = '_';
while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1)
@ -1913,6 +2075,7 @@ void V_InitCustomFonts()
start = 33; start = 33;
first = 33; first = 33;
count = 223; count = 223;
spacewidth = -1;
sc.MustGetStringName ("{"); sc.MustGetStringName ("{");
while (!sc.CheckString ("}")) while (!sc.CheckString ("}"))
@ -1951,6 +2114,13 @@ void V_InitCustomFonts()
sc.MustGetString(); sc.MustGetString();
cursor = sc.String[0]; cursor = sc.String[0];
} }
else if (sc.Compare ("SPACEWIDTH"))
{
if (format == 2) goto wrong;
sc.MustGetNumber();
spacewidth = sc.Number;
format = 1;
}
else if (sc.Compare ("NOTRANSLATION")) else if (sc.Compare ("NOTRANSLATION"))
{ {
if (format == 1) goto wrong; if (format == 1) goto wrong;
@ -1994,7 +2164,7 @@ void V_InitCustomFonts()
} }
if (format == 1) if (format == 1)
{ {
FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start); FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth);
fnt->SetCursor(cursor); fnt->SetCursor(cursor);
} }
else if (format == 2) else if (format == 2)
@ -2017,7 +2187,7 @@ void V_InitCustomFonts()
} }
if (count > 0) if (count > 0)
{ {
FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate); FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump);
fnt->SetCursor(cursor); fnt->SetCursor(cursor);
} }
} }
@ -2396,19 +2566,19 @@ void V_InitFonts()
} }
else if (Wads.CheckNumForName ("FONTA_S") >= 0) else if (Wads.CheckNumForName ("FONTA_S") >= 0)
{ {
SmallFont = new FFont ("SmallFont", "FONTA%02u", HU_FONTSTART, HU_FONTSIZE, 1); SmallFont = new FFont ("SmallFont", "FONTA%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1);
SmallFont->SetCursor('['); SmallFont->SetCursor('[');
} }
else else
{ {
SmallFont = new FFont ("SmallFont", "STCFN%.3d", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART); SmallFont = new FFont ("SmallFont", "STCFN%.3d", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
} }
} }
if (!(SmallFont2 = FFont::FindFont("SmallFont2"))) // Only used by Strife if (!(SmallFont2 = FFont::FindFont("SmallFont2"))) // Only used by Strife
{ {
if (Wads.CheckNumForName ("STBFN033", ns_graphics) >= 0) if (Wads.CheckNumForName ("STBFN033", ns_graphics) >= 0)
{ {
SmallFont2 = new FFont ("SmallFont2", "STBFN%.3d", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART); SmallFont2 = new FFont ("SmallFont2", "STBFN%.3d", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
} }
else else
{ {
@ -2427,7 +2597,7 @@ void V_InitFonts()
} }
else else
{ {
BigFont = new FFont ("BigFont", "FONTB%02u", HU_FONTSTART, HU_FONTSIZE, 1); BigFont = new FFont ("BigFont", "FONTB%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1);
} }
} }
if (!(ConFont = FFont::FindFont("ConsoleFont"))) if (!(ConFont = FFont::FindFont("ConsoleFont")))
@ -2455,4 +2625,14 @@ void V_ClearFonts()
} }
FFont::FirstFont = NULL; FFont::FirstFont = NULL;
SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL; SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL;
} }
void V_RetranslateFonts()
{
FFont *font = FFont::FirstFont;
while(font)
{
font->LoadTranslations();
font = font->Next;
}
}

View file

@ -76,15 +76,17 @@ extern int NumTextColors;
class FFont class FFont
{ {
public: public:
FFont (const char *fontname, const char *nametemplate, int first, int count, int base); FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1);
virtual ~FFont (); virtual ~FFont ();
virtual FTexture *GetChar (int code, int *const width) const; virtual FTexture *GetChar (int code, int *const width) const;
virtual int GetCharWidth (int code) const; virtual int GetCharWidth (int code) const;
FRemapTable *GetColorTranslation (EColorRange range) const; FRemapTable *GetColorTranslation (EColorRange range) const;
int GetLump() const { return Lump; }
int GetSpaceWidth () const { return SpaceWidth; } int GetSpaceWidth () const { return SpaceWidth; }
int GetHeight () const { return FontHeight; } int GetHeight () const { return FontHeight; }
int GetDefaultKerning () const { return GlobalKerning; } int GetDefaultKerning () const { return GlobalKerning; }
virtual void LoadTranslations();
void Preload() const; void Preload() const;
static FFont *FindFont (const char *fontname); static FFont *FindFont (const char *fontname);
@ -99,7 +101,7 @@ public:
void SetCursor(char c) { Cursor = c; } void SetCursor(char c) { Cursor = c; }
protected: protected:
FFont (); FFont (int lump);
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);
@ -122,6 +124,7 @@ protected:
TArray<FRemapTable> Ranges; TArray<FRemapTable> Ranges;
BYTE *PatchRemap; BYTE *PatchRemap;
int Lump;
char *Name; char *Name;
FFont *Next; FFont *Next;
@ -129,6 +132,7 @@ protected:
friend struct FontsDeleter; friend struct FontsDeleter;
friend void V_ClearFonts(); friend void V_ClearFonts();
friend void V_RetranslateFonts();
friend FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font); friend FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font);
}; };
@ -143,5 +147,6 @@ PalEntry V_LogColorFromColorRange (EColorRange range);
EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor); EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int boldcolor);
FFont *V_GetFont(const char *); FFont *V_GetFont(const char *);
void V_InitFontColors(); void V_InitFontColors();
void V_RetranslateFonts();
#endif //__V_FONT_H__ #endif //__V_FONT_H__

View file

@ -159,8 +159,8 @@ void FPalette::SetPalette (const BYTE *colors)
// Find white and black from the original palette so that they can be // Find white and black from the original palette so that they can be
// used to make an educated guess of the translucency % for a BOOM // used to make an educated guess of the translucency % for a BOOM
// translucency map. // translucency map.
WhiteIndex = BestColor ((DWORD *)BaseColors, 255, 255, 255); WhiteIndex = BestColor ((DWORD *)BaseColors, 255, 255, 255, 0, 255);
BlackIndex = BestColor ((DWORD *)BaseColors, 0, 0, 0); BlackIndex = BestColor ((DWORD *)BaseColors, 0, 0, 0, 0, 255);
} }
// In ZDoom's new texture system, color 0 is used as the transparent color. // In ZDoom's new texture system, color 0 is used as the transparent color.

View file

@ -859,7 +859,7 @@ void DFrameBuffer::DrawRateStuff ()
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount); chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount);
rate_x = Width - chars * 8; rate_x = Width - chars * 8;
Clear (rate_x, 0, Width, 8, 0, 0); Clear (rate_x, 0, Width, 8, GPalette.BlackIndex, 0);
DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE); DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE);
DWORD thisSec = ms/1000; DWORD thisSec = ms/1000;
@ -1324,10 +1324,7 @@ CCMD(clean)
bool V_DoModeSetup (int width, int height, int bits) bool V_DoModeSetup (int width, int height, int bits)
{ {
DFrameBuffer *buff = I_SetMode (width, height, screen); DFrameBuffer *buff = I_SetMode (width, height, screen);
int ratio; int cx1, cx2;
int cwidth;
int cheight;
int cx1, cy1, cx2, cy2;
if (buff == NULL) if (buff == NULL)
{ {
@ -1342,41 +1339,7 @@ bool V_DoModeSetup (int width, int height, int bits)
// if D3DFB is being used for the display. // if D3DFB is being used for the display.
FFont::StaticPreloadFonts(); FFont::StaticPreloadFonts();
ratio = CheckRatio (width, height); V_CalcCleanFacs(320, 200, width, height, &CleanXfac, &CleanYfac, &cx1, &cx2);
if (ratio & 4)
{
cwidth = width;
cheight = height * BaseRatioSizes[ratio][3] / 48;
}
else
{
cwidth = width * BaseRatioSizes[ratio][3] / 48;
cheight = height;
}
// Use whichever pair of cwidth/cheight or width/height that produces less difference
// between CleanXfac and CleanYfac.
cx1 = MAX(cwidth / 320, 1);
cy1 = MAX(cheight / 200, 1);
cx2 = MAX(width / 320, 1);
cy2 = MAX(height / 200, 1);
if (abs(cx1 - cy1) <= abs(cx2 - cy2))
{ // e.g. 640x360 looks better with this.
CleanXfac = cx1;
CleanYfac = cy1;
}
else
{ // e.g. 720x480 looks better with this.
CleanXfac = cx2;
CleanYfac = cy2;
}
if (CleanXfac > 1 && CleanYfac > 1 && CleanXfac != CleanYfac)
{
if (CleanXfac < CleanYfac)
CleanYfac = CleanXfac;
else
CleanXfac = CleanYfac;
}
CleanWidth = width / CleanXfac; CleanWidth = width / CleanXfac;
CleanHeight = height / CleanYfac; CleanHeight = height / CleanYfac;
@ -1426,6 +1389,52 @@ bool V_DoModeSetup (int width, int height, int bits)
return true; return true;
} }
void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2)
{
int ratio;
int cwidth;
int cheight;
int cx1, cy1, cx2, cy2;
ratio = CheckRatio(realwidth, realheight);
if (ratio & 4)
{
cwidth = realwidth;
cheight = realheight * BaseRatioSizes[ratio][3] / 48;
}
else
{
cwidth = realwidth * BaseRatioSizes[ratio][3] / 48;
cheight = realheight;
}
// Use whichever pair of cwidth/cheight or width/height that produces less difference
// between CleanXfac and CleanYfac.
cx1 = MAX(cwidth / designwidth, 1);
cy1 = MAX(cheight / designheight, 1);
cx2 = MAX(realwidth / designwidth, 1);
cy2 = MAX(realheight / designheight, 1);
if (abs(cx1 - cy1) <= abs(cx2 - cy2))
{ // e.g. 640x360 looks better with this.
*cleanx = cx1;
*cleany = cy1;
}
else
{ // e.g. 720x480 looks better with this.
*cleanx = cx2;
*cleany = cy2;
}
if (*cleanx > 1 && *cleany > 1 && *cleanx != *cleany)
{
if (*cleanx < *cleany)
*cleany = *cleanx;
else
*cleanx = *cleany;
}
if (_cx1 != NULL) *_cx1 = cx1;
if (_cx2 != NULL) *_cx2 = cx2;
}
bool IVideo::SetResolution (int width, int height, int bits) bool IVideo::SetResolution (int width, int height, int bits)
{ {
int oldwidth, oldheight; int oldwidth, oldheight;

View file

@ -46,6 +46,7 @@ extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1;
extern int DisplayWidth, DisplayHeight, DisplayBits; extern int DisplayWidth, DisplayHeight, DisplayBits;
bool V_DoModeSetup (int width, int height, int bits); bool V_DoModeSetup (int width, int height, int bits);
void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *cx1=NULL, int *cx2=NULL);
class FTexture; class FTexture;

View file

@ -116,7 +116,7 @@ static inline const char *MakeSaveSig()
#define BUGS_FORUM_URL "http://forum.zdoom.org/index.php?c=3" #define BUGS_FORUM_URL "http://forum.zdoom.org/index.php?c=3"
#ifdef unix #ifdef unix
#define GAME_DIR ".zdoom" #define GAME_DIR ".config/zdoom"
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define GAME_DIR GAMENAME #define GAME_DIR GAMENAME
#else #else

View file

@ -1588,30 +1588,36 @@ void WI_updateNetgameStats ()
void WI_drawNetgameStats () void WI_drawNetgameStats ()
{ {
int i, x, y, height; int i, x, y, ypadding, height, lineheight;
int maxnamewidth, maxscorewidth; int maxnamewidth, maxscorewidth, maxiconheight;
int pwidth = IntermissionFont->GetCharWidth('%'); int pwidth = IntermissionFont->GetCharWidth('%');
int icon_x, name_x, kills_x, bonus_x, secret_x; int icon_x, name_x, kills_x, bonus_x, secret_x;
int bonus_len, secret_len; int bonus_len, secret_len;
int missed_kills, missed_items, missed_secrets; int missed_kills, missed_items, missed_secrets;
EColorRange color; EColorRange color;
const char *bonus_label; const char *text_bonus, *text_color, *text_secret, *text_kills;
// draw animated background // draw animated background
WI_drawBackground(); WI_drawBackground();
y = WI_drawLF(); y = WI_drawLF();
HU_GetPlayerWidths(maxnamewidth, maxscorewidth); HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
height = SmallFont->GetHeight() * CleanYfac; height = SmallFont->GetHeight() * CleanYfac;
lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2;
y += 16*CleanYfac; y += 16*CleanYfac;
bonus_label = (gameinfo.gametype & GAME_Raven) ? "BONUS" : "ITEMS"; text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS");
icon_x = (SmallFont->StringWidth("COLOR") + 8) * CleanXfac; text_color = GStrings("SCORE_COLOR");
text_secret = GStrings("SCORE_SECRET");
text_kills = GStrings("SCORE_KILLS");
icon_x = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
name_x = icon_x + maxscorewidth * CleanXfac; name_x = icon_x + maxscorewidth * CleanXfac;
kills_x = name_x + (maxnamewidth + SmallFont->StringWidth("XXXXX") + 8) * CleanXfac; kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac;
bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(bonus_label)) + 8) * CleanXfac; bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac;
secret_x = bonus_x + ((secret_len = SmallFont->StringWidth("SECRET")) + 8) * CleanXfac; secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac;
x = (SCREENWIDTH - secret_x) >> 1; x = (SCREENWIDTH - secret_x) >> 1;
icon_x += x; icon_x += x;
@ -1622,11 +1628,11 @@ void WI_drawNetgameStats ()
color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, x, y, "COLOR", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, x, y, text_color, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, name_x, y, "NAME", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth("KILLS")*CleanXfac, y, "KILLS", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, bonus_label, DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, "SECRET", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE);
y += height + 6 * CleanYfac; y += height + 6 * CleanYfac;
missed_kills = wbs->maxkills; missed_kills = wbs->maxkills;
@ -1642,32 +1648,32 @@ void WI_drawNetgameStats ()
continue; continue;
player = &players[i]; player = &players[i];
HU_DrawColorBar(x, y, height, i); HU_DrawColorBar(x, y, lineheight, i);
color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); color = (EColorRange)HU_GetRowColor(player, i == consoleplayer);
if (player->mo->ScoreIcon.isValid()) if (player->mo->ScoreIcon.isValid())
{ {
FTexture *pic = TexMan[player->mo->ScoreIcon]; FTexture *pic = TexMan[player->mo->ScoreIcon];
screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
} }
screen->DrawText(SmallFont, color, name_x, y, player->userinfo.netname, DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.netname, DTA_CleanNoMove, true, TAG_DONE);
WI_drawPercent(SmallFont, kills_x, y, cnt_kills[i], wbs->maxkills, false, color); WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color);
missed_kills -= cnt_kills[i]; missed_kills -= cnt_kills[i];
if (ng_state >= 4) if (ng_state >= 4)
{ {
WI_drawPercent(SmallFont, bonus_x, y, cnt_items[i], wbs->maxitems, false, color); WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color);
missed_items -= cnt_items[i]; missed_items -= cnt_items[i];
if (ng_state >= 6) if (ng_state >= 6)
{ {
WI_drawPercent(SmallFont, secret_x, y, cnt_secret[i], wbs->maxsecret, false, color); WI_drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs->maxsecret, false, color);
missed_secrets -= cnt_secret[i]; missed_secrets -= cnt_secret[i];
} }
} }
y += height + CleanYfac; y += lineheight + CleanYfac;
} }
// Draw "MISSED" line // Draw "MISSED" line
y += 5 * CleanYfac; y += 5 * CleanYfac;
screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, "MISSED", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE);
WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY);
if (ng_state >= 4) if (ng_state >= 4)
{ {
@ -1681,7 +1687,7 @@ void WI_drawNetgameStats ()
// Draw "TOTAL" line // Draw "TOTAL" line
y += height + 5 * CleanYfac; y += height + 5 * CleanYfac;
color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
screen->DrawText(SmallFont, color, name_x, y, "TOTAL", DTA_CleanNoMove, true, TAG_DONE); screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color);
if (ng_state >= 4) if (ng_state >= 4)
{ {

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