diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 40b6ab706..902d4226c 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -252,7 +252,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride & FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def); FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnim &ao, ModelAnim *def); FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnimFrame &ao, ModelAnimFrame *def); -FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); +FSerializer &Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); +FSerializer &Serialize(FSerializer& arc, const char* key, struct FStandaloneAnimation& value, struct FStandaloneAnimation* defval); void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); diff --git a/src/common/objects/dobjtype.cpp b/src/common/objects/dobjtype.cpp index 0d1bfdf9a..a3172c5e5 100644 --- a/src/common/objects/dobjtype.cpp +++ b/src/common/objects/dobjtype.cpp @@ -46,6 +46,8 @@ #include "symbols.h" #include "types.h" +#include "p_visualthinker.h" + // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- @@ -421,7 +423,7 @@ PClass *PClass::FindClass (FName zaname) // //========================================================================== -DObject *PClass::CreateNew() +DObject *PClass::CreateNew(int *statnum) { uint8_t *mem = (uint8_t *)M_Malloc (Size); assert (mem != nullptr); @@ -444,6 +446,12 @@ DObject *PClass::CreateNew() ((DObject *)mem)->SetClass (const_cast(this)); InitializeSpecials(mem, Defaults, &PClass::SpecialInits); + + if(statnum && ((DObject *)mem)->IsKindOf(RUNTIME_CLASS(DVisualThinker))) + { + *statnum = STAT_VISUALTHINKER; + } + return (DObject *)mem; } diff --git a/src/common/objects/dobjtype.h b/src/common/objects/dobjtype.h index 62e6f5ccc..17ad29862 100644 --- a/src/common/objects/dobjtype.h +++ b/src/common/objects/dobjtype.h @@ -90,7 +90,7 @@ public: PClass(); ~PClass(); void InsertIntoHash(bool native); - DObject *CreateNew(); + DObject *CreateNew(int *statnum = nullptr); PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0); void InitializeActorInfo(); diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 094223548..516de5c46 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -425,11 +425,9 @@ public: DThinker *CreateThinker(PClass *cls, int statnum = STAT_DEFAULT) { - DThinker *thinker = static_cast(cls->CreateNew()); + DThinker *thinker = static_cast(cls->CreateNew(&statnum)); assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker))); thinker->ObjectFlags |= OF_JustSpawned; - if (thinker->IsKindOf(RUNTIME_CLASS(DVisualThinker))) // [MC] This absolutely must happen for this class! - statnum = STAT_VISUALTHINKER; Thinkers.Link(thinker, statnum); thinker->Level = this; return thinker; diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index 4a4cb46fd..216b8804b 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -405,10 +405,14 @@ void FDynamicLight::UpdateLocation() Pos = target->Vec3Offset(m_off.X * c + m_off.Y * s, m_off.X * s - m_off.Y * c, m_off.Z + target->GetBobOffset()); Sector = target->subsector->sector; // Get the render sector. target->Sector is the sector according to play logic. - // Some z-coordinate fudging to prevent the light from getting too close to the floor or ceiling planes. With proper attenuation this would render them invisible. - // A distance of 5 is needed so that the light's effect doesn't become too small. - if (Z() < target->floorz + 5.) Pos.Z = target->floorz + 5.; - else if (Z() > target->ceilingz - 5.) Pos.Z = target->ceilingz - 5.; + if (!(target->flags5 & MF5_NOINTERACTION)) + { + // Some z-coordinate fudging to prevent the light from getting too close to the floor or ceiling planes. With proper attenuation this would render them invisible. + // A distance of 5 is needed so that the light's effect doesn't become too small. + // [SP] don't do this if +NOINTERACTION is set, since the object can fly right through floors and ceilings with that flag + if (Z() < target->floorz + 5.) Pos.Z = target->floorz + 5.; + else if (Z() > target->ceilingz - 5.) Pos.Z = target->ceilingz - 5.; + } // The radius being used here is always the maximum possible with the // current settings. This avoids constant relinking of flickering lights diff --git a/src/playsim/dthinker.cpp b/src/playsim/dthinker.cpp index 4229de792..e84384752 100644 --- a/src/playsim/dthinker.cpp +++ b/src/playsim/dthinker.cpp @@ -46,6 +46,8 @@ #include "g_cvars.h" #include "d_main.h" +#include "p_visualthinker.h" + static int ThinkCount; static cycle_t ThinkCycles; extern cycle_t BotSupportCycles; diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index bdceae149..f96ec1301 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -50,6 +50,7 @@ #include "actorinlines.h" #include "g_game.h" #include "serializer_doom.h" +#include "p_visualthinker.h" #include "hwrenderer/scene/hw_drawstructs.h" @@ -364,9 +365,9 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v particle->sizestep = sizestep; particle->texture = texture; particle->style = style; - particle->Roll = startroll; - particle->RollVel = rollvel; - particle->RollAcc = rollacc; + particle->Roll = (float)startroll; + particle->RollVel = (float)rollvel; + particle->RollAcc = (float)rollacc; particle->flags = flags; if(flags & SPF_LOCAL_ANIM) { @@ -1005,7 +1006,6 @@ void DVisualThinker::Construct() PT.subsector = nullptr; cursector = nullptr; PT.color = 0xffffff; - spr = new HWSprite(); AnimatedTexture.SetNull(); } @@ -1017,11 +1017,6 @@ DVisualThinker::DVisualThinker() void DVisualThinker::OnDestroy() { PT.alpha = 0.0; // stops all rendering. - if(spr) - { - delete spr; - spr = nullptr; - } Super::OnDestroy(); } @@ -1050,6 +1045,33 @@ static DVisualThinker* SpawnVisualThinker(FLevelLocals* Level, PClass* type) return DVisualThinker::NewVisualThinker(Level, type); } +void DVisualThinker::UpdateSector(subsector_t * newSubsector) +{ + assert(newSubsector); + if(PT.subsector != newSubsector) + { + PT.subsector = newSubsector; + cursector = newSubsector->sector; + } +} + +void DVisualThinker::UpdateSector() +{ + UpdateSector(Level->PointInRenderSubsector(PT.Pos)); +} + +static void UpdateSector(DVisualThinker * self) +{ + self->UpdateSector(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, UpdateSector, UpdateSector) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + self->UpdateSector(); + return 0; +} + DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnVisualThinker, SpawnVisualThinker) { PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); @@ -1068,6 +1090,19 @@ void DVisualThinker::UpdateSpriteInfo() } } +static void UpdateSpriteInfo(DVisualThinker * self) +{ + self->UpdateSpriteInfo(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, UpdateSpriteInfo, UpdateSpriteInfo) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + self->UpdateSpriteInfo(); + return 0; +} + + // This runs just like Actor's, make sure to call Super.Tick() in ZScript. void DVisualThinker::Tick() { @@ -1097,27 +1132,27 @@ void DVisualThinker::Tick() PT.Pos.Y = newxy.Y; PT.Pos.Z += PT.Vel.Z; - PT.subsector = Level->PointInRenderSubsector(PT.Pos); - cursector = PT.subsector->sector; + subsector_t * ss = Level->PointInRenderSubsector(PT.Pos); + // Handle crossing a sector portal. - if (!cursector->PortalBlocksMovement(sector_t::ceiling)) + if (!ss->sector->PortalBlocksMovement(sector_t::ceiling)) { - if (PT.Pos.Z > cursector->GetPortalPlaneZ(sector_t::ceiling)) + if (PT.Pos.Z > ss->sector->GetPortalPlaneZ(sector_t::ceiling)) { - PT.Pos += cursector->GetPortalDisplacement(sector_t::ceiling); - PT.subsector = Level->PointInRenderSubsector(PT.Pos); - cursector = PT.subsector->sector; + PT.Pos += ss->sector->GetPortalDisplacement(sector_t::ceiling); + ss = Level->PointInRenderSubsector(PT.Pos); } } - else if (!cursector->PortalBlocksMovement(sector_t::floor)) + else if (!ss->sector->PortalBlocksMovement(sector_t::floor)) { - if (PT.Pos.Z < cursector->GetPortalPlaneZ(sector_t::floor)) + if (PT.Pos.Z < ss->sector->GetPortalPlaneZ(sector_t::floor)) { - PT.Pos += cursector->GetPortalDisplacement(sector_t::floor); - PT.subsector = Level->PointInRenderSubsector(PT.Pos); - cursector = PT.subsector->sector; + PT.Pos += ss->sector->GetPortalDisplacement(sector_t::floor); + ss = Level->PointInRenderSubsector(PT.Pos); } } + + UpdateSector(ss); UpdateSpriteInfo(); } @@ -1125,7 +1160,7 @@ int DVisualThinker::GetLightLevel(sector_t* rendersector) const { int lightlevel = rendersector->GetSpriteLight(); - if (bAddLightLevel) + if (flags & VTF_AddLightLevel) { lightlevel += LightLevel; } @@ -1138,7 +1173,7 @@ int DVisualThinker::GetLightLevel(sector_t* rendersector) const FVector3 DVisualThinker::InterpolatedPosition(double ticFrac) const { - if (bDontInterpolate) return FVector3(PT.Pos); + if (flags & VTF_DontInterpolate) return FVector3(PT.Pos); DVector3 proc = Prev + (ticFrac * (PT.Pos - Prev)); return FVector3(proc); @@ -1147,7 +1182,7 @@ FVector3 DVisualThinker::InterpolatedPosition(double ticFrac) const float DVisualThinker::InterpolatedRoll(double ticFrac) const { - if (bDontInterpolate) return PT.Roll; + if (flags & VTF_DontInterpolate) return PT.Roll; return float(PrevRoll + (PT.Roll - PrevRoll) * ticFrac); } @@ -1227,17 +1262,29 @@ int DVisualThinker::GetRenderStyle() float DVisualThinker::GetOffset(bool y) const // Needed for the renderer. { if (y) - return (float)(bFlipOffsetY ? Offset.Y : -Offset.Y); + return (float)((flags & VTF_FlipOffsetY) ? Offset.Y : -Offset.Y); else - return (float)(bFlipOffsetX ? Offset.X : -Offset.X); + return (float)((flags & VTF_FlipOffsetX) ? Offset.X : -Offset.X); +} + + +FSerializer& Serialize(FSerializer& arc, const char* key, FStandaloneAnimation& value, FStandaloneAnimation* defval) +{ + arc.BeginObject(key); + arc("SwitchTic", value.SwitchTic); + arc("AnimIndex", value.AnimIndex); + arc("CurFrame", value.CurFrame); + arc("Ok", value.ok); + arc("AnimType", value.AnimType); + arc.EndObject(); + return arc; } void DVisualThinker::Serialize(FSerializer& arc) { Super::Serialize(arc); - arc - ("pos", PT.Pos) + arc ("pos", PT.Pos) ("vel", PT.Vel) ("prev", Prev) ("scale", Scale) @@ -1250,15 +1297,15 @@ void DVisualThinker::Serialize(FSerializer& arc) ("translation", Translation) ("cursector", cursector) ("scolor", PT.color) - ("flipx", bXFlip) - ("flipy", bYFlip) - ("dontinterpolate", bDontInterpolate) - ("addlightlevel", bAddLightLevel) - ("flipoffsetx", bFlipOffsetX) - ("flipoffsetY", bFlipOffsetY) ("lightlevel", LightLevel) - ("flags", PT.flags); - + ("animData", PT.animData) + ("flags", PT.flags) + ("visualThinkerFlags", flags); + + if(arc.isReading()) + { + UpdateSector(); + } } IMPLEMENT_CLASS(DVisualThinker, false, false); @@ -1269,6 +1316,7 @@ DEFINE_FIELD_NAMED(DVisualThinker, PT.Roll, Roll); DEFINE_FIELD_NAMED(DVisualThinker, PT.alpha, Alpha); DEFINE_FIELD_NAMED(DVisualThinker, PT.texture, Texture); DEFINE_FIELD_NAMED(DVisualThinker, PT.flags, Flags); +DEFINE_FIELD_NAMED(DVisualThinker, flags, VisualThinkerFlags); DEFINE_FIELD(DVisualThinker, Prev); DEFINE_FIELD(DVisualThinker, Scale); @@ -1277,9 +1325,3 @@ DEFINE_FIELD(DVisualThinker, PrevRoll); DEFINE_FIELD(DVisualThinker, Translation); DEFINE_FIELD(DVisualThinker, LightLevel); DEFINE_FIELD(DVisualThinker, cursector); -DEFINE_FIELD(DVisualThinker, bXFlip); -DEFINE_FIELD(DVisualThinker, bYFlip); -DEFINE_FIELD(DVisualThinker, bDontInterpolate); -DEFINE_FIELD(DVisualThinker, bAddLightLevel); -DEFINE_FIELD(DVisualThinker, bFlipOffsetX); -DEFINE_FIELD(DVisualThinker, bFlipOffsetY); diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index 735a87e81..1e5ba2705 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -147,56 +147,4 @@ struct SPortalHit void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = nullAngle, int duration = TICRATE, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270, DAngle pitch = nullAngle); void P_DrawSplash (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int kind); void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int updown, int kind); -void P_DisconnectEffect (AActor *actor); - -//=========================================================================== -// -// VisualThinkers -// by Major Cooke -// Credit to phantombeta, RicardoLuis0 & RaveYard for aid -// -//=========================================================================== -class HWSprite; -struct FTranslationID; -class DVisualThinker : public DThinker -{ - DECLARE_CLASS(DVisualThinker, DThinker); -public: - DVector3 Prev; - DVector2 Scale, - Offset; - float PrevRoll; - int16_t LightLevel; - FTranslationID Translation; - FTextureID AnimatedTexture; - sector_t *cursector; - - bool bFlipOffsetX, - bFlipOffsetY, - bXFlip, - bYFlip, // flip the sprite on the x/y axis. - bDontInterpolate, // disable all interpolation - bAddLightLevel; // adds sector light level to 'LightLevel' - - // internal only variables - particle_t PT; - HWSprite *spr; //in an effort to cache the result. - - DVisualThinker(); - void Construct(); - void OnDestroy() override; - - static DVisualThinker* NewVisualThinker(FLevelLocals* Level, PClass* type); - void SetTranslation(FName trname); - int GetRenderStyle(); - bool isFrozen(); - int GetLightLevel(sector_t *rendersector) const; - FVector3 InterpolatedPosition(double ticFrac) const; - float InterpolatedRoll(double ticFrac) const; - - void Tick() override; - void UpdateSpriteInfo(); - void Serialize(FSerializer& arc) override; - - float GetOffset(bool y) const; -}; \ No newline at end of file +void P_DisconnectEffect (AActor *actor); \ No newline at end of file diff --git a/src/playsim/p_visualthinker.h b/src/playsim/p_visualthinker.h new file mode 100644 index 000000000..d4b1e262d --- /dev/null +++ b/src/playsim/p_visualthinker.h @@ -0,0 +1,62 @@ +#pragma once + +#include "palettecontainer.h" +#include "hwrenderer/scene/hw_drawstructs.h" + + +//=========================================================================== +// +// VisualThinkers +// by Major Cooke +// Credit to phantombeta, RicardoLuis0 & RaveYard for aid +// +//=========================================================================== + +enum EVisualThinkerFlags +{ + VTF_FlipOffsetX = 1 << 0, + VTF_FlipOffsetY = 1 << 1, + VTF_FlipX = 1 << 2, + VTF_FlipY = 1 << 3, // flip the sprite on the x/y axis. + VTF_DontInterpolate = 1 << 4, // disable all interpolation + VTF_AddLightLevel = 1 << 5, // adds sector light level to 'LightLevel' +}; + +class DVisualThinker : public DThinker +{ + DECLARE_CLASS(DVisualThinker, DThinker); + void UpdateSector(subsector_t * newSubsector); +public: + DVector3 Prev; + DVector2 Scale, + Offset; + float PrevRoll; + int16_t LightLevel; + FTranslationID Translation; + FTextureID AnimatedTexture; + sector_t *cursector; + + int flags; + + // internal only variables + particle_t PT; + + DVisualThinker(); + void Construct(); + void OnDestroy() override; + + static DVisualThinker* NewVisualThinker(FLevelLocals* Level, PClass* type); + void SetTranslation(FName trname); + int GetRenderStyle(); + bool isFrozen(); + int GetLightLevel(sector_t *rendersector) const; + FVector3 InterpolatedPosition(double ticFrac) const; + float InterpolatedRoll(double ticFrac) const; + + void Tick() override; + void UpdateSpriteInfo(); + void UpdateSector(); + void Serialize(FSerializer& arc) override; + + float GetOffset(bool y) const; +}; \ No newline at end of file diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index a86e09177..7fb1cbe01 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -45,6 +45,8 @@ #include "hw_walldispatcher.h" #include "hw_flatdispatcher.h" +#include "p_visualthinker.h" + #ifdef ARCH_IA32 #include #endif // ARCH_IA32 @@ -670,10 +672,9 @@ void HWDrawInfo::RenderParticles(subsector_t *sub, sector_t *front, FRenderState int clipres = mClipPortal->ClipPoint(sp->PT.Pos.XY()); if (clipres == PClip_InFront) continue; } - - assert(sp->spr); - sp->spr->ProcessParticle(this, state, &sp->PT, front, sp); + HWSprite sprite; + sprite.ProcessParticle(this, state, &sp->PT, front, sp); } for (int i = Level->ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Level->Particles[i].snext) { diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 2c5328647..6b003ece0 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -59,6 +59,8 @@ #include "hw_drawcontext.h" #include "quaternion.h" +#include "p_visualthinker.h" + extern TArray sprites; extern TArray SpriteFrames; extern uint32_t r_renderercaps; @@ -1657,7 +1659,7 @@ void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t ? TexAnim.UpdateStandaloneAnimation(spr->PT.animData, di->Level->maptime + timefrac) : spr->PT.texture, !custom_anim); - if (spr->bDontInterpolate) + if (spr->flags & VTF_DontInterpolate) timefrac = 0.; FVector3 interp = spr->InterpolatedPosition(timefrac); @@ -1687,13 +1689,12 @@ void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t double mult = 1.0 / sqrt(ps); // shrink slightly r.Scale(mult * ps, mult); } - - if (spr->bXFlip) + if (spr->flags & VTF_FlipX) { std::swap(ul,ur); r.left = -r.width - r.left; // mirror the sprite's x-offset } - if (spr->bYFlip) std::swap(vt,vb); + if (spr->flags & VTF_FlipY) std::swap(vt,vb); float viewvecX = vp.ViewVector.X; float viewvecY = vp.ViewVector.Y; diff --git a/src/scripting/zscript/zcc_compile_doom.cpp b/src/scripting/zscript/zcc_compile_doom.cpp index a86ea9a0e..bd7ba9048 100644 --- a/src/scripting/zscript/zcc_compile_doom.cpp +++ b/src/scripting/zscript/zcc_compile_doom.cpp @@ -161,17 +161,14 @@ bool ZCCDoomCompiler::CompileProperties(PClass *type, TArray &Pr bool ZCCDoomCompiler::CompileFlagDefs(PClass *type, TArray &Properties, FName prefix) { - if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - Error(Properties[0], "Flags can only be defined for actors"); - return false; - } + //[RL0] allow property-less flagdefs for non-actors + bool isActor = type->IsDescendantOf(RUNTIME_CLASS(AActor)); for (auto p : Properties) { PField *field; FName referenced = FName(p->RefName); - if (FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0) + if (isActor && FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0) { // only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use. prefix = referenced; @@ -191,24 +188,28 @@ bool ZCCDoomCompiler::CompileFlagDefs(PClass *type, TArray &Prope } } else field = nullptr; - - - FString qualifiedname; - // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. - // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. + FName name = FName(p->NodeName); - for (int i = 0; i < 2; i++) - { - if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars()); - else - { - if (prefix == NAME_None) continue; - qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars()); - } - if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None))) + if(isActor) + { + FString qualifiedname; + // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. + // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. + + for (int i = 0; i < 2; i++) { - Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); + if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars()); + else + { + if (prefix == NAME_None) continue; + qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars()); + } + + if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None))) + { + Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); + } } } diff --git a/wadsrc/static/graphics/AMMNUM0.png b/wadsrc/static/graphics/AMMNUM0.png new file mode 100644 index 000000000..6924f3956 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM0.png differ diff --git a/wadsrc/static/graphics/AMMNUM1.png b/wadsrc/static/graphics/AMMNUM1.png new file mode 100644 index 000000000..14dab57fe Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM1.png differ diff --git a/wadsrc/static/graphics/AMMNUM2.png b/wadsrc/static/graphics/AMMNUM2.png new file mode 100644 index 000000000..4c6514893 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM2.png differ diff --git a/wadsrc/static/graphics/AMMNUM3.png b/wadsrc/static/graphics/AMMNUM3.png new file mode 100644 index 000000000..bcd495a68 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM3.png differ diff --git a/wadsrc/static/graphics/AMMNUM4.png b/wadsrc/static/graphics/AMMNUM4.png new file mode 100644 index 000000000..6d373156c Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM4.png differ diff --git a/wadsrc/static/graphics/AMMNUM5.png b/wadsrc/static/graphics/AMMNUM5.png new file mode 100644 index 000000000..c840a0a00 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM5.png differ diff --git a/wadsrc/static/graphics/AMMNUM6.png b/wadsrc/static/graphics/AMMNUM6.png new file mode 100644 index 000000000..2c0f3b101 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM6.png differ diff --git a/wadsrc/static/graphics/AMMNUM7.png b/wadsrc/static/graphics/AMMNUM7.png new file mode 100644 index 000000000..1739247cd Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM7.png differ diff --git a/wadsrc/static/graphics/AMMNUM8.png b/wadsrc/static/graphics/AMMNUM8.png new file mode 100644 index 000000000..0bb5499fa Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM8.png differ diff --git a/wadsrc/static/graphics/AMMNUM9.png b/wadsrc/static/graphics/AMMNUM9.png new file mode 100644 index 000000000..fa9232fa4 Binary files /dev/null and b/wadsrc/static/graphics/AMMNUM9.png differ diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 3aec0a6f1..e56b826c3 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1410,6 +1410,8 @@ enum ELevelFlags LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support. LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag. LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame + LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map + LEVEL3_SECRET = 0x00200000, // level is a secret level VKDLEVELFLAG_NOUSERSAVE = 0x00000001, VKDLEVELFLAG_NOAUTOMAP = 0x00000002, @@ -1519,3 +1521,13 @@ enum EModelFlags MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied MDL_FORCECULLBACKFACES = 1<<14, }; + +enum EVisualThinkerFlags +{ + VTF_FlipOffsetX = 1 << 0, + VTF_FlipOffsetY = 1 << 1, + VTF_FlipX = 1 << 2, + VTF_FlipY = 1 << 3, // flip the sprite on the x/y axis. + VTF_DontInterpolate = 1 << 4, // disable all interpolation + VTF_AddLightLevel = 1 << 5, // adds sector light level to 'LightLevel' +}; diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index 69f5d66fe..e25c82229 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -15,27 +15,29 @@ enum ESoundFlags // modifier flags CHAN_LISTENERZ = 8, CHAN_MAYBE_LOCAL = 16, - CHAN_UI = 32, - CHAN_NOPAUSE = 64, + CHAN_UI = 32, // Do not record sound in savegames. + CHAN_NOPAUSE = 64, // Do not pause this sound in menus. CHAN_LOOP = 256, CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL), // Do not use this with A_StartSound! It would not do what is expected. - CHAN_NOSTOP = 4096, - CHAN_OVERLAP = 8192, + CHAN_NOSTOP = 4096, // only for A_PlaySound. Does not start if channel is playing something. + CHAN_OVERLAP = 8192, // [MK] Does not stop any sounds in the channel and instead plays over them. // Same as above, with an F appended to allow better distinction of channel and channel flags. - CHANF_DEFAULT = 0, // just to make the code look better and avoid literal 0's. + CHANF_DEFAULT = 0, // just to make the code look better and avoid literal 0's. CHANF_LISTENERZ = 8, CHANF_MAYBE_LOCAL = 16, - CHANF_UI = 32, - CHANF_NOPAUSE = 64, + CHANF_UI = 32, // Do not record sound in savegames. + CHANF_NOPAUSE = 64, // Do not pause this sound in menus. CHANF_LOOP = 256, - CHANF_NOSTOP = 4096, - CHANF_OVERLAP = 8192, - CHANF_LOCAL = 16384, + CHANF_NOSTOP = 4096, // only for A_PlaySound. Does not start if channel is playing something. + CHANF_OVERLAP = 8192, // [MK] Does not stop any sounds in the channel and instead plays over them. + CHANF_LOCAL = 16384, // only plays locally for the calling actor + CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood) + CHANF_FORCE = 65536, // Start, even if sound is paused. + CHANF_SINGULAR = 0x20000, // Only start if no sound of this name is already playing. CHANF_LOOPING = CHANF_LOOP | CHANF_NOSTOP, // convenience value for replicating the old 'looping' boolean. - }; // sound attenuation values diff --git a/wadsrc/static/zscript/visualthinker.zs b/wadsrc/static/zscript/visualthinker.zs index 12a8c41d6..45b32865c 100644 --- a/wadsrc/static/zscript/visualthinker.zs +++ b/wadsrc/static/zscript/visualthinker.zs @@ -10,14 +10,18 @@ Class VisualThinker : Thinker native Alpha; native TextureID Texture; native TranslationID Translation; - native uint16 Flags; native int16 LightLevel; - native bool bFlipOffsetX, - bFlipOffsetY, - bXFlip, - bYFlip, - bDontInterpolate, - bAddLightLevel; + + native uint16 Flags; + native int VisualThinkerFlags; + + FlagDef FlipOffsetX : VisualThinkerFlags, 0; + FlagDef FlipOffsetY : VisualThinkerFlags, 1; + FlagDef XFlip : VisualThinkerFlags, 2; + FlagDef YFlip : VisualThinkerFlags, 3; + FlagDef DontInterpolate : VisualThinkerFlags, 4; + FlagDef AddLightLevel : VisualThinkerFlags, 5; + native Color scolor; native Sector CurSector; // can be null! @@ -26,8 +30,11 @@ Class VisualThinker : Thinker native native void SetRenderStyle(int mode); // see ERenderStyle native bool IsFrozen(); + native protected void UpdateSector(); // needs to be called if the thinker is set to a non-ticking statnum and the position is modified (or if Tick is overriden and doesn't call Super.Tick()) + native protected void UpdateSpriteInfo(); // needs to be called every time the texture is updated if the thinker uses SPF_LOCAL_ANIM and is set to a non-ticking statnum (or if Tick is overriden and doesn't call Super.Tick()) + static VisualThinker Spawn(Class type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0, - double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, TranslationID trans = 0) + double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, TranslationID trans = 0, int VisualThinkerFlags = 0) { if (!Level) return null; @@ -44,6 +51,9 @@ Class VisualThinker : Thinker native p.SetRenderStyle(style); p.Translation = trans; p.Flags = flags; + p.VisualThinkerFlags = VisualThinkerFlags; + p.UpdateSector(); + p.UpdateSpriteInfo(); } return p; }