diff --git a/l b/l new file mode 100644 index 000000000..29f120f84 --- /dev/null +++ b/l @@ -0,0 +1,28 @@ +Mainly a bugfix release addressing the following issues: +- Fixed: SBar_DrawTextureRotated was missing the angle parameter +- Compat patch for misplaced items in Hexen MAP08. +- fixed some imprecisions in font luminosity calculation. This was still going through the palette which could result in off-by-one errors. +- fixed palette initialization for single lump fonts (FON2 and BMF) +- push sprite shadows a little back for distance sorting +- avoid multiple Dehacked mappings to the same function to fix MBF21 lookup issues. +- disallow changing the line spacing for option menus. +- be a bit more aggressive with the GC when not running the game loop. +- fixed memory leak in DShape2DBufferInfo. +- allow "INDEXFON" as an alias for "INDEXFONT". +- fixed A_Punch having a short attack range (take 2). +- GLES: Fix texture MapBuffer and AllocateBuffer create client side memory. +- Fix "out of memory" errors when the vulkan backend is asked to create zero byte sized buffers +- resolved a VM abort upon morphing while the tome of power is active +- fixed particle processing in the main thinker loop. This may not be guarded by the dynamic light flags, only the light ticking may. +- fixed handling of states with the 'light' keyword. +- Fixed broken V_BreakLines. +- treat "materials" as a known folder name for eliminating root folders in Zips. + +New Features: +- widescreen assets for all officially supported games. This version adds Hacx, Harmony and Chex Quest. +- Allow WorldUnloaded events to know the next map name (if any). +- Allow map markers to scale relative to automap zoom. +- Add cvars to control automap line alpha and thickness +- PreTravelled virtual for player and inventory. +- Allow customization of pause screen. +- ReadThisMenu / MenuDelegate overriding. diff --git a/options.checklist b/options.checklist new file mode 100644 index 000000000..c2cfa95e2 --- /dev/null +++ b/options.checklist @@ -0,0 +1,34 @@ +N/A weapon_recoil Firing a weapon pushes the player back +---N/A (todo, lastenemy?) monsters_remember 1 Friendly monsters return to old target when losing current one +!LEVEL2_NOINFIGHTING monster_infighting 1 Monsters infight +LEVEL3_AVOIDMELEE monster_backing Ranged monsters will back away from close melee targets +COMPATF2_AVOID_HAZARDS monster_avoid_hazards 1 Monsters avoid hazards such as crushing ceilings +N/A monkeys Monsters can climb steep stairs +COMPATF_MBFMONSTERMOVE monster_friction 1 Monsters are affected by friction modifiers + help_friends Friendly monsters prefer targets of friends + player_helpers Number of dogs to spawn + friend_distance 128 Friendly monsters try to keep at least this distance apart +!LEVEL3_NOJUMPDOWN dog_jumping 1 Dogs can jump down from high ledges +N/A comp_telefrag Spawners only telefrag on Map 30 +COMPATF_DROPOFF comp_dropoff 01 Discourage / prevent enemies from walking off ledges (?) +COMPATF_CORPSEGIBS,BCOMPATF_VILEGHOSTS comp_vile Archviles can create ghosts +COMPATF_LIMITPAIN comp_pain Pain elementals don't spawn lost souls if there are over 20 +--- N/A (todo) comp_skull Lost souls can spawn past impassable lines +N/A comp_blazing Blazing doors have double sounds +COMPATF_NODOORLIGHT comp_doorlight Door lighting changes are abrupt +COMPATF_LIGHT,COMPATF_SHORTTEX (partial) comp_model Assorted physics quirks and bugs +N/A comp_god God mode is removed in sector 11 & ignored at 1000+ damage +N/A comp_falloff Don't pull monsters off ledges they are hanging off of +COMPATF2_FLOORMOVE comp_floors Assorted floor bugs +N/A comp_skymap Don't apply invulnerability palette to skies +---todo comp_pursuit 1 Monsters can infight immediately when alerted +N/A comp_doorstuck Monsters get stuck in door tracks +COMPATF2_STAYONLIFT comp_staylift Monsters don't prefer staying on lifts their target is on +N/A comp_zombie Dead players can activate things +COMPATF_STAIRINDEX comp_stairs Assorted stair bugs +N/A comp_infcheat ? +N/A comp_zerotags Allow tag zero actions +N/A comp_respawn Monsters not spawned at level start respawn at the origin +N/A comp_soul Buggy lost soul bouncing +COMPATF_CROSSDROPOFF comp_ledgeblock 10 Monsters are blocked by ledges (except when scrolling) +---todo comp_friendlyspawn 1 Spawned things inherit the friend attribute from the source \ No newline at end of file diff --git a/src/gamedata/options.cpp b/src/gamedata/options.cpp new file mode 100644 index 000000000..85a9b930d --- /dev/null +++ b/src/gamedata/options.cpp @@ -0,0 +1,205 @@ +// +// Copyright(C) 2020 by Ryan Krafnick +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// DSDA Options Lump +// + +#include "filesystem.h" +#include "g_mapinfo.h" +#include "doomdef.h" +#include "templates.h" + + +struct dsda_options +{ + int monsters_remember = -1; + int monster_infighting = -1; + int monster_backing = -1; + int monster_avoid_hazards = -1; + int monster_friction = -1; + int help_friends = 0; + int player_helpers = 0; + int friend_distance = 128; + int dog_jumping = -1; + int comp_dropoff = -1; + int comp_vile = -1; + int comp_pain = -1; + int comp_doorlight = -1; + int comp_model = -1; + int comp_floors = -1; + int comp_pursuit = -1; // 1 for 'latest' + int comp_staylift = -1; + int comp_stairs = -1; + int comp_ledgeblock = -1; + int comp_friendlyspawn = -1; +}; + +struct dsda_option_t +{ + const char* key; + int dsda_options::* value; + int min; + int max; +}; + +static dsda_option_t option_list[] = { + { "monsters_remember", &dsda_options::monsters_remember, 0, 1 }, + { "monster_infighting", &dsda_options::monster_infighting, 0, 1 }, + { "monster_backing", &dsda_options::monster_backing, 0, 1 }, + { "monster_avoid_hazards", &dsda_options::monster_avoid_hazards, 0, 1 }, + { "monster_friction", &dsda_options::monster_friction, 0, 1 }, + { "help_friends", &dsda_options::help_friends, 0, 1 }, + { "player_helpers", &dsda_options::player_helpers, 0, 3 }, + { "friend_distance", &dsda_options::friend_distance, 0, 999 }, + { "dog_jumping", &dsda_options::dog_jumping, 0, 1 }, + { "comp_dropoff", &dsda_options::comp_dropoff, 0, 1 }, + { "comp_vile", &dsda_options::comp_vile, 0, 1 }, + { "comp_pain", &dsda_options::comp_pain, 0, 1 }, + { "comp_doorlight", &dsda_options::comp_doorlight, 0, 1 }, + { "comp_model", &dsda_options::comp_model, 0, 1 }, + { "comp_floors", &dsda_options::comp_floors, 0, 1 }, + { "comp_pursuit", &dsda_options::comp_pursuit, 0, 1 }, + { "comp_staylift", &dsda_options::comp_staylift, 0, 1 }, + { "comp_stairs", &dsda_options::comp_stairs, 0, 1 }, + { "comp_ledgeblock", &dsda_options::comp_ledgeblock, 0, 1 }, + { "comp_friendlyspawn", &dsda_options::comp_friendlyspawn, 0, 1 }, + { 0 } +}; + +enum { OPTIONS_LINE_LENGTH = 80 }; + +struct options_lump_t +{ + const char* data; + int length; +}; + +static const char* dsda_ReadOption(char* buf, size_t size, options_lump_t* lump) +{ + if (lump->length <= 0) + return nullptr; + + while (size > 1 && *lump->data && lump->length) + { + size--; + lump->length--; + if ((*buf++ = *lump->data++) == '\n') + break; + } + + *buf = '\0'; + + return lump->data; +} + +static struct dsda_options dsda_LumpOptions(int lumpnum) +{ + struct dsda_options mbf_options; + + options_lump_t lump; + char buf[OPTIONS_LINE_LENGTH]; + char key[OPTIONS_LINE_LENGTH]; + char* scan; + int value, count; + dsda_option_t* option; + + lump.length = fileSystem.FileLength(lumpnum); + auto data = fileSystem.ReadFile(lumpnum); + lump.data = (char*)data.GetMem(); + + while (dsda_ReadOption(buf, OPTIONS_LINE_LENGTH, &lump)) + { + if (buf[0] == '#') + continue; + + scan = buf; + count = sscanf(scan, "%79s %d", key, &value); + + if (count != 2) + continue; + + for (option = option_list; option->value; option++) + { + if (!strncmp(key, option->key, OPTIONS_LINE_LENGTH)) + { + mbf_options.*option->value = clamp(option->min, option->max, value); + + //lprintf(LO_INFO, "dsda_LumpOptions: %s = %d\n", key, value); + + break; + } + } + } + return mbf_options; +} + + +void parseOptions() +{ + int lumpnum = fileSystem.FindFile("OPTIONS"); + + if (lumpnum == -1) + return; + + auto opt = dsda_LumpOptions(lumpnum); + + auto setflag = [](auto& flag, auto mask, bool set) + { + if (set) flag |= mask; + else flag &= ~mask; + }; + + for (auto& lev : wadlevelinfos) + { + setflag(lev.flags2, LEVEL2_NOINFIGHTING, opt.monster_infighting); + setflag(lev.flags3, LEVEL3_AVOIDMELEE, opt.monster_backing); + setflag(lev.compatflags2, COMPATF2_AVOID_HAZARDS, opt.monster_avoid_hazards); + setflag(lev.compatmask2, COMPATF2_AVOID_HAZARDS, opt.monster_avoid_hazards); + setflag(lev.compatflags, COMPATF_MBFMONSTERMOVE, opt.monster_friction); + setflag(lev.compatmask, COMPATF_MBFMONSTERMOVE, opt.monster_friction); + setflag(lev.compatflags, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatmask, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatflags, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatmask, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatflags, COMPATF_CORPSEGIBS, opt.comp_vile); + setflag(lev.compatmask, COMPATF_CORPSEGIBS, opt.comp_vile); + setflag(lev.flags3, LEVEL3_VILEOPTION, opt.comp_vile); + setflag(lev.flags3, LEVEL3_NOJUMPDOWN, !opt.dog_jumping); // this one's rather pointless, but well... + setflag(lev.compatflags, COMPATF_LIMITPAIN, opt.comp_pain); + setflag(lev.compatmask, COMPATF_LIMITPAIN, opt.comp_pain); + setflag(lev.compatflags, COMPATF_NODOORLIGHT, opt.comp_doorlight); + setflag(lev.compatmask, COMPATF_NODOORLIGHT, opt.comp_doorlight); + setflag(lev.compatflags, COMPATF_LIGHT | COMPATF_SHORTTEX, opt.comp_model); // only the relevant parts of this catch-all option. + setflag(lev.compatmask, COMPATF_LIGHT | COMPATF_SHORTTEX, opt.comp_model); + setflag(lev.compatflags2, COMPATF2_FLOORMOVE, opt.comp_floors); + setflag(lev.compatmask2, COMPATF2_FLOORMOVE, opt.comp_floors); + setflag(lev.compatflags2, COMPATF2_STAYONLIFT, opt.comp_staylift); + setflag(lev.compatmask2, COMPATF2_STAYONLIFT, opt.comp_staylift); + setflag(lev.compatflags, COMPATF_STAIRINDEX, opt.comp_stairs); + setflag(lev.compatmask, COMPATF_STAIRINDEX, opt.comp_stairs); + setflag(lev.compatflags, COMPATF_CROSSDROPOFF, opt.comp_ledgeblock); + setflag(lev.compatmask, COMPATF_CROSSDROPOFF, opt.comp_ledgeblock); + + /* later. these should be supported but are not implemented yet. + if (opt.monsters_remember == 0) + if (opt.comp_pursuit) + if (opt.comp_friendlyspawn == 0) + int help_friends = 0; + int player_helpers = 0; + int friend_distance = 128; + */ + + } +} + diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index d233e09e0..377418d92 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -37,6 +37,7 @@ #include "r_data/r_translate.h" #include "texmanip.h" #include "fcolormap.h" +#include "r_sky.h" #include "p_terrain.h" #include "hwrenderer/data/buffers.h" @@ -797,6 +798,7 @@ public: int GetFloorLight() const; int GetCeilingLight() const; + int GetSpriteLight() const; sector_t *GetHeightSec() const { @@ -1795,6 +1797,10 @@ inline void sector_t::SetColor(PalEntry pe, int desat) { ::SetColor(this, pe, de inline void sector_t::SetFade(PalEntry pe) { ::SetFade(this, pe); } inline int sector_t::GetFloorLight() const { return ::GetFloorLight(this); } inline int sector_t::GetCeilingLight() const { return ::GetCeilingLight(this); } +inline int sector_t::GetSpriteLight() const +{ + return GetTexture(ceiling) == skyflatnum ? GetCeilingLight() : GetFloorLight(); +} inline double sector_t::GetFriction(int plane, double *movefac) const { return ::GetFriction(this, plane, movefac); } inline void sector_t::CheckExColorFlag() diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 3b5bb3bfe..f075f0225 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1282,7 +1282,7 @@ public: bool IsMapActor(); int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); - int UpdateWaterDepth(bool splash); + double UpdateWaterDepth(bool splash); virtual void SplashCheck(); virtual bool UpdateWaterLevel (bool splash=true); bool isFast(); @@ -1509,6 +1509,7 @@ public: return max(1., Distance2D(dest) / speed); } + int GetLightLevel(sector_t* rendersector); int ApplyDamageFactor(FName damagetype, int damage) const; int GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags = 0); void DeleteAttachedLights(); diff --git a/src/playsim/actorinlines.h b/src/playsim/actorinlines.h index 8eb7781e7..ec1807269 100644 --- a/src/playsim/actorinlines.h +++ b/src/playsim/actorinlines.h @@ -178,6 +178,22 @@ inline bool AActor::isFrozen() const return false; } +inline int AActor::GetLightLevel(sector_t* rendersector) +{ + int lightlevel = rendersector->GetSpriteLight(); + + if (flags8 & MF8_ADDLIGHTLEVEL) + { + lightlevel += LightLevel; + } + else if (LightLevel > -1) + { + lightlevel = LightLevel; + } + return lightlevel; +} + + // Consolidated from all (incomplete) variants that check if a line should block. inline bool P_IsBlockedByLine(AActor* actor, line_t* line) { diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 7b67017dc..62e67c1e0 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -4272,7 +4272,7 @@ void AActor::CheckSectorTransition(sector_t *oldsec) // //========================================================================== -int AActor::UpdateWaterDepth(bool splash) +double AActor::UpdateWaterDepth(bool splash) { double fh = -FLT_MAX; bool reset = false; diff --git a/src/r_data/colormaps.cpp b/src/r_data/colormaps.cpp index 0a616add0..2ee96133a 100644 --- a/src/r_data/colormaps.cpp +++ b/src/r_data/colormaps.cpp @@ -41,6 +41,7 @@ #include "filesystem.h" #include "r_sky.h" +#include "textures.h" #include "colormaps.h" #include "c_cvars.h" diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 1affd4db0..ede39e474 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -997,7 +997,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t // light calculation bool enhancedvision = false; - const bool UseActorLight = (thing->LightLevel > -1); // allow disabling of the fullbright flag by a brightmap definition // (e.g. to do the gun flashes of Doom's zombies correctly. @@ -1005,23 +1004,9 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t ((thing->renderflags & RF_FULLBRIGHT) && (!texture || !texture->isFullbrightDisabled())); if (fullbright) lightlevel = 255; - else if (UseActorLight) - { - int newlevel = thing->LightLevel; - if (thing->flags8 & MF8_ADDLIGHTLEVEL) - { - newlevel += hw_ClampLight(rendersector->GetTexture(sector_t::ceiling) == skyflatnum ? - rendersector->GetCeilingLight() : rendersector->GetFloorLight()); + else lightlevel = hw_ClampLight(thing->GetLightLevel(rendersector)); - newlevel = clamp(newlevel, 0, 255); - } - lightlevel = newlevel; - } - else - lightlevel = hw_ClampLight(rendersector->GetTexture(sector_t::ceiling) == skyflatnum ? - rendersector->GetCeilingLight() : rendersector->GetFloorLight()); - - foglevel = (uint8_t)clamp((UseActorLight) ? lightlevel : rendersector->lightlevel, 0, 255); + foglevel = (uint8_t)clamp(rendersector->lightlevel, 0, 255); // this *must* use the sector's light level or the fog will just look bad. lightlevel = rendersector->CheckSpriteGlow(lightlevel, thingpos); @@ -1234,8 +1219,7 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t * { if (particle->alpha==0) return; - lightlevel = hw_ClampLight(sector->GetTexture(sector_t::ceiling) == skyflatnum ? - sector->GetCeilingLight() : sector->GetFloorLight()); + lightlevel = hw_ClampLight(sector->GetSpriteLight()); foglevel = (uint8_t)clamp(sector->lightlevel, 0, 255); if (di->isFullbrightScene()) diff --git a/src/rendering/r_sky.h b/src/rendering/r_sky.h index fa36e535b..47f563e6e 100644 --- a/src/rendering/r_sky.h +++ b/src/rendering/r_sky.h @@ -29,7 +29,7 @@ #define __R_SKY_H__ #include -#include "textures.h" +#include "textureid.h" struct FLevelLocals; @@ -42,7 +42,6 @@ extern int freelookviewheight; void InitSkyMap(FLevelLocals *Level); void R_InitSkyMap(); void R_UpdateSky (uint64_t mstime); -std::pair& R_GetSkyCapColor(FGameTexture* tex); #endif //__R_SKY_H__ diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index 48cf6a326..03e00b208 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -606,14 +606,7 @@ namespace swrenderer } Add3DFloorPlanes(sub, frontsector, basecolormap, foggy, adjusted_ceilinglightlevel, adjusted_floorlightlevel); - - // killough 9/18/98: Fix underwater slowdown, by passing real sector - // instead of fake one. Improve sprite lighting by basing sprite - // lightlevels on floor & ceiling lightlevels in the surrounding area. - // [RH] Handle sprite lighting like Duke 3D: If the ceiling is a sky, sprites are lit by - // it, otherwise they are lit by the floor. - auto nc = !!(frontsector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - AddSprites(sub->sector, frontsector->GetTexture(sector_t::ceiling) == skyflatnum ? ceilinglightlevel : floorlightlevel, FakeSide, foggy, GetSpriteColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::sprites], nc)); + AddSprites(sub->sector, frontsector, FakeSide, foggy); // [RH] Add particles if ((unsigned int)(sub->Index()) < Level->subsectors.Size()) @@ -881,7 +874,7 @@ namespace swrenderer fillshort(ceilingclip, viewwidth, 0); } - void RenderOpaquePass::AddSprites(sector_t *sec, int lightlevel, WaterFakeSide fakeside, bool foggy, FDynamicColormap *basecolormap) + void RenderOpaquePass::AddSprites(sector_t *sec, sector_t* frontsector, WaterFakeSide fakeside, bool foggy) { // BSP is traversed by subsector. // A sector might have been split into several @@ -947,23 +940,22 @@ namespace swrenderer } else if (GetThingSprite(thing, sprite)) { - FDynamicColormap *thingColormap = basecolormap; - int thinglightlevel = lightlevel; + int thinglightlevel; if (sec->sectornum != thing->Sector->sectornum) // compare sectornums to account for R_FakeFlat copies. { - thinglightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); - auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - thingColormap = GetSpriteColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], nc); + frontsector = thing->Sector; } - if (thing->LightLevel > -1) - { - thinglightlevel = thing->LightLevel; + auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); + FDynamicColormap* thingColormap = GetSpriteColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::sprites], nc); - if (thing->flags8 & MF8_ADDLIGHTLEVEL) - { - thinglightlevel += thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); - thinglightlevel = clamp(thinglightlevel, 0, 255); - } + // per-sprite lightlevel and fog do not mix well in the software renderer. + if (!foggy) + { + thinglightlevel = clamp(thing->GetLightLevel(frontsector), 0, 255); + } + else + { + thinglightlevel = clamp(frontsector->lightlevel, 0, 255); } if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.h b/src/rendering/swrenderer/scene/r_opaque_pass.h index d9d20c972..ffe5a8cd2 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.h +++ b/src/rendering/swrenderer/scene/r_opaque_pass.h @@ -89,7 +89,7 @@ namespace swrenderer void FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, Fake3DOpaque opaque3dfloor); void Add3DFloorLine(seg_t *line, sector_t *frontsector); - void AddSprites(sector_t *sec, int lightlevel, WaterFakeSide fakeside, bool foggy, FDynamicColormap *basecolormap); + void AddSprites(sector_t *sec, sector_t* frontsector, WaterFakeSide fakeside, bool foggy); bool IsPotentiallyVisible(AActor *thing); bool GetThingSprite(AActor *thing, ThingSprite &sprite);