diff --git a/src/playsim/p_trace.cpp b/src/playsim/p_trace.cpp index dd9c7bb99..02608b8de 100644 --- a/src/playsim/p_trace.cpp +++ b/src/playsim/p_trace.cpp @@ -901,6 +901,41 @@ bool FTraceInfo::TraceTraverse (int ptflags) Results->Distance = MaxDist; Results->Fraction = 1.; } + + // [MK] set 3d floor on plane hits (if any) + // modders will need this to get accurate plane normals on slopes + if (Results->HitType == TRACE_HitFloor) + { + double secbottom = Results->Sector->floorplane.ZatPoint(Results->HitPos); + for (auto rover : Results->Sector->e->XFloor.ffloors) + { + if (!(rover->flags&FF_EXISTS)) + continue; + double ff_top = rover->top.plane->ZatPoint(Results->HitPos); + if (fabs(ff_top-secbottom) < EQUAL_EPSILON) + continue; + if (fabs(ff_top-Results->HitPos.Z) > EQUAL_EPSILON) + continue; + Results->ffloor = rover; + break; + } + } + else if (Results->HitType == TRACE_HitCeiling) + { + double sectop = Results->Sector->ceilingplane.ZatPoint(Results->HitPos); + for (auto rover : Results->Sector->e->XFloor.ffloors) + { + if (!(rover->flags&FF_EXISTS)) + continue; + double ff_bottom = rover->bottom.plane->ZatPoint(Results->HitPos); + if (fabs(ff_bottom-sectop) < EQUAL_EPSILON) + continue; + if (fabs(ff_bottom-Results->HitPos.Z) > EQUAL_EPSILON) + continue; + Results->ffloor = rover; + break; + } + } return Results->HitType != TRACE_HitNone; } @@ -1008,6 +1043,7 @@ DEFINE_FIELD_X(TraceResults, FTraceResults, Side) DEFINE_FIELD_X(TraceResults, FTraceResults, Tier) DEFINE_FIELD_X(TraceResults, FTraceResults, unlinked) DEFINE_FIELD_X(TraceResults, FTraceResults, HitType) +DEFINE_FIELD_X(TraceResults, FTraceResults, ffloor) DEFINE_FIELD_X(TraceResults, FTraceResults, CrossedWater) DEFINE_FIELD_X(TraceResults, FTraceResults, CrossedWaterPos) DEFINE_FIELD_X(TraceResults, FTraceResults, Crossed3DWater) diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index e6113e847..fc12c97fa 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -1340,6 +1340,72 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) return 0; } + static F3DFloor* Get3DFloor(sector_t *self, int index) + { + if ((index < 0) || (index >= self->e->XFloor.ffloors.Size())) + return nullptr; + return self->e->XFloor.ffloors[index]; + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, Get3DFloor, Get3DFloor) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(index); + ACTION_RETURN_POINTER(Get3DFloor(self,index)); + } + + static int Get3DFloorCount(sector_t *self) + { + return self->e->XFloor.ffloors.Size(); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, Get3DFloorCount, Get3DFloorCount) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + ACTION_RETURN_INT(self->e->XFloor.ffloors.Size()); + } + + static sector_t* GetAttached(sector_t *self, int index) + { + if ((index < 0) || (index >= self->e->XFloor.attached.Size())) + return nullptr; + return self->e->XFloor.attached[index]; + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetAttached, GetAttached) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(index); + ACTION_RETURN_POINTER(GetAttached(self,index)); + } + + static int GetAttachedCount(sector_t *self) + { + return self->e->XFloor.attached.Size(); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetAttachedCount, GetAttachedCount) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + ACTION_RETURN_INT(self->e->XFloor.attached.Size()); + } + + static int Get3DFloorTexture(F3DFloor *self, int pos) + { + if ( pos ) + return self->bottom.texture->GetIndex(); + return self->top.texture->GetIndex(); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_F3DFloor, GetTexture, Get3DFloorTexture) + { + PARAM_SELF_STRUCT_PROLOGUE(F3DFloor); + PARAM_INT(pos); + if ( pos ) + ACTION_RETURN_INT(self->bottom.texture->GetIndex()); + ACTION_RETURN_INT(self->top.texture->GetIndex()); + } + //=========================================================================== // // line_t exports @@ -3183,6 +3249,14 @@ DEFINE_FIELD_X(Secplane, secplane_t, normal) DEFINE_FIELD_X(Secplane, secplane_t, D) DEFINE_FIELD_X(Secplane, secplane_t, negiC) +DEFINE_FIELD_NAMED_X(F3DFloor, F3DFloor, bottom.plane, bottom); +DEFINE_FIELD_NAMED_X(F3DFloor, F3DFloor, top.plane, top); +DEFINE_FIELD_X(F3DFloor, F3DFloor, flags); +DEFINE_FIELD_X(F3DFloor, F3DFloor, master); +DEFINE_FIELD_X(F3DFloor, F3DFloor, model); +DEFINE_FIELD_X(F3DFloor, F3DFloor, target); +DEFINE_FIELD_X(F3DFloor, F3DFloor, alpha); + DEFINE_FIELD_X(Vertex, vertex_t, p) DEFINE_FIELD(DBaseStatusBar, RelTop); diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index 0dc38f983..0f617050a 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -618,7 +618,7 @@ struct TraceResults native native bool unlinked; // passed through a portal without static offset. native ETraceResult HitType; - // F3DFloor *ffloor; + native F3DFloor ffloor; native Sector CrossedWater; // For Boom-style, Transfer_Heights-based deep water native vector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash @@ -835,10 +835,6 @@ struct State native native bool InStateSequence(State base); } -struct F3DFloor native -{ -} - struct Wads { enum WadNamespace diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index 4a1154feb..3fbb21df9 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -212,6 +212,55 @@ struct SecPlane native play native double PointToDist(Vector2 xy, double z) const; } +struct F3DFloor native play +{ + enum EF3DFloorFlags + { + FF_EXISTS = 0x1, //MAKE SURE IT'S VALID + FF_SOLID = 0x2, //Does it clip things? + FF_RENDERSIDES = 0x4, //Render the sides? + FF_RENDERPLANES = 0x8, //Render the floor/ceiling? + FF_RENDERALL = 0xC, //Render everything? + FF_SWIMMABLE = 0x10, //Can we swim? + FF_NOSHADE = 0x20, //Does it mess with the lighting? + FF_BOTHPLANES = 0x200, //Render both planes all the time? + FF_TRANSLUCENT = 0x800, //See through! + FF_FOG = 0x1000, //Fog "brush"? + FF_INVERTPLANES = 0x2000, //Reverse the plane visibility rules? + FF_ALLSIDES = 0x4000, //Render inside and outside sides? + FF_INVERTSIDES = 0x8000, //Only render inside sides? + FF_DOUBLESHADOW = 0x10000,//Make two lightlist entries to reset light? + FF_UPPERTEXTURE = 0x20000, + FF_LOWERTEXTURE = 0x40000, + FF_THINFLOOR = 0x80000, // EDGE + FF_SCROLLY = 0x100000, // EDGE - not yet implemented!!! + FF_FIX = 0x200000, // use floor of model sector as floor and floor of real sector as ceiling + FF_INVERTSECTOR = 0x400000, // swap meaning of sector planes + FF_DYNAMIC = 0x800000, // created by partitioning another 3D-floor due to overlap + FF_CLIPPED = 0x1000000, // split into several dynamic ffloors + FF_SEETHROUGH = 0x2000000, + FF_SHOOTTHROUGH = 0x4000000, + FF_FADEWALLS = 0x8000000, // Applies real fog to walls and doesn't blend the view + FF_ADDITIVETRANS = 0x10000000, // Render this floor with additive translucency + FF_FLOOD = 0x20000000, // extends towards the next lowest flooding or solid 3D floor or the bottom of the sector + FF_THISINSIDE = 0x40000000, // hack for software 3D with FF_BOTHPLANES + FF_RESET = 0x80000000, // light effect is completely reset, once interrupted + }; + + native readonly secplane bottom; + native readonly secplane top; + + native readonly uint flags; + native readonly Line master; + + native readonly Sector model; + native readonly Sector target; + + native readonly int alpha; + + native TextureID GetTexture(int pos); +} + // This encapsulates all info Doom's original 'special' field contained - for saving and transferring. struct SecSpecial play { @@ -367,6 +416,11 @@ struct Sector native play native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); + native F3DFloor Get3DFloor(int index); + native int Get3DFloorCount(); + native Sector GetAttached(int index); + native int GetAttachedCount(); + native void RemoveForceField(); deprecated("3.8") static clearscope Sector PointInSector(Vector2 pt) {