diff --git a/src/actor.h b/src/actor.h index b36f3667b..4e0b0de06 100644 --- a/src/actor.h +++ b/src/actor.h @@ -30,9 +30,7 @@ #include "dthinker.h" -// States are tied to finite states are -// tied to animation frames. -// Needs precompiled tables/data structures. +// States are tied to finite states are tied to animation frames. #include "info.h" #include "doomdef.h" @@ -40,6 +38,7 @@ #include "r_data/renderstyle.h" #include "s_sound.h" #include "memarena.h" +#include "g_level.h" struct subsector_t; class PClassAmmo; @@ -550,15 +549,14 @@ public: bool AdjustReflectionAngle (AActor *thing, angle_t &angle); // 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 (); - virtual void PostBeginPlay (); - // LevelSpawned: Called after BeginPlay if this actor was spawned by the world - virtual void LevelSpawned (); - // Translates SpawnFlags into in-game flags. - virtual void HandleSpawnFlags (); + virtual void BeginPlay(); // Called immediately after the actor is created + virtual void PostBeginPlay(); // Called immediately before the actor's first tick + virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world + virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. + + virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. virtual void Activate (AActor *activator); virtual void Deactivate (AActor *activator); @@ -679,9 +677,20 @@ public: // Do I hate the other actor? bool IsHostile (AActor *other); + inline bool IsNoClip2() const; + // What species am I? 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 void Crash(); @@ -938,6 +947,7 @@ private: static FSharedStringArena mStringPropertyData; friend class FActorIterator; + friend bool P_IsTIDUsed(int tid); 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) { return AActor::StaticSpawn (type, x, y, z, allowreplacement); diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 4f59f53c8..c67c2a24e 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -173,6 +173,15 @@ CCMD (noclip) Net_WriteByte (CHT_NOCLIP); } +CCMD (noclip2) +{ + if (CheckCheatmode()) + return; + + Net_WriteByte (DEM_GENERICCHEAT); + Net_WriteByte (CHT_NOCLIP2); +} + CCMD (powerup) { if (CheckCheatmode ()) @@ -243,7 +252,7 @@ CCMD (chase) else { // 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; Net_WriteByte (DEM_GENERICCHEAT); @@ -947,9 +956,16 @@ CCMD(thaw) //----------------------------------------------------------------------------- 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)) { @@ -968,9 +984,16 @@ CCMD(nextmap) //----------------------------------------------------------------------------- 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)) { diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index d05e44a67..d99acda42 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -273,7 +273,9 @@ void CT_Drawer (void) if (players[consoleplayer].camera != NULL && (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]); } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 1c7dbadb5..40e919aae 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1354,7 +1354,7 @@ static int PatchFrame (int frameNum) 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) { diff --git a/src/d_main.cpp b/src/d_main.cpp index ee46a894d..049d0a933 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -804,17 +804,21 @@ void D_Display () if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10) { + StatusBar->DrawBottomStuff (HUD_None); if (DrawFSHUD || automapactive) DrawHUD(); StatusBar->DrawTopStuff (HUD_None); } else if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10) { - StatusBar->Draw (DrawFSHUD ? HUD_Fullscreen : HUD_None); - StatusBar->DrawTopStuff (DrawFSHUD ? HUD_Fullscreen : HUD_None); + EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None; + StatusBar->DrawBottomStuff (state); + StatusBar->Draw (state); + StatusBar->DrawTopStuff (state); } else { + StatusBar->DrawBottomStuff (HUD_StatusBar); StatusBar->Draw (HUD_StatusBar); StatusBar->DrawTopStuff (HUD_StatusBar); } @@ -2207,14 +2211,17 @@ void D_DoomMain (void) // [RH] Load sound environments S_ParseReverbDef (); + // [RH] Parse any SNDINFO lumps + Printf ("S_InitData: Load sound definitions.\n"); + S_InitData (); + // [RH] Parse through all loaded mapinfo lumps Printf ("G_ParseMapInfo: Load map definitions.\n"); G_ParseMapInfo (iwad_info->MapInfo); ReadStatistics(); - // [RH] Parse any SNDINFO lumps - Printf ("S_InitData: Load sound definitions.\n"); - S_InitData (); + // MUSINFO must be parsed after MAPINFO + S_ParseMusInfo(); Printf ("Texman.Init: Init texture manager.\n"); TexMan.Init(); diff --git a/src/d_net.cpp b/src/d_net.cpp index bd86c2317..a108e8daf 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -60,6 +60,7 @@ #include "p_lnspec.h" #include "v_video.h" #include "p_spec.h" +#include "hardware.h" #include "intermission/intermission.h" EXTERN_CVAR (Int, disableautosave) @@ -135,7 +136,18 @@ static int oldentertics; 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 static struct TicSpecial diff --git a/src/d_player.h b/src/d_player.h index 40b0d2ecd..244aa192a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -65,7 +65,9 @@ struct FPlayerColorSet BYTE NumExtraRanges; ExtraRange Extra[6]; }; + typedef TMap FPlayerColorSetMap; +typedef TMap PainFlashList; class PClassPlayerPawn : public PClassActor { @@ -76,6 +78,8 @@ public: PClassPlayerPawn(); void EnumColorSets(TArray *out); 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 SoundClass; // Sound class @@ -88,6 +92,7 @@ public: BYTE ColorRangeStart; // Skin color range BYTE ColorRangeEnd; FPlayerColorSetMap ColorSets; + PainFlashList PainFlashes; }; FString GetPrintableDisplayName(PClassPlayerPawn *cls); @@ -105,6 +110,7 @@ public: virtual void AddInventory (AInventory *item); virtual void RemoveInventory (AInventory *item); virtual bool UseInventory (AInventory *item); + virtual void MarkPrecacheSounds () const; virtual void PlayIdle (); virtual void PlayRunning (); @@ -122,7 +128,7 @@ public: void GiveDefaultInventory (); void PlayAttacking (); void PlayAttacking2 (); - const char *GetSoundClass (); + const char *GetSoundClass () const; enum EInvulState { @@ -145,6 +151,8 @@ public: // [GRB] Player class properties fixed_t JumpZ; + fixed_t GruntSpeed; + fixed_t FallingScreamMinSpeed, FallingScreamMaxSpeed; fixed_t ViewHeight; fixed_t ForwardMove1, ForwardMove2; fixed_t SideMove1, SideMove2; @@ -221,6 +229,7 @@ typedef enum CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon. CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function. + CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip } cheat_t; #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) diff --git a/src/d_protocol.h b/src/d_protocol.h index b3d72a4ca..028ad1606 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -218,7 +218,8 @@ enum ECheatCommand CHT_GIMMIEI, CHT_GIMMIEJ, CHT_GIMMIEZ, - CHT_BUDDHA + CHT_BUDDHA, + CHT_NOCLIP2 }; void StartChunk (int id, BYTE **stream); diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index e96bd6739..2e23ed066 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -3367,7 +3367,7 @@ void FParser::SF_RadiusAttack() if (spot && source) { - P_RadiusAttack(spot, source, damage, damage, NAME_None, true); + P_RadiusAttack(spot, source, damage, damage, NAME_None, RADF_HURTSOURCE); } } } diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp index 850d61769..d9b4f2d04 100644 --- a/src/fragglescript/t_load.cpp +++ b/src/fragglescript/t_load.cpp @@ -342,7 +342,7 @@ void T_LoadScripts(MapData *map) // the default translator is being used. // Custom translators will not be patched. 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]; SimpleLineTranslations[270] = SimpleLineTranslations[272]; diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 4b892ed63..86ccf51f5 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) target->y - FixedMul (24*FRACUNIT, finesine[an]), 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); return 0; diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index 46aa076ab..67ae803b9 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -151,7 +151,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) 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<z += 32*FRACUNIT; self->RenderStyle = STYLE_Add; 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<z += 28*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++) { tiny = Spawn("VolcanoTBlast", self->x, self->y, self->z, ALLOW_REPLACE); diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index 1a8aab967..58184f45a 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -98,8 +98,8 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { PARAM_ACTION_PROLOGUE; PARAM_INT_OPT (blastflags) { blastflags = 0; } - PARAM_FIXED_OPT (strength) { strength = 255; } - PARAM_FIXED_OPT (radius) { radius = 255; } + PARAM_INT_OPT (strength) { strength = 255; } + PARAM_INT_OPT (radius) { radius = 255; } PARAM_FIXED_OPT (speed) { speed = 20; } PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); } PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; } diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 0b907031a..ac1b4b024 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -418,7 +418,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) 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; self->z += finesine[bobIndex << BOBTOFINESHIFT] >> 1; self->special2 = (bobIndex + 1) & 63; diff --git a/src/g_level.cpp b/src/g_level.cpp index e6b8bad91..32acf14cb 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -737,7 +737,14 @@ void G_DoCompleted (void) if (mode == FINISH_SameHub) { // 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 { // Forget the states of all existing levels. diff --git a/src/g_level.h b/src/g_level.h index 9b0120263..188207f32 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -36,8 +36,8 @@ #include "doomtype.h" #include "doomdef.h" -//#include "autosegs.h" #include "sc_man.h" +#include "s_sound.h" struct level_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_MUSICDEFINED = 0x00000080, // a marker to disable the $map command in SNDINFO for this map + /* = 0x00000080, */ LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100, LEVEL2_CLIPMIDTEX = 0x00000200, LEVEL2_WRAPMIDTEX = 0x00000400, @@ -211,6 +211,7 @@ enum ELevelFlags LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected 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_FORGETSTATE = 0x80000000, // forget this map's state in a hub }; @@ -325,6 +326,8 @@ struct level_info_t TArray specialactions; + TArray PrecacheSounds; + level_info_t() { Reset(); diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 60a1251cf..b3952ec1b 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -61,6 +61,8 @@ static cluster_info_t TheDefaultClusterInfo; TArray AllEpisodes; +extern TMap HexenMusic; + //========================================================================== // // @@ -269,6 +271,7 @@ void level_info_t::Reset() teamdamage = 0.f; specialactions.Clear(); DefaultEnvironment = 0; + PrecacheSounds.Clear(); } @@ -917,8 +920,6 @@ DEFINE_MAP_OPTION(music, true) { parse.ParseAssign(); 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) @@ -1029,7 +1030,7 @@ DEFINE_MAP_OPTION(specialaction, true) sa->Action = P_FindLineSpecial(parse.sc.String, &min_arg, &max_arg); 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; 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); } +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) { parse.ParseAssign(); @@ -1244,6 +1264,8 @@ MapFlagHandlers[] = { "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 }, { "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 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 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "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. 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; } @@ -1810,7 +1840,6 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i } } - //========================================================================== // // diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index c0cfd82e4..dafa1bafc 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -47,12 +47,12 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp } if (p->morphTics) { // Player is already a beast - if ((p->mo->GetClass() == spawntype) - && (p->mo->PlayerFlags & PPF_CANSUPERMORPH) - && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) - && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL)) - { // Make a super chicken - p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); + if ((p->mo->GetClass() == spawntype) + && (p->mo->PlayerFlags & PPF_CANSUPERMORPH) + && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) + && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL)) + { // Make a super chicken + p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); } return false; } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 8578f69bf..3c868ffed 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -505,6 +505,18 @@ void AInventory::Serialize (FArchive &arc) arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags << Icon << PickupSound << SpawnPointClass; } +//=========================================================================== +// +// AInventory :: MarkPrecacheSounds +// +//=========================================================================== + +void AInventory::MarkPrecacheSounds() const +{ + Super::MarkPrecacheSounds(); + PickupSound.MarkUsed(); +} + //=========================================================================== // // AInventory :: SpecialDropAction @@ -532,6 +544,7 @@ bool AInventory::SpecialDropAction (AActor *dropper) bool AInventory::ShouldRespawn () { if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags & DF_RESPAWN_SUPER)) return false; + if (ItemFlags & IF_NEVERRESPAWN) return false; return !!(dmflags & DF_ITEMS_RESPAWN); } diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index a3f705c35..0f09a58dd 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -123,6 +123,7 @@ enum IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE 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_NEVERRESPAWN = 1<<20, // Never, ever respawns }; @@ -147,6 +148,7 @@ public: virtual void Touch (AActor *toucher); virtual void Serialize (FArchive &arc); + virtual void MarkPrecacheSounds() const; virtual void BeginPlay (); virtual void Destroy (); virtual void Tick (); @@ -296,6 +298,7 @@ public: bool bAltFire; // Set when this weapon's alternate fire is used. + virtual void MarkPrecacheSounds() const; virtual void Serialize (FArchive &arc); virtual bool ShouldStay (); virtual void AttachToOwner (AActor *other); diff --git a/src/g_shared/a_soundsequence.cpp b/src/g_shared/a_soundsequence.cpp index 94e8e1e60..ab0ee101b 100644 --- a/src/g_shared/a_soundsequence.cpp +++ b/src/g_shared/a_soundsequence.cpp @@ -105,6 +105,7 @@ public: void PostBeginPlay (); void Activate (AActor *activator); void Deactivate (AActor *activator); + void MarkPrecacheSounds () const; }; 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 @@ -175,4 +188,3 @@ void ASoundSequence::Deactivate (AActor *activator) { SN_StopSequence (this); } - diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 3ce2348d1..67e8d5769 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -85,6 +85,19 @@ void AWeapon::Serialize (FArchive &arc) << Crosshair; } +//=========================================================================== +// +// AWeapon :: MarkPrecacheSounds +// +//=========================================================================== + +void AWeapon::MarkPrecacheSounds() const +{ + Super::MarkPrecacheSounds(); + UpSound.MarkUsed(); + ReadySound.MarkUsed(); +} + //=========================================================================== // // AWeapon :: TryPickup @@ -732,6 +745,7 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) if (weap != NULL) { 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 (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; weap->BecomeItem(); @@ -741,7 +755,11 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) weap = barrier_cast(master); bool res = weap->CallTryPickup(toucher); - if (res) GoAwayAndDie(); + if (res) + { + GoAwayAndDie(); + master = NULL; + } return res; } } diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 22e12ead1..76eaedcec 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -140,6 +140,9 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h State = 0; SourceText = copystring (text); Font = font; + VisibilityFlags = 0; + Style = STYLE_Translucent; + Alpha = FRACUNIT; ResetText (SourceText); } @@ -184,6 +187,23 @@ void DHUDMessage::Serialize (FArchive &arc) Lines = NULL; 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 x, y; @@ -271,6 +291,12 @@ void DHUDMessage::Draw (int bottom) bool clean = false; int hudheight; + // If any of the visibility flags match, do NOT draw this message. + if (VisibilityFlags & visibility) + { + return; + } + DrawSetup (); 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, DTA_CleanNoMove, clean, + DTA_Alpha, Alpha, + DTA_RenderStyle, Style, TAG_DONE); } 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, DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualHeight, SCREENHEIGHT/2, + DTA_Alpha, Alpha, + DTA_RenderStyle, Style, DTA_KeepRatio, true, 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, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_Alpha, Alpha, + DTA_RenderStyle, Style, TAG_DONE); } } @@ -482,6 +514,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh else { fixed_t trans = -(Tics - FadeOutTics) * FRACUNIT / FadeOutTics; + trans = FixedMul(trans, Alpha); if (hudheight == 0) { 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, DTA_CleanNoMove, clean, DTA_Alpha, trans, + DTA_RenderStyle, Style, TAG_DONE); } else @@ -497,6 +531,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualHeight, SCREENHEIGHT/2, DTA_Alpha, trans, + DTA_RenderStyle, Style, DTA_KeepRatio, true, TAG_DONE); } @@ -507,6 +542,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, + DTA_RenderStyle, Style, TAG_DONE); } BorderNeedRefresh = screen->GetPageCount (); @@ -575,6 +611,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu if (State == 0) { fixed_t trans = Tics * FRACUNIT / FadeInTics; + trans = FixedMul(trans, Alpha); if (hudheight == 0) { 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, DTA_CleanNoMove, clean, DTA_Alpha, trans, + DTA_RenderStyle, Style, TAG_DONE); } else @@ -590,6 +628,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_VirtualWidth, SCREENWIDTH/2, DTA_VirtualHeight, SCREENHEIGHT/2, DTA_Alpha, trans, + DTA_RenderStyle, Style, DTA_KeepRatio, true, TAG_DONE); } @@ -600,6 +639,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, + DTA_RenderStyle, Style, TAG_DONE); } 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, DTA_CleanNoMove, clean, DTA_TextLen, LineVisible, + DTA_Alpha, Alpha, + DTA_RenderStyle, Style, TAG_DONE); } else @@ -762,6 +804,8 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in DTA_VirtualHeight, SCREENHEIGHT/2, DTA_KeepRatio, true, DTA_TextLen, LineVisible, + DTA_Alpha, Alpha, + DTA_RenderStyle, Style, 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, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_Alpha, Alpha, DTA_TextLen, LineVisible, + DTA_RenderStyle, Style, TAG_DONE); } } diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index be5ebddd5..df3daf597 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -66,13 +66,26 @@ public: virtual void Serialize (FArchive &arc); - void Draw (int bottom); + void Draw (int bottom, int visibility); virtual void ResetText (const char *text); virtual void DrawSetup (); virtual void DoDraw (int linenum, int x, int y, bool clean, int hudheight); virtual bool Tick (); // Returns true to indicate time for removal virtual void ScreenSizeChanged (); + void SetVisibility(int vis) + { + VisibilityFlags = vis; + } + void SetRenderStyle(ERenderStyle style) + { + Style = style; + } + void SetAlpha(fixed_t alpha) + { + Alpha = alpha; + } + protected: FBrokenLines *Lines; int Width, Height, NumLines; @@ -81,9 +94,12 @@ protected: int HoldTics; int Tics; int State; + int VisibilityFlags; int HUDWidth, HUDHeight; EColorRange TextColor; FFont *Font; + FRenderStyle Style; + fixed_t Alpha; DHUDMessage () : SourceText(NULL) {} @@ -95,6 +111,14 @@ private: 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 ------------------------ class DHUDMessageFadeOut : public DHUDMessage @@ -242,6 +266,16 @@ int FindMugShotStateIndex(FName state); class FTexture; class AAmmo; +enum +{ + HUDMSGLayer_OverHUD, + HUDMSGLayer_UnderHUD, + HUDMSGLayer_OverMap, + + NUM_HUDMSGLAYERS, + HUDMSGLayer_Default = HUDMSGLayer_OverHUD, +}; + class DBaseStatusBar : public DObject { DECLARE_CLASS (DBaseStatusBar, DObject) @@ -281,11 +315,10 @@ public: 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 (uint32 id); void DetachAllMessages (); - bool CheckMessage (DHUDMessage *msg); void ShowPlayerName (); fixed_t GetDisplacement () { return Displacement; } int GetPlayer (); @@ -296,6 +329,7 @@ public: virtual void Tick (); virtual void Draw (EHudState state); + void DrawBottomStuff (EHudState state); void DrawTopStuff (EHudState state); virtual void FlashItem (const PClass *itemtype); virtual void AttachToPlayer (player_t *player); @@ -343,6 +377,7 @@ public: bool Scaled; bool Centering; bool FixedOrigin; + bool CompleteBorder; fixed_t CrosshairSize; fixed_t Displacement; @@ -363,10 +398,10 @@ public: private: DBaseStatusBar() {} 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; - TObjPtr Messages; + TObjPtr Messages[NUM_HUDMSGLAYERS]; bool ShowLog; }; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 6a1f6fd98..7e0667062 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -149,6 +149,8 @@ class SBarInfoCommand virtual void Reset() {} virtual void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) {} + SBarInfo *GetScript() { return script; } + protected: void GetCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) { @@ -798,6 +800,8 @@ void SBarInfo::Init() spacingAlignment = ALIGN_CENTER; resW = 320; resH = 200; + cleanX = -1; + cleanY = -1; for(unsigned int i = 0;i < NUMHUDS;i++) huds[i] = new SBarInfoMainBlock(this); @@ -978,6 +982,8 @@ public: } invBarOffset = script->Images.Size(); Images.Init(&patchnames[0], patchnames.Size()); + + CompleteBorder = script->completeBorder; } ~DSBarInfo () @@ -985,19 +991,22 @@ public: Images.Uninit(); } + void ScreenSizeChanged() + { + Super::ScreenSizeChanged(); + V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY); + } + void Draw (EHudState state) { DBaseStatusBar::Draw(state); + if (script->cleanX <= 0) + { // Calculate cleanX and cleanY + ScreenSizeChanged(); + } int hud = STBAR_NORMAL; 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) { hud = STBAR_AUTOMAP; @@ -1250,8 +1259,8 @@ public: { 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 yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH; + double xScale = !hud_scale ? 1 : script->cleanX; + double yScale = !hud_scale ? 1 : script->cleanY; 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); rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale); 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) @@ -1370,8 +1351,8 @@ public: { if(hud_scale) { - xScale = (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; - yScale = (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENWIDTH/(double) script->resW; + xScale = script->cleanX; + yScale = script->cleanY; } adjustRelCenter(x.RelCenter(), y.RelCenter(), *x, *y, ax, ay, xScale, yScale); } diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index d2d81f1f7..1b92b1d80 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -108,6 +108,8 @@ struct SBarInfo FMugShot MugShot; int resW; int resH; + int cleanX; + int cleanY; int GetGameType() { return gameType; } void ParseSBarInfo(int lump); diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index ee4e98890..4ca4a519c 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -61,7 +61,9 @@ #define POWERUPICONSIZE 32 IMPLEMENT_POINTY_CLASS(DBaseStatusBar) - DECLARE_POINTER(Messages) + DECLARE_POINTER(Messages[0]) + DECLARE_POINTER(Messages[1]) + DECLARE_POINTER(Messages[2]) END_POINTERS EXTERN_CVAR (Bool, am_showmonsters) @@ -70,7 +72,6 @@ EXTERN_CVAR (Bool, am_showitems) EXTERN_CVAR (Bool, am_showtime) EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, noisedebug) -EXTERN_CVAR (Bool, hud_scale) EXTERN_CVAR (Int, con_scaletext) DBaseStatusBar *StatusBar; @@ -216,11 +217,12 @@ void ST_Clear() DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) { + CompleteBorder = false; Centering = false; FixedOrigin = false; CrosshairSize = FRACUNIT; RelTop = reltop; - Messages = NULL; + memset(Messages, 0, sizeof(Messages)); Displacement = 0; CPlayer = NULL; ShowLog = false; @@ -238,16 +240,17 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) void DBaseStatusBar::Destroy () { - DHUDMessage *msg; - - msg = Messages; - while (msg) + for (int i = 0; i < countof(Messages); ++i) { - DHUDMessage *next = msg->Next; - msg->Destroy(); - msg = next; + DHUDMessage *msg = Messages[i]; + while (msg) + { + DHUDMessage *next = msg->Next; + msg->Destroy(); + msg = next; + } + Messages[i] = NULL; } - Messages = NULL; Super::Destroy(); } @@ -339,32 +342,35 @@ void DBaseStatusBar::MultiplayerChanged () void DBaseStatusBar::Tick () { - DHUDMessage *msg = Messages; - DHUDMessage **prev = &Messages; - - while (msg) + for (int i = 0; i < countof(Messages); ++i) { - DHUDMessage *next = msg->Next; + DHUDMessage *msg = Messages[i]; + DHUDMessage **prev = &Messages[i]; - if (msg->Tick ()) + while (msg) { - *prev = next; - msg->Destroy(); - } - else - { - prev = &msg->Next; - } - msg = next; - } + DHUDMessage *next = msg->Next; - // If the crosshair has been enlarged, shrink it. - if (CrosshairSize > FRACUNIT) - { - CrosshairSize -= XHAIRSHRINKSIZE; - if (CrosshairSize < FRACUNIT) + if (msg->Tick ()) + { + *prev = next; + msg->Destroy(); + } + 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 **prev; @@ -387,7 +393,13 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id) 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 // 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 *probe = Messages; - DHUDMessage **prev = &Messages; + for (int i = 0; i < countof(Messages); ++i) + { + DHUDMessage *probe = Messages[i]; + DHUDMessage **prev = &Messages[i]; - 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) + while (probe && probe != msg) { - 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 *probe = Messages; - DHUDMessage **prev = &Messages; + for (int i = 0; i < countof(Messages); ++i) + { + DHUDMessage *probe = Messages[i]; + DHUDMessage **prev = &Messages[i]; - 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) + while (probe && probe->SBarID != id) { - 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 () { - DHUDMessage *probe = Messages; - - Messages = NULL; - while (probe != NULL) + for (int i = 0; i < countof(Messages); ++i) { - DHUDMessage *next = probe->Next; - probe->Destroy(); - probe = next; - } -} + DHUDMessage *probe = Messages[i]; -//--------------------------------------------------------------------------- -// -// PROC CheckMessage -// -//--------------------------------------------------------------------------- - -bool DBaseStatusBar::CheckMessage (DHUDMessage *msg) -{ - DHUDMessage *probe = Messages; - while (probe && probe != msg) - { - probe = probe->Next; + Messages[i] = NULL; + while (probe != NULL) + { + DHUDMessage *next = probe->Next; + probe->Destroy(); + probe = next; + } } - return (probe == msg); } //--------------------------------------------------------------------------- @@ -1037,27 +1044,46 @@ void DBaseStatusBar::RefreshBackground () const { 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); - x = (!(ratio & 3) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2); - if (x > 0) + if(y < SCREENHEIGHT) + { + 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 : 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) - { - const gameborder_t *border = gameinfo.border; - FTexture *p; + V_DrawBorder (0, y, x+1, SCREENHEIGHT); + V_DrawBorder (x2-1, y, SCREENWIDTH, SCREENHEIGHT); - p = TexMan[border->b]; - screen->FlatFill(0, y, x, y + p->GetHeight(), p, true); - screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetHeight(), p, true); - } + if (setblocks >= 10) + { + 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) { DHUDMessage *next = msg->Next; - msg->Draw (bottom); + msg->Draw (bottom, visibility); 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 @@ -1443,16 +1490,11 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) } DrawPowerups (); - - if (state == HUD_StatusBar) + if (automapactive && !viewactive) { - DrawMessages (::ST_Y); + DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT); } - else - { - DrawMessages (SCREENHEIGHT); - } - + DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT); DrawConsistancy (); if (ShowLog && MustDrawLog(state)) DrawLog (); @@ -1578,7 +1620,18 @@ void DBaseStatusBar::ReceivedWeapon (AWeapon *weapon) 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 () @@ -1586,11 +1639,14 @@ void DBaseStatusBar::ScreenSizeChanged () st_scale.Callback (); SB_state = screen->GetPageCount (); - DHUDMessage *message = Messages; - while (message != NULL) + for (int i = 0; i < countof(Messages); ++i) { - message->ScreenSizeChanged (); - message = message->Next; + DHUDMessage *message = Messages[i]; + while (message != NULL) + { + message->ScreenSizeChanged (); + message = message->Next; + } } } diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 87579ff8d..c5cfa7d26 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -89,6 +89,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || P_HitFriend(self) || + (self->MissileState == NULL && !self->CheckMeleeRange()) || pr_sentinelrefire() < 40) { self->SetState (self->SeeState); diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 0f8e2b86c..82054249d 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -721,7 +721,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DropFire) AActor *drop = Spawn("FireDroplet", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); drop->velz = -FRACUNIT; - P_RadiusAttack (self, self, 64, 64, NAME_Fire, false); + P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); return 0; } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 70e30f5f9..b87503468 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -605,7 +605,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BurnArea) { 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; } diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index d79801c36..b2898a235 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode512) { 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) { self->target->player->extralight = 5; diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 1d881bd3d..55d657b7c 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -47,6 +47,7 @@ #include "v_palette.h" #include "d_player.h" #include "hu_stuff.h" +#include "gstrings.h" // MACROS ------------------------------------------------------------------ @@ -60,7 +61,7 @@ static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]); 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 ---------------------------------------------- @@ -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"); maxscorewidth = 0; + maxiconheight = 0; for (int i = 0; i < MAXPLAYERS; i++) { @@ -195,11 +197,18 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth) if (players[i].mo->ScoreIcon.isValid()) { FTexture *pic = TexMan[players[i].mo->ScoreIcon]; - width = pic->GetWidth() - pic->GetScaledLeftOffset() + 2; + width = pic->GetScaledWidth() - pic->GetScaledLeftOffset() + 2; if (width > maxscorewidth) { 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]) { int color; - int height = SmallFont->GetHeight() * CleanYfac; + int height, lineheight; unsigned int i; - int maxnamewidth, maxscorewidth; + int maxnamewidth, maxscorewidth, maxiconheight; int numTeams = 0; - int x, y, bottom; + int x, y, ypadding, bottom; int col2, col3, col4; if (deathmatch) @@ -233,7 +242,10 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER 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; 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; } - col2 = (SmallFont->StringWidth("Color") + 8) * CleanXfac; - col3 = col2 + (SmallFont->StringWidth("Frags") + 8) * CleanXfac; + const char *text_color = GStrings("SCORE_COLOR"), + *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; 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); - screen->DrawText (SmallFont, color, x + col2, y, deathmatch ? "Frags" : "Kills", + screen->DrawText (SmallFont, color, x + col2, y, text_frags, 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); y += height + 6 * CleanYfac; @@ -320,8 +336,8 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER { if (playeringame[sortedplayers[i] - players]) { - HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, height); - y += height + CleanYfac; + HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, ypadding, lineheight); + 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; 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)); 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); if (player->mo->ScoreIcon.isValid()) @@ -397,13 +413,13 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, 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); if (teamplay && Teams[player->userinfo.team].GetLogo ().IsNotEmpty ()) { 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); } } diff --git a/src/hu_stuff.h b/src/hu_stuff.h index ce7266c75..c8e76fee0 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -46,7 +46,7 @@ extern int chatmodeon; // [RH] Draw deathmatch scores 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); int HU_GetRowColor(player_t *player, bool hightlight); diff --git a/src/info.cpp b/src/info.cpp index 01a3e3a25..cbcfe89d6 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -56,6 +56,7 @@ extern void InitBotStuff(); extern void ClearStrifeTypes(); TArray PClassActor::AllActorClasses; +FRandom FState::pr_statetics; 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 diff --git a/src/info.h b/src/info.h index 6a82f2a04..897cac27a 100644 --- a/src/info.h +++ b/src/info.h @@ -47,6 +47,7 @@ #include "s_sound.h" #include "m_fixed.h" +#include "m_random.h" struct Baggage; class FScanner; @@ -63,18 +64,19 @@ enum struct FState { + FState *NextState; + VMFunction *ActionFunc; WORD sprite; SWORD Tics; - int Misc1; // Was changed to SBYTE, reverted to long for MBF compat - int Misc2; // Was changed to BYTE, reverted to long for MBF compat + WORD TicRange; BYTE Frame; 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; BYTE Fullbright:1; // State is fullbright BYTE SameFrame:1; // Ignore Frame (except when spawning actor) BYTE Fast:1; - FState *NextState; - VMFunction *ActionFunc; inline int GetFrame() const { @@ -90,7 +92,11 @@ struct FState } inline int GetTics() const { - return Tics; + if (TicRange == 0) + { + return Tics; + } + return Tics + pr_statetics.GenRand32() % (TicRange + 1); } inline int GetMisc1() const { @@ -112,6 +118,7 @@ struct FState bool CallAction(AActor *self, AActor *stateowner); static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); + static FRandom pr_statetics; }; struct FStateLabels; @@ -143,7 +150,6 @@ struct DmgFactors : public TMap fixed_t *CheckFactor(FName type); }; typedef TMap PainChanceList; -typedef TMap PainFlashList; struct DamageTypeDefinition { @@ -190,7 +196,6 @@ public: void SetPainChance(FName type, int chance); size_t PropagateMark(); void InitializeNativeDefaults(); - void SetPainFlash(FName type, PalEntry color); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); @@ -217,7 +222,6 @@ public: FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; - PainFlashList *PainFlashes; TArray VisibleToPlayerClass; TArray RestrictedToPlayerClass; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 2bd9d751e..18be0ad6a 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -45,6 +45,7 @@ #include "d_net.h" #include "d_dehacked.h" #include "gi.h" +#include "farchive.h" // [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 @@ -106,6 +107,20 @@ void cht_DoCheat (player_t *player, int cheat) msg = GStrings("STSTR_NCOFF"); 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: 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]) Printf ("%s\n", msg); - else - Printf ("%s is a cheater: %s\n", player->userinfo.netname, msg); + else if (cheat != CHT_CHASECAM) + Printf ("%s cheats: %s\n", player->userinfo.netname, msg); } 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; } +class DSuicider : public DThinker +{ + DECLARE_CLASS(DSuicider, DThinker) + HAS_OBJECT_POINTERS; +public: + TObjPtr 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) { + // 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) { - plyr->mo->flags |= MF_SHOOTABLE; - plyr->mo->flags2 &= ~MF2_INVULNERABLE; - //Store the players current damage factor, to restore it later. - 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; - } + DSuicider *suicide = new DSuicider; + suicide->Pawn = plyr->mo; + GC::WriteBarrier(suicide, suicide->Pawn); } } diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 08149ad96..f552d4880 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -340,9 +340,41 @@ FString GetUserFile (const char *file) struct stat info; path = NicePath("~/" GAME_DIR "/"); + 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", path.GetChars(), strerror (errno)); @@ -682,7 +714,7 @@ void M_ScreenShot (const char *filename) if (dirlen == 0) { #ifdef unix - autoname = "~/.zdoom/screenshots/"; + autoname = "~/" GAME_DIR "/screenshots/"; #elif defined(__APPLE__) char cpath[PATH_MAX]; FSRef folder; @@ -702,7 +734,6 @@ void M_ScreenShot (const char *filename) } else if (dirlen > 0) { - autoname = screenshot_dir; if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') { autoname += '/'; diff --git a/src/menu/menu.h b/src/menu/menu.h index a8ec2989b..4ab3d2e10 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -139,7 +139,6 @@ struct FOptionMenuSettings EColorRange mFontColorHighlight; EColorRange mFontColorSelection; int mLinespacing; - int mLabelOffset; }; struct FOptionMenuDescriptor : public FMenuDescriptor diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 349f08bf3..98b1dc34b 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -605,7 +605,7 @@ static void ParseOptionSettings(FScanner &sc) else if (sc.Compare("LabelOffset")) { sc.MustGetNumber(); - OptionSettings.mLabelOffset = sc.Number; + // ignored } else { diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index e415f57c8..e7b6abcef 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -214,7 +214,7 @@ void DMessageBoxMenu::Drawer () { screen->DrawText(ConFont, OptionSettings.mFontColorSelection, (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", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac, @@ -466,19 +466,7 @@ IMPLEMENT_CLASS(DEndGameMenu) DEndGameMenu::DEndGameMenu(bool playsound) { - int messageindex = gametic % gameinfo.quitmessages.Size(); - FString EndString = gameinfo.quitmessages[messageindex]; - - if (netgame) - { - EndString = GStrings("NETEND"); - return; - } - - EndString = GStrings("ENDGAME"); - - - Init(NULL, EndString, 0, playsound); + Init(NULL, GStrings(netgame ? "NETEND" : "ENDGAME"), 0, playsound); } //============================================================================= @@ -492,7 +480,10 @@ void DEndGameMenu::HandleResult(bool res) if (res) { M_ClearMenus (); - D_StartTitle (); + if (!netgame) + { + D_StartTitle (); + } } else { diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index 4c5b2ef62..08489fe23 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -58,8 +58,6 @@ void M_DrawConText (int color, int x, int y, const char *str) { - int len = (int)strlen(str); - screen->DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac_1, DTA_CellY, 8 * CleanYfac_1, @@ -400,8 +398,6 @@ void DOptionMenu::Drawer () } } mDesc->mDrawTop = y; - //int labelofs = OptionSettings.mLabelOffset * CleanXfac_1; - //int cursorspace = 14 * CleanXfac_1; int fontheight = OptionSettings.mLinespacing * CleanYfac_1; y *= CleanYfac_1; @@ -440,7 +436,7 @@ void DOptionMenu::Drawer () { 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) { - M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop + OptionSettings.mLabelOffset, "\x1a"); + M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop, "\x1a"); } 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(); } diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 461af0478..d57e13d05 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -407,11 +407,11 @@ public: C_NameKeys (description, Key1, Key2); 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 { - 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); } 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]; double range; int maxlen = 0; int right = x + (12*8 + 4) * CleanXfac_1; + int cy = y + (OptionSettings.mLinespacing-8)*CleanYfac_1; range = max - min; double ccur = clamp(cur, min, max) - min; @@ -589,14 +590,14 @@ public: if (!mSliderShort) { - M_DrawConText(CR_WHITE, x, y, "\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_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), cy, "\x13"); } else { // On 320x200 we need a shorter slider - M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x12"); - M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), y, "\x13"); + 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), cy, "\x13"); right -= 5*8*CleanXfac_1; } @@ -613,7 +614,7 @@ public: { drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor); mDrawX = indent + CURSORSPACE; - DrawSlider (mDrawX, y + OptionSettings.mLabelOffset, mMin, mMax, GetValue(), mShowValue, indent); + DrawSlider (mDrawX, y, mMin, mMax, GetValue(), mShowValue, indent); return indent; } @@ -777,8 +778,8 @@ public: if (mCVar != NULL) { int box_x = indent + CURSORSPACE; - int box_y = y + OptionSettings.mLabelOffset * CleanYfac_1 / 2; - screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + (SmallFont->GetHeight() - 1) * CleanYfac_1, + int box_y = y + CleanYfac_1; + screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + OptionSettings.mLinespacing*CleanYfac_1, -1, (uint32)*mCVar | 0xff000000); } return indent; diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index cb6f69ab6..7ac4bdf31 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -590,8 +590,8 @@ void FListMenuItemPlayerDisplay::Drawer(bool selected) if (mTranslate) trans = translationtables[TRANSLATION_Players](MAXPLAYERS); screen->DrawTexture (tex, x + 36*CleanXfac, y + 71*CleanYfac, - DTA_DestWidth, MulScale16 (tex->GetWidth() * CleanXfac, scaleX), - DTA_DestHeight, MulScale16 (tex->GetHeight() * CleanYfac, scaleY), + DTA_DestWidth, MulScale16 (tex->GetScaledWidth() * CleanXfac, scaleX), + DTA_DestHeight, MulScale16 (tex->GetScaledHeight() * CleanYfac, scaleY), DTA_Translation, trans, DTA_FlipX, sprframe->Flip & (1 << mRotation), TAG_DONE); diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 3e8f18ea8..8a6e6720d 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -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(); if (opt != NULL) @@ -316,6 +316,7 @@ void M_InitVideoModesMenu () size_t currval = 0; M_RefreshModesList(); + vid_tft.Callback(); for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++) { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0fcdfaea5..668c4dc1b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -86,10 +86,24 @@ FRandom pr_acs ("ACS"); #define STACK_SIZE 4096 #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) +// 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 #define NOT_BOTTOM 1 #define NOT_MIDDLE 2 @@ -99,13 +113,12 @@ FRandom pr_acs ("ACS"); 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), ReturnModule(module), ReturnLocals(locals), ReturnAddress(pc), - bDiscardResult(discard), - StringBuilder(str) + bDiscardResult(discard) {} ScriptFunction *ReturnFunction; @@ -113,7 +126,6 @@ struct CallReturn SDWORD *ReturnLocals; int ReturnAddress; int bDiscardResult; - FString StringBuilder; }; static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module, @@ -157,8 +169,8 @@ TArray ACS_StringsOnTheFly, ACS_StringBuilderStack; -#define STRINGBUILDER_START(Builder) if (*Builder.GetChars() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; } -#define STRINGBUILDER_FINISH(Builder) if (!ACS_StringBuilderStack.Pop(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 = ""; } //============================================================================ // @@ -3362,6 +3374,11 @@ enum EACSFunctions ACSF_ACS_NamedLockedExecuteDoor, ACSF_ACS_NamedExecuteWithResult, ACSF_ACS_NamedExecuteAlways, + ACSF_UniqueTID, + ACSF_IsTIDUsed, + ACSF_Sqrt, + ACSF_FixedSqrt, + ACSF_VectorLength, // ZDaemon ACSF_GetTeamScore = 19620, @@ -3874,6 +3891,23 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } 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(FIXED2DBL(args[0]), FIXED2DBL(args[1])).Length()); + default: break; } @@ -4295,7 +4329,7 @@ int DLevelScript::RunScript () } sp += i; ::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); pc = module->Ofs2PC (func->Address); activeFunction = func; @@ -4334,7 +4368,6 @@ int DLevelScript::RunScript () { Stack[sp++] = value; } - work = ret->StringBuilder; ret->~CallReturn(); } break; @@ -5655,6 +5688,7 @@ scriptwait: float x = FIXED2FLOAT(Stack[optstart-3]); float y = FIXED2FLOAT(Stack[optstart-2]); float holdTime = FIXED2FLOAT(Stack[optstart-1]); + fixed_t alpha; DHUDMessage *msg; if (type & HUDMSG_COLORSTRING) @@ -5666,14 +5700,16 @@ scriptwait: color = CLAMPCOLOR(Stack[optstart-4]); } - switch (type & 0xFFFF) + switch (type & 0xFF) { default: // normal + alpha = (optstart < sp) ? Stack[optstart] : FRACUNIT; msg = new DHUDMessage (activefont, work, x, y, hudwidth, hudheight, color, holdTime); break; case 1: // fade out { 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); } break; @@ -5681,6 +5717,7 @@ scriptwait: { float typeTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 0.05f; 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); } break; @@ -5688,11 +5725,22 @@ scriptwait: { float inTime = (optstart < sp) ? FIXED2FLOAT(Stack[optstart]) : 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); } 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) { 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: { 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; @@ -6482,6 +6541,25 @@ scriptwait: } 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: // This might be useful for hardware rendering, but // for software it is superfluous. @@ -6886,7 +6964,8 @@ scriptwait: } else { - userinfo_t *userinfo = &players[STACK(2)].userinfo; + player_t *pl = &players[STACK(2)]; + userinfo_t *userinfo = &pl->userinfo; switch (STACK(1)) { case PLAYERINFO_TEAM: STACK(2) = userinfo->team; break; @@ -6897,6 +6976,8 @@ scriptwait: case PLAYERINFO_MOVEBOB: STACK(2) = userinfo->MoveBob; break; case PLAYERINFO_STILLBOB: STACK(2) = userinfo->StillBob; 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; } } @@ -7519,6 +7600,3 @@ void DACSThinker::DumpScriptStatus () script = script->next; } } - -#undef STRINGBUILDER_START -#undef STRINGBUILDER_FINISH diff --git a/src/p_acs.h b/src/p_acs.h index 7a432815b..d2ae2038b 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -601,8 +601,9 @@ public: PCD_PUSHFUNCTION, // from Eternity /*360*/ PCD_CALLSTACK, // from Eternity PCD_SCRIPTWAITNAMED, + PCD_TRANSLATIONRANGE3, -/*361*/ PCODE_COMMAND_COUNT +/*363*/ PCODE_COMMAND_COUNT }; // Some constants used by ACS scripts @@ -664,7 +665,9 @@ public: PLAYERINFO_NEVERSWITCH, PLAYERINFO_MOVEBOB, PLAYERINFO_STILLBOB, - PLAYERINFO_PLAYERCLASS + PLAYERINFO_PLAYERCLASS, + PLAYERINFO_FOV, + PLAYERINFO_DESIREDFOV, }; enum EScriptState diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 434c0a98c..a8eef319a 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -926,7 +926,6 @@ public: const char *speakerName; int x, y, linesize; int width, fontheight; - int labelofs; player_t *cp = &players[consoleplayer]; @@ -1015,8 +1014,6 @@ public: } y = mYpos; - labelofs = OptionSettings.mLabelOffset; - y -= labelofs; fontheight = OptionSettings.mLinespacing; int response = 0; @@ -1041,7 +1038,7 @@ public: int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY; 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", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac, diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index f178baf11..ae483fc66 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -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 // the player then, eh? - if(!(actor->flags & MF6_SEEINVISIBLE)) + if(!(actor->flags6 & MF6_SEEINVISIBLE)) { if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || player->mo->flags3 & MF3_GHOST) @@ -3210,7 +3210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Detonate) { PARAM_ACTION_PROLOGUE; 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<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 return; } diff --git a/src/p_local.h b/src/p_local.h index 073320b9d..fdf43c2da 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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); // [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, - 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_DelSeclist(msecnode_t *); // phares 3/16/98 diff --git a/src/p_map.cpp b/src/p_map.cpp index 1ffafccad..3c457a8b4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -501,7 +501,11 @@ int P_GetFriction (const AActor *mo, int *frictionfactor) const msecnode_t *m; 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; } @@ -938,8 +942,11 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) || ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE)) ) && (level.maptime > thing->lastbump)) // Leave the bumper enough time to go away { - if (P_ActivateThingSpecial(thing, tm.thing)) - thing->lastbump = level.maptime + TICRATE; + if (tm.thing->player == NULL || !(tm.thing->player->cheats & CF_PREDICTING)) + { + if (P_ActivateThingSpecial(thing, tm.thing)) + thing->lastbump = level.maptime + TICRATE; + } } // 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 //Check 3D floors - if(newsec->e->XFloor.ffloors.Size()) + if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size()) { F3DFloor* rover; fixed_t delta1; @@ -1605,7 +1612,7 @@ void P_FakeZMovement (AActor *mo) 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; } @@ -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, - bool DamageSource, bool bombdodamage, int fulldamagedistance, bool noimpactdamage) + int flags, int fulldamagedistance) { if (bombdistance <= 0) return; @@ -4454,6 +4461,11 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b FBlockThingsIterator it(FBoundingBox(bombspot->x, bombspot->y, bombdistance<flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) continue; - if (!DamageSource && (thing == bombsource || thing == bombspot)) + if (!(flags & RADF_HURTSOURCE) && (thing == bombsource || thing == bombspot)) { // don't damage the source of the explosion 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 // because some user levels require they have a height of 16, // 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 // 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; int damage = (int)points; - if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); - else if (thing->player == NULL && !noimpactdamage) thing->flags2 |= MF2_BLASTED; + if (!(flags & RADF_NODAMAGE)) + 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 (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)) { @@ -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; thing->velx += fixed_t (finecosine[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 } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 1eceee563..3035749fe 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -37,6 +37,7 @@ #include "doomstat.h" #include "v_video.h" #include "c_cvars.h" +#include "c_dispatch.h" #include "b_bot.h" //Added by MC: #include "stats.h" #include "a_hexenglobal.h" @@ -107,6 +108,7 @@ static FRandom pr_missiledamage ("MissileDamage"); FRandom pr_slam ("SkullSlam"); static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_rockettrail("RocketTrail"); +static FRandom pr_uniquetid("UniqueTID"); // 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->effects = 0; // [RH] + mo->flags &= ~MF_SHOOTABLE; FState *nextstate=NULL; @@ -1983,7 +1986,9 @@ explode: } 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 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)) { - 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); } if (mo->waterlevel && !(mo->flags & MF_NOGRAVITY)) @@ -2474,7 +2482,7 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj) { grunted = false; // 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); grunted = true; @@ -2613,10 +2621,7 @@ AActor *AActor::TIDHash[128]; void AActor::ClearTIDHashes () { - int i; - - for (i = 0; i < 128; i++) - TIDHash[i] = NULL; + memset(TIDHash, NULL, sizeof(TIDHash)); } // @@ -2667,6 +2672,92 @@ void AActor::RemoveFromHash () 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 +// 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 @@ -3363,8 +3454,11 @@ void AActor::Tick () || ((onmo->activationtype & THINGSPEC_MissileTrigger) && (flags & MF_MISSILE)) ) && (level.maptime > onmo->lastbump)) // Leave the bumper enough time to go away { - if (P_ActivateThingSpecial(onmo, this)) - onmo->lastbump = level.maptime + TICRATE; + if (player == NULL || !(player->cheats & CF_PREDICTING)) + { + if (P_ActivateThingSpecial(onmo, this)) + onmo->lastbump = level.maptime + TICRATE; + } } if (velz != 0 && (BounceFlags & BOUNCE_Actors)) { @@ -3902,6 +3996,19 @@ void AActor::PostBeginPlay () 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() { 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 if (gameinfo.gametype & GAME_DoomStrifeChex) { - FState *state = th->FindState(NAME_Spray); if (gameinfo.gametype == GAME_Strife) { if (damage > 13) { FState *state = th->FindState(NAME_Spray); - if (state != NULL) th->SetState (state); + if (state != NULL) + { + th->SetState (state); + goto statedone; + } } 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)) { + int checked_advance = advance; 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. - 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; } } @@ -5295,7 +5406,7 @@ static fixed_t GetDefaultSpeed(PClassActor *type) 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); } @@ -5417,7 +5528,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, 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)); } @@ -5460,7 +5571,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassAct AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, 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); } @@ -5985,25 +6096,25 @@ void PrintMiscActorInfo(AActor *query) Printf("\n\tflags6: %x", query->flags6); for (flagi = 0; flagi < 31; flagi++) if (query->flags6 & 1<BounceFlags, FIXED2FLOAT(query->bouncefactor), FIXED2FLOAT(query->wallbouncefactor), query->BounceFlags); /*for (flagi = 0; flagi < 31; flagi++) if (query->BounceFlags & 1<alpha), query->renderflags); /*for (flagi = 0; flagi < 31; flagi++) if (query->renderflags & 1<special ? LineSpecialsInfo[query->special]->name : "None"), query->args[0], query->args[1], query->args[2], query->args[3], query->args[4], query->special1, query->special2); - Printf("\nTID is %d", query->tid); - Printf("\nIts coordinates are x: %f, y: %f, z:%f, floor:%f, ceiling:%f.", + Printf("\nTID: %d", query->tid); + Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.", FIXED2FLOAT(query->x), FIXED2FLOAT(query->y), FIXED2FLOAT(query->z), 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), sqrt(pow(FIXED2FLOAT(query->velx), 2) + pow(FIXED2FLOAT(query->vely), 2) + pow(FIXED2FLOAT(query->velz), 2))); } diff --git a/src/p_states.cpp b/src/p_states.cpp index fe089b4c1..ac0696347 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -909,7 +909,6 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) { FState *realstates = new FState[count]; int i; - int currange; memcpy(realstates, &StateArray[0], count*sizeof(FState)); actor->OwnedStates = realstates; @@ -917,12 +916,15 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) // adjust the state pointers // 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 - switch(realstates[i].DefineFlags) + switch (realstates[i].DefineFlags) { case SDF_STOP: // stop realstates[i].NextState = NULL; @@ -946,10 +948,11 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) } } } - - // Fix state pointers that are gotos - ResolveGotoLabels(actor, defaults, StateLabels); - + else + { + // Fix state pointers that are gotos + ResolveGotoLabels(actor, defaults, StateLabels); + } return count; } diff --git a/src/p_things.cpp b/src/p_things.cpp index 8f81f97f5..41ba20ff5 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -137,6 +137,10 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) source->PrevX = x; source->PrevY = y; source->PrevZ = z; + if (source == players[consoleplayer].camera) + { + R_ResetViewInterpolation(); + } return true; } else diff --git a/src/p_user.cpp b/src/p_user.cpp index 5dc077c14..61e9e6f11 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -471,6 +471,29 @@ void PClassPlayerPawn::EnumColorSets(TArray *out) 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(info->ParentClass); + } + return false; +} + //=========================================================================== // // player_t :: SendPitchLimits @@ -523,6 +546,28 @@ void APlayerPawn::Serialize (FArchive &arc) << DamageFade << PlayerFlags << 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 && (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, // 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; } @@ -1804,7 +1853,7 @@ void P_MovePlayer (player_t *player) 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: // @@ -2185,7 +2234,11 @@ void P_PlayerThink (player_t *player) player->inventorytics--; } // 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; } @@ -2193,6 +2246,14 @@ void P_PlayerThink (player_t *player) { 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; // 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; } - 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; if (player->mo->waterlevel < 2 && !(player->mo->flags & MF_NOGRAVITY)) @@ -2447,8 +2508,8 @@ void P_PlayerThink (player_t *player) P_PlayerInSpecialSector (player); } P_PlayerOnSpecialFlat (player, P_GetThingFloorType (player->mo)); - if (player->mo->velz <= -35*FRACUNIT && - player->mo->velz >= -40*FRACUNIT && !player->morphTics && + if (player->mo->velz <= -player->mo->FallingScreamMinSpeed && + player->mo->velz >= -player->mo->FallingScreamMaxSpeed && !player->morphTics && player->mo->waterlevel == 0) { int id = S_FindSkinnedSound (player->mo, "*falling"); @@ -2531,7 +2592,7 @@ void P_PlayerThink (player_t *player) { if (player->mo->waterlevel < 3 || (player->mo->flags2 & MF2_INVULNERABLE) || - (player->cheats & CF_GODMODE)) + (player->cheats & (CF_GODMODE | CF_NOCLIP2))) { player->mo->ResetAirSupply (); } @@ -2763,6 +2824,14 @@ void player_t::Serialize (FArchive &arc) { 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) { diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 689977911..163b0e296 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1185,7 +1185,7 @@ void R_Subsector (subsector_t *sub) frontsector->GetTexture(sector_t::floor), floorlightlevel + r_actualextralight, // killough 3/16/98 frontsector->GetAlpha(sector_t::floor), - !!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE), + !!(fakeFloor->flags & FF_ADDITIVETRANS), frontsector->GetXOffset(position), // killough 3/7/98 frontsector->GetYOffset(position), // killough 3/7/98 frontsector->GetXScale(position), @@ -1250,7 +1250,7 @@ void R_Subsector (subsector_t *sub) frontsector->GetTexture(sector_t::ceiling), ceilinglightlevel + r_actualextralight, // killough 4/11/98 frontsector->GetAlpha(sector_t::ceiling), - !!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE), + !!(fakeFloor->flags & FF_ADDITIVETRANS), frontsector->GetXOffset(position), // killough 3/7/98 frontsector->GetYOffset(position), // killough 3/7/98 frontsector->GetXScale(position), diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index b7f2ca69f..230689ad9 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -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); - g1 = clamp(g1, 0.0f, 2.0f); - b1 = clamp(b1, 0.0f, 2.0f); - r2 = clamp(r2, 0.0f, 2.0f); - g2 = clamp(g2, 0.0f, 2.0f); - b2 = clamp(b2, 0.0f, 2.0f); + r1 = clamp(r1, 0.0, 2.0); + g1 = clamp(g1, 0.0, 2.0); + b1 = clamp(b1, 0.0, 2.0); + r2 = clamp(r2, 0.0, 2.0); + g2 = clamp(g2, 0.0, 2.0); + b2 = clamp(b2, 0.0, 2.0); + + if (start > end) + { + swapvalues(start, end); + swapvalues(r1, r2); + swapvalues(g1, g2); + swapvalues(b1, b2); + } r2 -= r1; g2 -= g1; @@ -419,7 +427,7 @@ void FRemapTable::AddDesaturation(int start, int end, float r1,float g1, float b g1 *= 255; b1 *= 255; - for(int c = start; c < end; c++) + for(int c = start; c <= end; c++) { double intensity = (GPalette.BaseColors[c].r * 77 + 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; bool desaturated = false; @@ -515,39 +523,39 @@ void FRemapTable::AddToTranslation(const char * range) else if (sc.TokenType == '%') { // translation using RGB values - float r1,g1,b1,r2,g2,b2; + double r1,g1,b1,r2,g2,b2; sc.MustGetToken('['); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r1 = float(sc.Float); + r1 = sc.Float; sc.MustGetToken(','); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g1 = float(sc.Float); + g1 = sc.Float; sc.MustGetToken(','); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b1 = float(sc.Float); + b1 = sc.Float; sc.MustGetToken(']'); sc.MustGetToken(':'); sc.MustGetToken('['); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r2 = float(sc.Float); + r2 = sc.Float; sc.MustGetToken(','); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g2 = float(sc.Float); + g2 = sc.Float; sc.MustGetToken(','); sc.MustGetAnyToken(); if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b2 = float(sc.Float); + b2 = sc.Float; sc.MustGetToken(']'); AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index d61a9a22e..23490cfb8 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -38,7 +38,7 @@ struct FRemapTable void Serialize(FArchive &ar); 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 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); int StoreTranslation(); diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 415665197..6252e9575 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -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 // of the SpriteFrames array. newstart = SpriteFrames.Reserve(frame - spr.numframes); + if (spr.numframes == 0) + { + spr.spriteframes = WORD(newstart); + } } else { // 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. memset(&SpriteFrames[newstart], 0, sizeof(spriteframe_t)*(frame - spr.numframes)); spr.numframes = frame; - spr.spriteframes = newstart; } //========================================================================== diff --git a/src/r_data/voxels.cpp b/src/r_data/voxels.cpp index 50705c5cc..eca4c89c4 100644 --- a/src/r_data/voxels.cpp +++ b/src/r_data/voxels.cpp @@ -71,7 +71,7 @@ TDeletingArray VoxelDefs; struct VoxelOptions { VoxelOptions() - : DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(0) + : DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(ANGLE_90) {} int DroppedSpin; @@ -332,7 +332,7 @@ FVoxelDef *R_LoadVoxelDef(int lumpnum, int spin) voxdef->Voxel = vox; voxdef->Scale = FRACUNIT; voxdef->DroppedSpin = voxdef->PlacedSpin = spin; - voxdef->AngleOffset = 0; + voxdef->AngleOffset = ANGLE_90; Voxels.Push(vox); VoxelDefs.Push(voxdef); @@ -508,7 +508,7 @@ static void VOX_ReadOptions(FScanner &sc, VoxelOptions &opts) { 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 { diff --git a/src/r_defs.h b/src/r_defs.h index 2d1dc5ca9..5f8272b3d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -38,8 +38,8 @@ #include "dthinker.h" -#define MAXWIDTH 2880 -#define MAXHEIGHT 1800 +#define MAXWIDTH 5760 +#define MAXHEIGHT 3600 const WORD NO_INDEX = 0xffffu; const DWORD NO_SIDE = 0xffffffffu; @@ -832,11 +832,11 @@ struct side_t 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) { - 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 { @@ -850,11 +850,11 @@ struct side_t 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) { - 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 { diff --git a/src/r_draw.cpp b/src/r_draw.cpp index cc9bc9b26..165394652 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -79,6 +79,8 @@ void (*R_DrawSpan)(void); void (*R_DrawSpanMasked)(void); void (*R_DrawSpanTranslucent)(void); void (*R_DrawSpanMaskedTranslucent)(void); +void (*R_DrawSpanAddClamp)(void); +void (*R_DrawSpanMaskedAddClamp)(void); 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 void R_FillSpan (void) { @@ -2005,6 +2153,14 @@ void tmvline4_revsubclamp () 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); } @@ -2040,6 +2196,8 @@ void R_InitColumnDrawers () #endif R_DrawSpanTranslucent = R_DrawSpanTranslucentP_C; R_DrawSpanMaskedTranslucent = R_DrawSpanMaskedTranslucentP_C; + R_DrawSpanAddClamp = R_DrawSpanAddClampP_C; + R_DrawSpanMaskedAddClamp = R_DrawSpanMaskedAddClampP_C; } // [RH] Choose column drawers in a single place diff --git a/src/r_draw.h b/src/r_draw.h index ace6bde0b..c8a7f2d47 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -106,6 +106,12 @@ extern void (*R_DrawSpanTranslucent)(void); // Span drawing for masked, translucent textures. 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 extern void (*R_DrawColumnHoriz)(void); void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 0652121f7..0e8237cb6 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -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 skybox = NULL; alpha = FRACUNIT; - additive = false; } // New visplane algorithm uses hash table -- killough @@ -1047,7 +1046,7 @@ void R_DrawHeightPlanes(fixed_t height) viewy = pl->viewy; viewangle = pl->viewangle; 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 plane_shade = true; - // Additive not supported yet because the drawer function doesn't look like it can handle it. if (spanfunc != R_FillSpan) { if (masked) { - if (alpha < OPAQUE) + if (alpha < OPAQUE || additive) { - spanfunc = R_DrawSpanMaskedTranslucent; - dc_srcblend = Col2RGB8[alpha>>10]; - dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10]; + if (!additive) + { + 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 { @@ -1546,11 +1553,20 @@ void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske } else { - if (alpha < OPAQUE) + if (alpha < OPAQUE || additive) { - spanfunc = R_DrawSpanTranslucent; - dc_srcblend = Col2RGB8[alpha>>10]; - dc_destblend = Col2RGB8[(OPAQUE-alpha)>>10]; + if (!additive) + { + 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 { diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 41632d240..bfeab506a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1965,7 +1965,7 @@ void R_NewWall (bool needlights) } if (midtexture->bWorldPanning) { - rw_midtexturemid = MulScale16(rowoffset, yrepeat); + rw_midtexturemid += MulScale16(rowoffset, yrepeat); } else { @@ -2769,6 +2769,7 @@ int WallMost (short *mostbuf, const secplane_t &plane) static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat) { // fix for rounding errors + walxrepeat = abs(walxrepeat); fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0; 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) { // swall = scale, lwall = texturecolumn double top, bot, i; - double xrepeat = walxrepeat; + double xrepeat = fabs((double)walxrepeat); i = WallSX1 - centerx; 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++) { 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); top += WallUoverZstep; 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) { // lwall = texturecolumn double top, bot, i; - double xrepeat = walxrepeat; + double xrepeat = fabs((double)walxrepeat); double topstep; i = WallSX1 - centerx; @@ -2835,7 +2843,14 @@ void PrepLWall (fixed_t *lwall, fixed_t walxrepeat) 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; bot += WallInvZstep; } diff --git a/src/r_things.cpp b/src/r_things.cpp index fca102d64..680efeacb 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -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 fx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX); fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY); - fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ); - - // [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; - } + fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ) + thing->GetBobOffset(r_TicFrac); // transform the origin point tr_x = fx - viewx; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index cea8950ac..f4c343fac 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -100,6 +100,7 @@ public: void AddSound (int player_sound_id, int sfx_id); int LookupSound (int player_sound_id); FPlayerSoundHashTable &operator= (const FPlayerSoundHashTable &other); + void MarkUsed(); protected: struct Entry @@ -122,7 +123,7 @@ struct FAmbientSound int periodmax; // max # of tics for random ambients float volume; // relative volume of sound float attenuation; - FString sound; // Logical name of sound to play + FSoundID sound; // Sound to play }; TMap Ambients; @@ -219,6 +220,7 @@ extern int sfx_empty; // PUBLIC DATA DEFINITIONS ------------------------------------------------- TArray S_sfx (128); +TMap HexenMusic; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -830,6 +832,25 @@ int FPlayerSoundHashTable::LookupSound (int player_sound_id) 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 @@ -866,6 +887,7 @@ static void S_ClearSoundData() DefPlayerClassName = ""; MusicAliases.Clear(); MidiDevices.Clear(); + HexenMusic.Clear(); } //========================================================================== @@ -984,10 +1006,10 @@ static void S_AddSNDINFO (int lump) ambient->periodmax = 0; ambient->volume = 0; ambient->attenuation = 0; - ambient->sound = ""; + ambient->sound = 0; sc.MustGetString (); - ambient->sound = sc.String; + ambient->sound = FSoundID(S_FindSoundTentative(sc.String)); ambient->attenuation = 0; sc.MustGetString (); @@ -1064,16 +1086,14 @@ static void S_AddSNDINFO (int lump) case SI_Map: { // Hexen-style $MAP command - level_info_t *info; - char temp[16]; + int mapnum; - sc.MustGetNumber (); - mysnprintf (temp, countof(temp), "MAP%02d", sc.Number); - info = FindLevelInfo (temp); - sc.MustGetString (); - if (info->mapname[0] && (!(info->flags2 & LEVEL2_MUSICDEFINED))) + sc.MustGetNumber(); + mapnum = sc.Number; + sc.MustGetString(); + if (mapnum != 0) { - info->Music = sc.String; + HexenMusic[mapnum] = sc.String; } } break; @@ -1899,6 +1919,44 @@ bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time) 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 @@ -2014,6 +2072,7 @@ class AAmbientSound : public AActor public: void Serialize (FArchive &arc); + void MarkPrecacheSounds () const; void BeginPlay (); void Tick (); void Activate (AActor *activator); @@ -2040,6 +2099,22 @@ void AAmbientSound::Serialize (FArchive &arc) 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 @@ -2067,7 +2142,7 @@ void AAmbientSound::Tick () loop = CHAN_LOOP; } - if (ambient->sound.IsNotEmpty()) + if (ambient->sound != 0) { // The second argument scales the ambient sound's volume. // 0 and 100 are normal volume. The maximum volume level diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 9ba713dcb..cf2957885 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -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]->SeqName = seqname; Sequences[curseq]->Slot = slot; - Sequences[curseq]->StopSound = stopsound; + Sequences[curseq]->StopSound = FSoundID(stopsound); memcpy (Sequences[curseq]->Script, &ScriptTemp[0], sizeof(DWORD)*ScriptTemp.Size()); 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; } +//========================================================================== +// +// 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 diff --git a/src/s_sndseq.h b/src/s_sndseq.h index 41035fb1d..59b9293c0 100644 --- a/src/s_sndseq.h +++ b/src/s_sndseq.h @@ -71,10 +71,10 @@ void SN_StopAllSequences (void); struct FSoundSequence { - FName SeqName; - FName Slot; - int StopSound; - SDWORD Script[1]; // + more until end of sequence script + FName SeqName; + FName Slot; + FSoundID StopSound; + SDWORD Script[1]; // + more until end of sequence script }; void S_ParseSndSeq (int levellump); @@ -98,6 +98,7 @@ void SN_DoStop (void *); void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, float volume, int currentSoundID); FName SN_GetSequenceSlot (int sequence, seqtype_t type); +void SN_MarkPrecacheSounds (int sequence, seqtype_t type); bool SN_IsMakingLoopingSound (sector_t *sector); #endif //__S_SNDSEQ_H__ diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 2c8c74131..005f01df2 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -326,7 +326,6 @@ void S_InitData () LastLocalSndInfo = LastLocalSndSeq = ""; S_ParseSndInfo (false); S_ParseSndSeq (-1); - S_ParseMusInfo(); } //========================================================================== @@ -477,14 +476,15 @@ void S_PrecacheLevel () AActor *actor; TThinkerIterator 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; - S_sfx[actor->AttackSound].bUsed = true; - S_sfx[actor->PainSound].bUsed = true; - S_sfx[actor->DeathSound].bUsed = true; - S_sfx[actor->ActiveSound].bUsed = true; - S_sfx[actor->UseSound].bUsed = true; + actor->MarkPrecacheSounds(); + } + // Precache all extra sounds requested by this map. + for (i = 0; i < level.info->PrecacheSounds.Size(); ++i) + { + level.info->PrecacheSounds[i].MarkUsed(); } for (i = 1; i < S_sfx.Size(); ++i) @@ -1764,7 +1764,7 @@ void S_SetSoundPaused (int state) S_ResumeSound(true); if (GSnd != NULL) { - GSnd->SetInactive(false); + GSnd->SetInactive(SoundRenderer::INACTIVE_Active); } if (!netgame #ifdef _DEBUG @@ -1783,7 +1783,9 @@ void S_SetSoundPaused (int state) S_PauseSound(false, true); if (GSnd != NULL) { - GSnd->SetInactive(true); + GSnd->SetInactive(gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL ? + SoundRenderer::INACTIVE_Complete : + SoundRenderer::INACTIVE_Mute); } if (!netgame #ifdef _DEBUG diff --git a/src/s_sound.h b/src/s_sound.h index 84881862c..8b0e4ddea 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -65,6 +65,8 @@ struct sfxinfo_t FRolloffInfo Rolloff; float Attenuation; // Multiplies the attenuation passed to S_Sound. + + void MarkUsed(); // Marks this sound as used. }; // Rolloff types @@ -132,6 +134,10 @@ public: { return ID ? S_sfx[ID].name.GetChars() : NULL; } + void MarkUsed() const + { + S_sfx[ID].MarkUsed(); + } private: int ID; 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, int lumpnum, 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_UnloadSound (sfxinfo_t *sfx); sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); diff --git a/src/sdl/hardware.cpp b/src/sdl/hardware.cpp index a7af588ce..ef78b4c31 100644 --- a/src/sdl/hardware.cpp +++ b/src/sdl/hardware.cpp @@ -177,6 +177,10 @@ void I_ClosestResolution (int *width, int *height, int bits) } } +void I_SetFPSLimit(int limit) +{ +} + extern int NewWidth, NewHeight, NewBits, DisplayBits; CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index f82af7bb4..651d3ee2b 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -59,6 +59,8 @@ void I_InitGraphics (); void I_ShutdownGraphics (); void I_CreateRenderer(); +void I_SetFPSLimit(int limit); + extern IVideo *Video; #endif // __HARDWARE_H__ diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 21ba53b5b..5abb67e76 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -672,6 +672,7 @@ bool FMODSoundRenderer::Init() PrevEnvironment = DefaultEnvironments[0]; DSPClock.AsOne = 0; ChannelGroupTargetUnit = NULL; + ChannelGroupTargetUnitOutput = NULL; SfxReverbHooked = false; SfxReverbPlaceholder = NULL; OutputPlugin = 0; @@ -1155,6 +1156,15 @@ bool FMODSoundRenderer::Init() { 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_RESULT result; bool url; + FString patches; InitCreateSoundExInfo(&exinfo); mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; @@ -1614,7 +1625,20 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla exinfo.fileoffset = offset; 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); @@ -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) { - ChannelGroupTargetUnit->setActive(!inactive); + ChannelGroupTargetUnit->setActive(active); } } diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index e00b2ed27..99d627e5f 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -49,7 +49,7 @@ public: void SetSfxPaused (bool paused, int slot); // Pauses or resumes *every* channel, including environmental reverb. - void SetInactive (bool inactive); + void SetInactive (EInactiveState inactive); // Updates the position of a sound channel. void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); @@ -107,6 +107,7 @@ private: FMOD::ChannelGroup *MusicGroup; FMOD::DSP *WaterLP, *WaterReverb; FMOD::DSPConnection *SfxConnection; + FMOD::DSPConnection *ChannelGroupTargetUnitOutput; FMOD::DSP *ChannelGroupTargetUnit; FMOD::DSP *SfxReverbPlaceholder; bool SfxReverbHooked; diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 27c00e93f..0fe68a25c 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -199,7 +199,7 @@ public: } // Pauses or resumes *every* channel, including environmental reverb. - void SetInactive(bool inactive) + void SetInactive(SoundRenderer::EInactiveState inactive) { } diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index 660e47166..c905678ad 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -126,7 +126,13 @@ public: virtual void SetSfxPaused (bool paused, int slot) = 0; // 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. virtual void UpdateSoundParams3D (SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) = 0; diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index d50e236b7..7914aa256 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -42,6 +42,7 @@ #include "m_swap.h" #include "w_wad.h" #include "v_text.h" +#include "cmdlib.h" // MACROS ------------------------------------------------------------------ @@ -471,7 +472,21 @@ int FluidSynthMIDIDevice::LoadPatchSets(const char *patches) count = 0; 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); count++; diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 30d8ba6f6..ba0077903 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -944,7 +944,13 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time) if (Restarting) { 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(); } events = MakeEvents(events, max_event_p, max_time); @@ -1130,7 +1136,7 @@ void MIDIStreamer::Precache() void MIDIStreamer::CreateSMF(TArray &file, int looplimit) { DWORD delay = 0; - BYTE running_status = 0; + BYTE running_status = 255; // Always create songs aimed at GM devices. CheckCaps(MOD_MIDIPORT); @@ -1163,6 +1169,7 @@ void MIDIStreamer::CreateSMF(TArray &file, int looplimit) file.Push(BYTE(tempo >> 16)); file.Push(BYTE(tempo >> 8)); file.Push(BYTE(tempo)); + running_status = 255; } else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) { @@ -1176,6 +1183,7 @@ void MIDIStreamer::CreateSMF(TArray &file, int looplimit) file.Push(MIDI_SYSEX); WriteVarLen(file, len); memcpy(&file[file.Reserve(len - 1)], bytes, len); + running_status = 255; } } else if (MEVT_EVENTTYPE(event[2]) == 0) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 1a884472a..5d5f61062 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -608,10 +608,11 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota } else { - info.blendcolor[3] = b.a * FRACUNIT / 255; - info.blendcolor[0] = b.r * (FRACUNIT-info.blendcolor[3]); - info.blendcolor[1] = b.g * (FRACUNIT-info.blendcolor[3]); - info.blendcolor[2] = b.b * (FRACUNIT-info.blendcolor[3]); + fixed_t blendalpha = b.a * FRACUNIT / 255; + info.blendcolor[0] = b.r * blendalpha; + info.blendcolor[1] = b.g * blendalpha; + info.blendcolor[2] = b.b * blendalpha; + info.blendcolor[3] = FRACUNIT - blendalpha; info.blend = BLEND_OVERLAY; } } diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 03c6d4e7f..78d890be0 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -197,6 +197,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) if (type->NumOwnedStates == 1) { type->OwnedStates->Tics = -1; + type->OwnedStates->TicRange = 0; type->OwnedStates->Misc1 = 0; } else @@ -224,6 +225,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) else { type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].Misc1 = 0; } @@ -274,6 +276,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) else { type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].TicRange = 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].Tics = 5; + type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); i = type->NumOwnedStates - 1; type->OwnedStates[i].NextState = &type->OwnedStates[i]; type->OwnedStates[i].Tics = 1; + type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); @@ -672,6 +677,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, FScann } state.Tics = rate; + state.TicRange = 0; while (*token) { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b68c73c62..b764e48ab 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -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" if (replaceName != NAME_None) @@ -180,7 +180,8 @@ void SetReplacement(PClassActor *info, FName replaceName) 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) { diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 278ac6f8a..68d16e8fc 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -211,7 +211,7 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name); //========================================================================== 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 FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a9840d867..e4aac1a14 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -355,9 +355,9 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, else if (domissile && MissileType != NULL) { // 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); - self->z -= MissileHeight - 32*FRACUNIT; + self->z -= MissileHeight + self->GetBobOffset() - 32*FRACUNIT; if (missile) { @@ -663,6 +663,42 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) 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 @@ -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) { PARAM_ACTION_PROLOGUE; PARAM_INT_OPT (damage) { damage = -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_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; } PARAM_INT_OPT (nails) { nails = 0; } @@ -815,11 +857,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) { damage = self->GetClass()->ExplosionDamage; distance = self->GetClass()->ExplosionRadius; - if (distance < 0) - { - distance = damage; - } - hurtSource = !self->GetClass()->DontHurtShooter; + flags = !self->GetClass()->DontHurtShooter; alert = false; } 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<target != NULL && self->target->player != NULL) { @@ -852,43 +890,41 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) return 0; } -enum -{ - RTF_AFFECTSOURCE = 1, - RTF_NOIMPACTDAMAGE = 2, -}; - //========================================================================== // // A_RadiusThrust // //========================================================================== +enum +{ + RTF_AFFECTSOURCE = 1, + RTF_NOIMPACTDAMAGE = 2, + RTF_NOTMISSILE = 4, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) { PARAM_ACTION_PROLOGUE; PARAM_INT_OPT (force) { force = 128; } 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; } - bool affectSource = !!(thrustFlags & RTF_AFFECTSOURCE); - bool noimpactdamage = !!(thrustFlags & RTF_NOIMPACTDAMAGE); - bool sourcenothrust = false; if (force <= 0) force = 128; if (distance <= 0) distance = force; // 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; self->target->flags2 &= ~MF2_NODMGTHRUST; } 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); if (sourcenothrust) @@ -959,7 +995,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; fixed_t x = spawnofs_xy * finecosine[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) { @@ -976,14 +1012,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) break; 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; case 2: self->x += x; self->y += y; - missile = P_SpawnMissileAngleZSpeed(self, self->z+spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); - self->x -= x; + missile = P_SpawnMissileAngleZSpeed(self, self->z + self->GetBobOffset() + spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); + self->x -= x; self->y -= y; flags |= CMF_ABSOLUTEPITCH; @@ -1210,9 +1246,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) else if (ti) { // This seemingly senseless code is needed for proper aiming. - self->z += spawnheight - 32*FRACUNIT; - 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; + AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); + self->z -= spawnheight + self->GetBobOffset() - 32*FRACUNIT; if (missile) { @@ -1951,7 +1987,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) AActor *mo = Spawn(missile, self->x + FixedMul(distance, finecosine[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); bool res = InitSpawnedItem(self, mo, flags); @@ -2024,7 +2060,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) 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); ACTION_SET_RESULT(res); // for an inventory item's use state if (mo) @@ -2073,7 +2109,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) AActor *bo; 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); if (bo) { @@ -2435,7 +2471,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) { mo = Spawn(debris, self->x+((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) { mo->Translation = self->Translation; @@ -2760,7 +2796,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) mo = Spawn(chunk, self->x + (((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) { @@ -4712,3 +4748,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) 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; +} \ No newline at end of file diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index f60e69c40..f154bd189 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -276,6 +276,7 @@ static FFlagDef ActorFlags[]= DEFINE_DUMMY_FLAG(NONETID), // netcode-based DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), // netcode-based DEFINE_DUMMY_FLAG(CLIENTSIDEONLY), // netcode-based + DEFINE_DUMMY_FLAG(SERVERSIDEONLY), // netcode-based DEFINE_DUMMY_FLAG(EXPLODEONDEATH), // seems useless }; @@ -297,6 +298,7 @@ static FFlagDef InventoryFlags[] = DEFINE_FLAG(IF, NOATTENPICKUPSOUND, AInventory, ItemFlags), DEFINE_FLAG(IF, PERSISTENTPOWER, AInventory, ItemFlags), DEFINE_FLAG(IF, RESTRICTABSOLUTELY, AInventory, ItemFlags), + DEFINE_FLAG(IF, NEVERRESPAWN, AInventory, ItemFlags), DEFINE_DEPRECATED_FLAG(PICKUPFLASH), DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 9eb570897..8b974ac8d 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -1124,7 +1124,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); - SetReplacement(info, replaceName); + SetReplacement(sc, info, replaceName); ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast(info->ParentClass)); bag->Info = info; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 80faddf5c..8f4470058 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2280,6 +2280,26 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, jumpz, F, PlayerPawn) 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); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - info->SetPainFlash(type, color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->PainFlashes.Insert(type, color); } } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 353ab221b..03e042a21 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -56,6 +56,7 @@ #include "colormatcher.h" #include "thingdef_exp.h" #include "version.h" +#include "templates.h" TDeletingArray StateTempCalls; @@ -223,12 +224,34 @@ do_stop: sc.MustGetString(); statestring = sc.String; - sc.MustGetNumber(); - state.Tics = clamp(sc.Number, -1, 32767); if (tcall == NULL) { tcall = new FStateTempCall; } + if (sc.CheckString("RANDOM")) + { + int min, max; + + sc.MustGetStringName("("); + sc.MustGetNumber(); + min = clamp(sc.Number, -1, SHRT_MAX); + sc.MustGetStringName(","); + sc.MustGetNumber(); + max = clamp(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(sc.Number, -1, SHRT_MAX); + state.TicRange = 0; + } while (sc.GetString() && !sc.Crossed) { diff --git a/src/v_blend.cpp b/src/v_blend.cpp index d5317bd7a..05b1cffea 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -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); } - PainFlashList * pfl = CPlayer->mo->GetClass()->PainFlashes; PalEntry painFlash = CPlayer->mo->DamageFade; - - if (pfl) - { - PalEntry * color = pfl->CheckKey(CPlayer->mo->DamageTypeReceived); - - if (color) painFlash = *color; - } + CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) { diff --git a/src/v_draw.cpp b/src/v_draw.cpp index f399e4e53..87b4e0842 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -837,10 +837,10 @@ void DCanvas::FillBorder (FTexture *img) } else { - Clear (0, 0, Width, bordtop, 0, 0); // Top - Clear (0, bordtop, bordleft, Height - bordbottom, 0, 0); // Left - Clear (Width - bordright, bordtop, Width, Height - bordbottom, 0, 0); // Right - Clear (0, Height - bordbottom, Width, Height, 0, 0); // Bottom + Clear (0, 0, Width, bordtop, GPalette.BlackIndex, 0); // Top + Clear (0, bordtop, bordleft, Height - bordbottom, GPalette.BlackIndex, 0); // Left + Clear (Width - bordright, bordtop, Width, Height - bordbottom, GPalette.BlackIndex, 0); // Right + Clear (0, Height - bordbottom, Width, Height, GPalette.BlackIndex, 0); // Bottom } } diff --git a/src/v_font.cpp b/src/v_font.cpp index b7d5392cd..c1923e4ac 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -124,16 +124,26 @@ public: FSingleLumpFont (const char *fontname, int lump); protected: - void CheckFON1Chars (int lump, const BYTE *data, double *luminosity); + void CheckFON1Chars (double *luminosity); void BuildTranslations2 (); void FixupPalette (BYTE *identity, double *luminosity, const BYTE *palette, bool rescale, PalEntry *out_palette); + void LoadTranslations (); void LoadFON1 (int lump, const BYTE *data); void LoadFON2 (int lump, const BYTE *data); void LoadBMF (int lump, const BYTE *data); void CreateFontFromPic (FTextureID picnum); 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 @@ -153,16 +163,22 @@ protected: class FSpecialFont : public FFont { 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. class FFontChar1 : public FTexture { public: - FFontChar1 (FTexture *sourcelump, const BYTE *sourceremap); + FFontChar1 (FTexture *sourcelump); const BYTE *GetColumn (unsigned int column, const Span **spans_out); const BYTE *GetPixels (); + void SetSourceRemap(const BYTE *sourceremap); void Unload (); ~FFontChar1 (); @@ -178,11 +194,12 @@ protected: class FFontChar2 : public FTexture { 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 (); const BYTE *GetColumn (unsigned int column, const Span **spans_out); const BYTE *GetPixels (); + void SetSourceRemap(const BYTE *sourceremap); void Unload (); 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; FTextureID lump; char buffer[12]; FTexture **charlumps; - BYTE usedcolors[256], identity[256]; - double *luminosity; int maxyoffs; bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool stcfn121 = false; + Lump = fdlump; Chars = new CharData[count]; charlumps = new FTexture *[count]; PatchRemap = new BYTE[256]; @@ -341,7 +357,6 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, LastChar = first + count - 1; FontHeight = 0; GlobalKerning = false; - memset (usedcolors, 0, 256); Name = copystring (name); Next = FirstFont; FirstFont = this; @@ -392,18 +407,12 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, { FontHeight = height; } - RecordTextureColors (pic, usedcolors); } } - } - ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity); - - for (i = 0; i < count; i++) - { 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(); } 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; } @@ -424,9 +437,8 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, FixXMoves(); - BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); + LoadTranslations(); - delete[] luminosity; delete[] charlumps; } @@ -803,6 +815,42 @@ int FFont::GetCharWidth (int code) const 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(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(Chars[i].Pic)->SetSourceRemap(PatchRemap); + } + + BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); + + delete[] luminosity; +} + //========================================================================== // // FFont :: Preload @@ -854,8 +902,9 @@ void FFont::StaticPreloadFonts() // //========================================================================== -FFont::FFont () +FFont::FFont (int lump) { + Lump = lump; Chars = NULL; PatchRemap = 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); @@ -927,6 +976,51 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) 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(Chars[i].Pic)->SetSourceRemap(PatchRemap); + } + + BuildTranslations (luminosity, useidentity ? identity : NULL, ranges, ActiveColors, usepalette ? local_palette : NULL); +} + //========================================================================== // // FSingleLumpFont :: LoadFON1 @@ -937,7 +1031,6 @@ void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data) { - double luminosity[256]; int w, h; Chars = new CharData[256]; @@ -945,6 +1038,7 @@ void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data) w = data[4] + data[5]*256; h = data[6] + data[7]*256; + FontType = FONT1; FontHeight = h; SpaceWidth = w; FirstChar = 0; @@ -952,8 +1046,10 @@ void FSingleLumpFont::LoadFON1 (int lump, const BYTE *data) GlobalKerning = 0; PatchRemap = new BYTE[256]; - CheckFON1Chars (lump, data, luminosity); - BuildTranslations (luminosity, NULL, &TranslationParms[1][0], ActiveColors, NULL); + for(unsigned int i = 0;i < 256;++i) + Chars[i].Pic = NULL; + + LoadTranslations(); } //========================================================================== @@ -969,17 +1065,17 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) { int count, i, totalwidth; int *widths2; - BYTE identity[256]; - double luminosity[256]; - PalEntry local_palette[256]; WORD *widths; const BYTE *palette; const BYTE *data_p; + FontType = FONT2; FontHeight = data[4] + data[5]*256; FirstChar = data[6]; LastChar = data[7]; ActiveColors = data[10]; + PatchRemap = NULL; + RescalePalette = data[9] == 0; count = LastChar - FirstChar + 1; Chars = new CharData[count]; @@ -1029,7 +1125,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) 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; @@ -1043,7 +1139,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) } 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 { 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; } @@ -1087,15 +1183,14 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data) int i, chari; BYTE raw_palette[256*3]; PalEntry sort_palette[256]; - PalEntry local_palette[256]; - double luminosity[256]; - BYTE identity[256]; + FontType = BMFFONT; FontHeight = data[5]; GlobalKerning = (SBYTE)data[8]; ActiveColors = data[16]; SpaceWidth = -1; nwidth = -1; + RescalePalette = true; infolen = data[17 + ActiveColors*3]; chardata = data + 18 + ActiveColors*3 + infolen; @@ -1160,7 +1255,7 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data) 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. 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. 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+2], // height -(SBYTE)chardata[chari+3], // x offset @@ -1202,7 +1297,7 @@ void FSingleLumpFont::LoadBMF(int lump, const BYTE *data) } 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]; const BYTE *data_p; int i, j; @@ -1245,8 +1343,11 @@ void FSingleLumpFont::CheckFON1Chars (int lump, const BYTE *data, double *lumino { int destSize = SpaceWidth * FontHeight; - Chars[i].Pic = new FFontChar2 (lump, PatchRemap, int(data_p - data), SpaceWidth, FontHeight); - Chars[i].XMove = SpaceWidth; + if(!Chars[i].Pic) + { + 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. do @@ -1304,7 +1405,7 @@ void FSingleLumpFont::FixupPalette (BYTE *identity, double *luminosity, const BY identity[0] = 0; 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 g = palette[1]; @@ -1331,7 +1432,7 @@ void FSingleLumpFont::FixupPalette (BYTE *identity, double *luminosity, const BY { diver = 1.0 / 255.0; } - for (i = 1; i <= ActiveColors; ++i) + for (i = 1; i < ActiveColors; ++i) { 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); @@ -1413,8 +1515,8 @@ int FSinglePicFont::GetCharWidth (int code) const // //========================================================================== -FFontChar1::FFontChar1 (FTexture *sourcelump, const BYTE *sourceremap) -: SourceRemap (sourceremap) +FFontChar1::FFontChar1 (FTexture *sourcelump) +: SourceRemap (NULL) { UseType = FTexture::TEX_FontChar; BaseTexture = sourcelump; @@ -1453,9 +1555,16 @@ void FFontChar1::MakeTexture () Pixels = new BYTE[Width*Height]; 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; } +//========================================================================== +// +// FFontChar1 :: SetSourceRemap +// +//========================================================================== + +void FFontChar1::SetSourceRemap(const BYTE *sourceremap) +{ + Unload(); + SourceRemap = sourceremap; +} + //========================================================================== // // 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) -: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(sourceremap) +FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) +: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(NULL) { UseType = TEX_FontChar; Width = width; @@ -1594,6 +1715,18 @@ const BYTE *FFontChar2::GetColumn (unsigned int column, const Span **spans_out) return Pixels + column*Height; } +//========================================================================== +// +// FFontChar2 :: SetSourceRemap +// +//========================================================================== + +void FFontChar2::SetSourceRemap(const BYTE *sourceremap) +{ + Unload(); + SourceRemap = sourceremap; +} + //========================================================================== // // 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; - BYTE usedcolors[256], identity[256]; - double *luminosity; int maxyoffs; - int TotalColors; FTexture *pic; - + + memcpy(this->notranslate, notranslate, 256*sizeof(bool)); + Name = copystring(name); Chars = new CharData[count]; charlumps = new FTexture*[count]; @@ -1748,7 +1880,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l LastChar = first + count - 1; FontHeight = 0; GlobalKerning = false; - memset (usedcolors, 0, 256); Next = FirstFont; FirstFont = this; @@ -1771,7 +1902,58 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l { 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(Chars[i].Pic); + if(pic) + { + pic->SetSourceRemap(NULL); // Force the FFontChar1 to return the same pixels as the base texture RecordTextureColors (pic, usedcolors); } } @@ -1802,30 +1984,10 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l for (i = 0; i < count; i++) { - if (charlumps[i] != NULL) - { - 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; - } + if(Chars[i].Pic) + static_cast(Chars[i].Pic)->SetSourceRemap(PatchRemap); } - // 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); // 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; delete[] luminosity; - delete[] charlumps; } //========================================================================== @@ -1899,6 +2060,7 @@ void V_InitCustomFonts() int start; int first; int count; + int spacewidth; char cursor = '_'; while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) @@ -1913,6 +2075,7 @@ void V_InitCustomFonts() start = 33; first = 33; count = 223; + spacewidth = -1; sc.MustGetStringName ("{"); while (!sc.CheckString ("}")) @@ -1951,6 +2114,13 @@ void V_InitCustomFonts() sc.MustGetString(); 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")) { if (format == 1) goto wrong; @@ -1994,7 +2164,7 @@ void V_InitCustomFonts() } 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); } else if (format == 2) @@ -2017,7 +2187,7 @@ void V_InitCustomFonts() } 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); } } @@ -2396,19 +2566,19 @@ void V_InitFonts() } 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('['); } 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 (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 { @@ -2427,7 +2597,7 @@ void V_InitFonts() } 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"))) @@ -2455,4 +2625,14 @@ void V_ClearFonts() } FFont::FirstFont = NULL; SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL; -} \ No newline at end of file +} + +void V_RetranslateFonts() +{ + FFont *font = FFont::FirstFont; + while(font) + { + font->LoadTranslations(); + font = font->Next; + } +} diff --git a/src/v_font.h b/src/v_font.h index 27cf50b2c..13dca6e2c 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -76,15 +76,17 @@ extern int NumTextColors; class FFont { 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 FTexture *GetChar (int code, int *const width) const; virtual int GetCharWidth (int code) const; FRemapTable *GetColorTranslation (EColorRange range) const; + int GetLump() const { return Lump; } int GetSpaceWidth () const { return SpaceWidth; } int GetHeight () const { return FontHeight; } int GetDefaultKerning () const { return GlobalKerning; } + virtual void LoadTranslations(); void Preload() const; static FFont *FindFont (const char *fontname); @@ -99,7 +101,7 @@ public: void SetCursor(char c) { Cursor = c; } protected: - FFont (); + FFont (int lump); void BuildTranslations (const double *luminosity, const BYTE *identity, const void *ranges, int total_colors, const PalEntry *palette); @@ -122,6 +124,7 @@ protected: TArray Ranges; BYTE *PatchRemap; + int Lump; char *Name; FFont *Next; @@ -129,6 +132,7 @@ protected: friend struct FontsDeleter; friend void V_ClearFonts(); + friend void V_RetranslateFonts(); 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); FFont *V_GetFont(const char *); void V_InitFontColors(); +void V_RetranslateFonts(); #endif //__V_FONT_H__ diff --git a/src/v_palette.cpp b/src/v_palette.cpp index fa8ed4615..92182311b 100644 --- a/src/v_palette.cpp +++ b/src/v_palette.cpp @@ -159,8 +159,8 @@ void FPalette::SetPalette (const BYTE *colors) // 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 // translucency map. - WhiteIndex = BestColor ((DWORD *)BaseColors, 255, 255, 255); - BlackIndex = BestColor ((DWORD *)BaseColors, 0, 0, 0); + WhiteIndex = BestColor ((DWORD *)BaseColors, 255, 255, 255, 0, 255); + BlackIndex = BestColor ((DWORD *)BaseColors, 0, 0, 0, 0, 255); } // In ZDoom's new texture system, color 0 is used as the transparent color. diff --git a/src/v_video.cpp b/src/v_video.cpp index 310ca5b2e..e6145cc95 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -859,7 +859,7 @@ void DFrameBuffer::DrawRateStuff () chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount); 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); DWORD thisSec = ms/1000; @@ -1324,10 +1324,7 @@ CCMD(clean) bool V_DoModeSetup (int width, int height, int bits) { DFrameBuffer *buff = I_SetMode (width, height, screen); - int ratio; - int cwidth; - int cheight; - int cx1, cy1, cx2, cy2; + int cx1, cx2; if (buff == NULL) { @@ -1342,41 +1339,7 @@ bool V_DoModeSetup (int width, int height, int bits) // if D3DFB is being used for the display. FFont::StaticPreloadFonts(); - ratio = CheckRatio (width, height); - 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; - } + V_CalcCleanFacs(320, 200, width, height, &CleanXfac, &CleanYfac, &cx1, &cx2); CleanWidth = width / CleanXfac; CleanHeight = height / CleanYfac; @@ -1426,6 +1389,52 @@ bool V_DoModeSetup (int width, int height, int bits) 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) { int oldwidth, oldheight; diff --git a/src/v_video.h b/src/v_video.h index 6aee6d203..f6a1caeba 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -46,6 +46,7 @@ extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; extern int DisplayWidth, DisplayHeight, DisplayBits; 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; diff --git a/src/version.h b/src/version.h index 00fa5371e..b8d15d1b0 100644 --- a/src/version.h +++ b/src/version.h @@ -116,7 +116,7 @@ static inline const char *MakeSaveSig() #define BUGS_FORUM_URL "http://forum.zdoom.org/index.php?c=3" #ifdef unix -#define GAME_DIR ".zdoom" +#define GAME_DIR ".config/zdoom" #elif defined(__APPLE__) #define GAME_DIR GAMENAME #else diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 1b81aeb00..41981c45f 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1588,30 +1588,36 @@ void WI_updateNetgameStats () void WI_drawNetgameStats () { - int i, x, y, height; - int maxnamewidth, maxscorewidth; + int i, x, y, ypadding, height, lineheight; + int maxnamewidth, maxscorewidth, maxiconheight; int pwidth = IntermissionFont->GetCharWidth('%'); int icon_x, name_x, kills_x, bonus_x, secret_x; int bonus_len, secret_len; int missed_kills, missed_items, missed_secrets; EColorRange color; - const char *bonus_label; + const char *text_bonus, *text_color, *text_secret, *text_kills; // draw animated background WI_drawBackground(); y = WI_drawLF(); - HU_GetPlayerWidths(maxnamewidth, maxscorewidth); + HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); height = SmallFont->GetHeight() * CleanYfac; + lineheight = MAX(height, maxiconheight * CleanYfac); + ypadding = (lineheight - height + 1) / 2; y += 16*CleanYfac; - bonus_label = (gameinfo.gametype & GAME_Raven) ? "BONUS" : "ITEMS"; - icon_x = (SmallFont->StringWidth("COLOR") + 8) * CleanXfac; + text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); + 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; - kills_x = name_x + (maxnamewidth + SmallFont->StringWidth("XXXXX") + 8) * CleanXfac; - bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(bonus_label)) + 8) * CleanXfac; - secret_x = bonus_x + ((secret_len = SmallFont->StringWidth("SECRET")) + 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(text_bonus)) + 8) * CleanXfac; + secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac; x = (SCREENWIDTH - secret_x) >> 1; icon_x += x; @@ -1622,11 +1628,11 @@ void WI_drawNetgameStats () 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, name_x, y, "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, bonus_x - bonus_len*CleanXfac, y, bonus_label, 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, x, y, text_color, 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(text_kills)*CleanXfac, y, text_kills, 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, text_secret, DTA_CleanNoMove, true, TAG_DONE); y += height + 6 * CleanYfac; missed_kills = wbs->maxkills; @@ -1642,32 +1648,32 @@ void WI_drawNetgameStats () continue; player = &players[i]; - HU_DrawColorBar(x, y, height, i); + HU_DrawColorBar(x, y, lineheight, i); color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); if (player->mo->ScoreIcon.isValid()) { FTexture *pic = TexMan[player->mo->ScoreIcon]; 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); - WI_drawPercent(SmallFont, kills_x, y, cnt_kills[i], wbs->maxkills, false, color); + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.netname, DTA_CleanNoMove, true, TAG_DONE); + WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); missed_kills -= cnt_kills[i]; 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]; 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]; } } - y += height + CleanYfac; + y += lineheight + CleanYfac; } // Draw "MISSED" line 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); if (ng_state >= 4) { @@ -1681,7 +1687,7 @@ void WI_drawNetgameStats () // Draw "TOTAL" line y += height + 5 * CleanYfac; 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); if (ng_state >= 4) { diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 876ebdbd9..3598f52d1 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1208,6 +1208,11 @@ void D3DFB::Flip() BlockSurface[BlockNum]->UnlockRect(); } } + // Limiting the frame rate is as simple as waiting for the timer to signal this event. + if (FPSLimitEvent != NULL) + { + WaitForSingleObject(FPSLimitEvent, 1000); + } D3DDevice->Present(NULL, NULL, NULL, NULL); InScene = false; diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp index 046c7ed4f..9fb65c2a7 100644 --- a/src/win32/fb_ddraw.cpp +++ b/src/win32/fb_ddraw.cpp @@ -1201,6 +1201,10 @@ void DDrawFB::Update () LockCount = 0; UpdatePending = false; + if (FPSLimitEvent != NULL) + { + WaitForSingleObject(FPSLimitEvent, 1000); + } if (!Windowed && AppActive && !SessionState /*&& !UseBlitter && !MustBuffer*/) { HRESULT hr = PrimarySurf->Flip (NULL, FlipFlags); diff --git a/src/win32/hardware.h b/src/win32/hardware.h index 38cb15ea8..e6b23ab2f 100644 --- a/src/win32/hardware.h +++ b/src/win32/hardware.h @@ -62,6 +62,9 @@ void I_CreateRenderer(); void I_SaveWindowedPos (); void I_RestoreWindowedPos (); +void I_SetFPSLimit(int limit); + + extern IVideo *Video; #endif // __HARDWARE_H__ diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 2369d4bde..13d5027a9 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1224,14 +1224,14 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n InitCommonControls (); // Load some needed controls and be pretty under XP + // We need to load riched20.dll so that we can create the control. if (NULL == LoadLibrary ("riched20.dll")) { - // Technically, it isn't really Internet Explorer that is needed, but this - // is an example of a specific program that will provide riched20.dll. - // But considering how much extra stuff needs to be installed to make Windows 95 - // useable with pretty much any recent software, the chances are high that - // the user already has riched20.dll installed. - I_FatalError ("Sorry, you need to install Internet Explorer 3 or higher to play ZDoom on Windows 95."); + // This should only happen on basic Windows 95 installations, but since we + // don't support Windows 95, we have no obligation to provide assistance in + // getting it installed. + MessageBoxA(NULL, "Could not load riched20.dll", "ZDoom Error", MB_OK | MB_ICONSTOP); + exit(0); } #if !defined(__GNUC__) && defined(_DEBUG) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index ae2e86d32..e28ce07a7 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -607,8 +607,8 @@ void I_DetectOS(void) if (OSPlatform == os_unknown) { - Printf ("(Assuming Windows 95)\n"); - OSPlatform = os_Win95; + Printf ("(Assuming Windows 2000)\n"); + OSPlatform = os_Win2k; } } diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index ec64f2164..07151fb02 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -52,6 +52,8 @@ EXTERN_CVAR (Bool, vid_vsync) +extern HANDLE FPSLimitEvent; + class D3DTex; class D3DPal; struct FSoftwareRenderer; diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index d82744ef7..b6d6d670e 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -41,6 +41,7 @@ #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #include +#include #include #include @@ -87,6 +88,8 @@ void DoBlending (const PalEntry *from, PalEntry *to, int count, int r, int g, in // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- +static void StopFPSLimit(); + // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern HWND Window; @@ -98,20 +101,38 @@ extern bool VidResizing; EXTERN_CVAR (Bool, fullscreen) EXTERN_CVAR (Float, Gamma) +EXTERN_CVAR (Bool, cl_capfps) // PRIVATE DATA DEFINITIONS ------------------------------------------------ static HMODULE D3D9_dll; static HMODULE DDraw_dll; +static UINT FPSLimitTimer; // PUBLIC DATA DEFINITIONS ------------------------------------------------- IDirectDraw2 *DDraw; IDirect3D9 *D3D; IDirect3DDevice9 *D3Device; +HANDLE FPSLimitEvent; CVAR (Bool, vid_forceddraw, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR (Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (vid_maxfps < TICRATE && vid_maxfps != 0) + { + vid_maxfps = TICRATE; + } + else if (vid_maxfps > 1000) + { + vid_maxfps = 1000; + } + else if (cl_capfps == 0) + { + I_SetFPSLimit(vid_maxfps); + } +} #if VID_FILE_DEBUG FILE *dbg; @@ -389,10 +410,6 @@ void Win32Video::DumpAdapters() { *p = '\0'; } - // Get monitor info from GDI for more details. Windows 95 apparently does not have - // the GetMonitorInfo function. I will leave this like this for now instead of using - // GetProcAddress to see if it's still worth worrying about Windows 95 support. - // (e.g. Will anybody complain that they can't run ZDoom anymore?) HMONITOR hm = D3D->GetAdapterMonitor(i); MONITORINFOEX mi; mi.cbSize = sizeof(mi); @@ -718,4 +735,74 @@ void Win32Video::SetWindowedScale (float scale) // FIXME } -// FrameBuffer implementation ----------------------------------------------- +//========================================================================== +// +// SetFPSLimit +// +// Initializes an event timer to fire at a rate of /sec. The video +// update will wait for this timer to trigger before updating. +// +// Pass 0 as the limit for unlimited. +// Pass a negative value for the limit to use the value of vid_maxfps. +// +//========================================================================== + +void I_SetFPSLimit(int limit) +{ + if (limit < 0) + { + limit = vid_maxfps; + } + // Kill any leftover timer. + if (FPSLimitTimer != 0) + { + timeKillEvent(FPSLimitTimer); + FPSLimitTimer = 0; + } + if (limit == 0) + { // no limit + if (FPSLimitEvent != NULL) + { + CloseHandle(FPSLimitEvent); + FPSLimitEvent = NULL; + } + DPrintf("FPS timer disabled\n"); + } + else + { + if (FPSLimitEvent == NULL) + { + FPSLimitEvent = CreateEvent(NULL, FALSE, TRUE, NULL); + if (FPSLimitEvent == NULL) + { // Could not create event, so cannot use timer. + Printf("Failed to create FPS limitter event\n"); + return; + } + } + atterm(StopFPSLimit); + // Set timer event as close as we can to limit/sec, in milliseconds. + UINT period = 1000 / limit; + FPSLimitTimer = timeSetEvent(period, 0, (LPTIMECALLBACK)FPSLimitEvent, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET); + if (FPSLimitTimer == 0) + { + CloseHandle(FPSLimitEvent); + FPSLimitEvent = NULL; + Printf("Failed to create FPS limitter timer\n"); + return; + } + DPrintf("FPS timer set to %u ms\n", period); + } +} + +//========================================================================== +// +// StopFPSLimit +// +// Used for cleanup during application shutdown. +// +//========================================================================== + +static void StopFPSLimit() +{ + I_SetFPSLimit(0); +} diff --git a/src/win32/wrappers.asm b/src/win32/wrappers.asm deleted file mode 100644 index 6754ff12b..000000000 --- a/src/win32/wrappers.asm +++ /dev/null @@ -1,39 +0,0 @@ -; The Visual C++ CRT unconditionally links to IsDebuggerPresent. -; This function is not available under Windows 95, so here is a -; lowlevel replacement for it. - -extern __imp__GetModuleHandleA@4 -extern __imp__GetProcAddress@8 - - SECTION .data - -global __imp__IsDebuggerPresent@0 -__imp__IsDebuggerPresent@0: - dd IsDebuggerPresent_Check - - SECTION .rdata - -StrKERNEL32: - db "KERNEL32",0 - -StrIsDebuggerPresent: - db "IsDebuggerPresent",0 - - SECTION .text - -IsDebuggerPresent_No: - xor eax,eax - ret - -IsDebuggerPresent_Check: - push StrKERNEL32 - call [__imp__GetModuleHandleA@4] - push StrIsDebuggerPresent - push eax - call [__imp__GetProcAddress@8] - test eax,eax - jne near .itis - mov eax,IsDebuggerPresent_No -.itis: - mov [__imp__IsDebuggerPresent@0],eax - jmp eax diff --git a/src/zstring.cpp b/src/zstring.cpp index d126d607b..dc171f398 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -773,7 +773,7 @@ void FString::Insert (size_t index, const char *instr, size_t instrlen) AllocBuffer (mylen + instrlen); StrCopy (Chars, old->Chars(), index); StrCopy (Chars + index, instr, instrlen); - StrCopy (Chars + index + instrlen, Chars + index, mylen - index + 1); + StrCopy (Chars + index + instrlen, old->Chars() + index, mylen - index); old->Release(); } } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 137371447..07012e73f 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -201,6 +201,8 @@ ACTOR Actor native //: Thinker action native A_JumpIfCloser(float distance, state label); action native A_JumpIfTracerCloser(float distance, state label); action native A_JumpIfMasterCloser(float distance, state label); + action native A_JumpIfTargetOutsideMeleeRange(state label); + action native A_JumpIfTargetInsideMeleeRange(state label); action native A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); action native A_JumpIfArmorType(name Type, state label, int amount = 1); action native A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); @@ -252,9 +254,9 @@ ACTOR Actor native //: Thinker action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); action native A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); action native A_Burst(class chunktype); - action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); - action native A_RadiusThrust(int force = 128, int distance = -1, int flags = 1, int fullthrustdistance = 0); - action native A_Explode(int damage = -1, int distance = -1, bool hurtsource = true, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff"); + action native A_Blast(int flags = 0, int strength = 255, int radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); + action native A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); + action native A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff"); action native A_Stop(); action native A_Respawn(int flags = 1); action native A_BarrelDestroy(); @@ -290,6 +292,7 @@ ACTOR Actor native //: Thinker action native A_SetUserArray(name varname, int index, int value); action native A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); + action native A_SetTics(int tics); action native A_CheckSightOrRange(float distance, state label); @@ -323,7 +326,3 @@ ACTOR Actor native //: Thinker Stop } } - - - - diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 72cf767fd..1c3cf8c7d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -124,9 +124,14 @@ const int MSF_Standard = 0; const int MSF_Classic = 1; const int MSF_DontHurt = 2; +// Flags for A_Explode +const int XF_HURTSOURCE = 1; +const int XF_NOTMISSILE = 4; + // Flags for A_RadiusThrust const int RTF_AFFECTSOURCE = 1; const int RTF_NOIMPACTDAMAGE = 2; +const int RTF_NOTMISSILE = 4; // Flags for A_Blast const int BF_USEAMMO = 1; diff --git a/wadsrc/static/actors/shared/player.txt b/wadsrc/static/actors/shared/player.txt index 3edb7aa40..05fb998c3 100644 --- a/wadsrc/static/actors/shared/player.txt +++ b/wadsrc/static/actors/shared/player.txt @@ -21,6 +21,8 @@ Actor PlayerPawn : Actor native +NOBLOCKMONST Player.AttackZOffset 8 Player.JumpZ 8 + Player.GruntSpeed 12 + Player.FallingScreamSpeed 35,40 Player.ViewHeight 41 Player.ForwardMove 1,1 Player.SideMove 1,1 diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 261b91574..e6b3af2fb 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -184,3 +184,103 @@ E2B5D1400279335811C1C1C0B437D9C8 // Deathknights of the Dark Citadel, map54 limitpain } +// Daedalus: Fix SPAC_Push lines that aren't on lines you can actually push +3ABB618A475BCBC531B457BAA6E4E70A // map04 +{ + // forcefields + // the lines we're setting are already set for repeatable SPAC_Push + clearlinespecial 90 + setlinespecial 3749 ACS_Execute 23 0 1 0 0 + clearlinespecial 94 + setlinespecial 3766 ACS_Execute 23 0 2 0 0 + clearlinespecial 92 + setlinespecial 3777 ACS_Execute 23 0 3 0 0 + clearlinespecial 98 + setlinespecial 3784 ACS_Execute 23 0 4 0 0 +} +795FDE3CC1C97140F326D0152B3FCE2A // map24 +{ + // doors + clearlinespecial 1512 + setlinespecial 1505 Door_Raise 213 50 100 0 0 + setlineflags 1505 0x200 // repeatable + setactivation 1505 16 // SPAC_Push + clearlinespecial 1514 + setlinespecial 1508 Door_Raise 213 50 100 0 0 + setlineflags 1508 0x200 + setactivation 1508 16 + + clearlinespecial 1525 + setlinespecial 1522 Door_Raise 214 50 100 0 0 + setlineflags 1522 0x200 + setactivation 1522 16 + clearlinespecial 1530 + setlinespecial 1527 Door_Raise 214 50 100 0 0 + setlineflags 1527 0x200 + setactivation 1527 16 + + clearlinespecial 5277 + setlinespecial 5209 Door_Raise 24 20 255 0 0 + setlineflags 5209 0x200 + setactivation 5209 16 + clearlinespecial 5714 + setlinespecial 5267 Door_Raise 24 20 255 0 0 + setlineflags 5267 0x200 + setactivation 5267 16 + + clearlinespecial 5715 + setlinespecial 5229 Door_Raise 24 20 255 0 0 + setlineflags 5229 0x200 + setactivation 5229 16 + clearlinespecial 5345 + setlinespecial 5232 Door_Raise 24 20 255 0 0 + setlineflags 5232 0x200 + setactivation 5232 16 + + // consoles? + clearlinespecial 3639 + setlinespecial 3633 ACS_Execute 14 0 0 0 0 + setlinespecial 3635 ACS_Execute 14 0 0 0 0 + setlineflags 3633 0x200 + setlineflags 3635 0x200 + setactivation 3633 16 + setactivation 3635 16 + + clearlinespecial 3647 + setlinespecial 3644 ACS_Execute 14 0 0 0 0 + setlinespecial 3641 ACS_Execute 14 0 0 0 0 + setlineflags 3644 0x200 + setlineflags 3641 0x200 + setactivation 3644 16 + setactivation 3641 16 + + clearlinespecial 3659 + clearlinespecial 3657 + setlinespecial 3653 ACS_Execute 13 0 0 0 0 + setlinespecial 3655 ACS_Execute 13 0 0 0 0 + setlinespecial 3651 ACS_Execute 13 0 0 0 0 + setlinespecial 3654 ACS_Execute 13 0 0 0 0 + setlineflags 3653 0x200 + setlineflags 3655 0x200 + setlineflags 3651 0x200 + setlineflags 3654 0x200 + setactivation 3653 16 + setactivation 3655 16 + setactivation 3651 16 + setactivation 3654 16 +} + +// Community Chest 3 +F481922F4881F74760F3C0437FD5EDD0 // map03 +{ + // I have no idea how this conveyor belt setup manages to work under Boom. + // Set the sector the voodoo doll ends up standing on when sectors tagged + // 1 are raised so that the voodoo doll will be carried. + setlinespecial 3559 Sector_CopyScroller 17 6 0 0 0 +} + +7C1913DEE396BA26CFF22A0E9369B7D2 // Nuke Mine, e1m2 +{ + clearlinespecial 1107 + clearlinespecial 1108 +} diff --git a/wadsrc/static/decaldef.txt b/wadsrc/static/decaldef.txt index 8b12e637b..0ea9039e5 100644 --- a/wadsrc/static/decaldef.txt +++ b/wadsrc/static/decaldef.txt @@ -758,7 +758,7 @@ decal SnakeScorch21 decal SnakeScorch22 { - pic CBALSCR1 + pic CBALSCR2 shade "00 00 00" x-scale 0.7 y-scale 0.7 diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 2f9f7509e..7564ff85b 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -280,6 +280,7 @@ STSTR_KFAADDED = "Very Happy Ammo Added"; STSTR_FAADDED = "Ammo (no keys) Added"; STSTR_NCON = "No Clipping Mode ON"; STSTR_NCOFF = "No Clipping Mode OFF"; +STSTR_NC2ON = "No Clipping Mode 2 ON"; STSTR_BEHOLD = "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"; STSTR_BEHOLDX = "Power-up Toggled"; STSTR_CHOPPERS = "... doesn't suck - GM"; @@ -792,6 +793,16 @@ STARTUP3 = ""; STARTUP4 = ""; STARTUP5 = ""; +// Scoreboard text +SCORE_ITEMS = "ITEMS"; +SCORE_BONUS = "BONUS"; +SCORE_COLOR = "COLOR"; +SCORE_SECRET = "SECRET"; +SCORE_NAME = "NAME"; +SCORE_KILLS = "KILLS"; +SCORE_FRAGS = "FRAGS"; +SCORE_MISSED = "MISSED"; +SCORE_TOTAL = "TOTAL"; // Item tags: Doom weapons TAG_FIST = "Brass Knuckles"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c555818c4..38ac1bd74 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -313,11 +313,9 @@ OptionMenuSettings { // These can be overridden if a different menu fonts requires it. Linespacing 8 - LabelOffset 0 IfGame(Heretic, Hexen) { Linespacing 9 - LabelOffset 2 } } @@ -653,7 +651,7 @@ OptionMenu "VideoOptions" Submenu "Scoreboard Options", "ScoreboardOptions" StaticText " " Slider "Screen size", "screenblocks", 3.0, 12.0, 1.0, 0 - Slider "Brightness", "Gamma", 1.0, 3.0, 0.1 + Slider "Brightness", "Gamma", 0.75, 3.0, 0.05, 2 Option "Vertical Sync", "vid_vsync", "OnOff" Option "Column render mode", "r_columnmethod", "ColumnMethods" diff --git a/zdoom.vcproj b/zdoom.vcproj index 118ac6d29..b0c59a076 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2028,46 +2028,6 @@ RelativePath=".\src\win32\win32video.cpp" > - - - - - - - - - - - - - -