mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-27 06:12:19 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
205bbac411
7 changed files with 210 additions and 148 deletions
|
@ -1398,7 +1398,7 @@ intercept_t *FPathTraverse::Next()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
|
void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
|
||||||
{
|
{
|
||||||
fixed_t xt1, xt2;
|
fixed_t xt1, xt2;
|
||||||
fixed_t yt1, yt2;
|
fixed_t yt1, yt2;
|
||||||
|
|
|
@ -325,6 +325,7 @@ public:
|
||||||
|
|
||||||
class FPathTraverse
|
class FPathTraverse
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
static TArray<intercept_t> intercepts;
|
static TArray<intercept_t> intercepts;
|
||||||
|
|
||||||
divline_t trace;
|
divline_t trace;
|
||||||
|
@ -332,17 +333,39 @@ class FPathTraverse
|
||||||
unsigned int intercept_count;
|
unsigned int intercept_count;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
|
||||||
void AddLineIntercepts(int bx, int by);
|
virtual void AddLineIntercepts(int bx, int by);
|
||||||
void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
|
virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
|
||||||
|
FPathTraverse() {}
|
||||||
public:
|
public:
|
||||||
|
|
||||||
intercept_t *Next();
|
intercept_t *Next();
|
||||||
|
|
||||||
FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
|
FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
|
||||||
~FPathTraverse();
|
{
|
||||||
|
init(x1, y1, x2, y2, flags);
|
||||||
|
}
|
||||||
|
void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
|
||||||
|
virtual ~FPathTraverse();
|
||||||
const divline_t &Trace() const { return trace; }
|
const divline_t &Trace() const { return trace; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A traverser that uses the portal blockmap
|
||||||
|
// This should be in portal.h but that'd create circular dependencies.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
class FLinePortalTraverse : public FPathTraverse
|
||||||
|
{
|
||||||
|
void AddLineIntercepts(int bx, int by);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FLinePortalTraverse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
233
src/portal.cpp
233
src/portal.cpp
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
|
#include "p_blockmap.h"
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "r_bsp.h"
|
#include "r_bsp.h"
|
||||||
#include "r_segs.h"
|
#include "r_segs.h"
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||||
|
|
||||||
FDisplacementTable Displacements;
|
FDisplacementTable Displacements;
|
||||||
|
FPortalBlockmap PortalBlockmap;
|
||||||
|
|
||||||
TArray<FLinePortal> linePortals;
|
TArray<FLinePortal> linePortals;
|
||||||
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
|
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups.
|
||||||
|
@ -93,7 +95,85 @@ struct FPortalBits
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// BuildBlockmap
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
static void BuildBlockmap()
|
||||||
|
{
|
||||||
|
PortalBlockmap.Clear();
|
||||||
|
PortalBlockmap.Create(bmapwidth, bmapheight);
|
||||||
|
for (int y = 0; y < bmapheight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < bmapwidth; x++)
|
||||||
|
{
|
||||||
|
int offset = y*bmapwidth + x;
|
||||||
|
int *list = blockmaplump + *(blockmap + offset) + 1;
|
||||||
|
FPortalBlock &block = PortalBlockmap(x, y);
|
||||||
|
|
||||||
|
while (*list != -1)
|
||||||
|
{
|
||||||
|
line_t *ld = &lines[*list++];
|
||||||
|
|
||||||
|
if (ld->isLinePortal())
|
||||||
|
{
|
||||||
|
PortalBlockmap.containsLines = true;
|
||||||
|
block.portallines.Push(ld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!PortalBlockmap.containsLines) PortalBlockmap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// FLinePortalTraverse :: AddLineIntercepts.
|
||||||
|
//
|
||||||
|
// Similar to AddLineIntercepts but checks the portal blockmap for line-to-line portals
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FLinePortalTraverse::AddLineIntercepts(int bx, int by)
|
||||||
|
{
|
||||||
|
FPortalBlock &block = PortalBlockmap(bx, by);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i<block.portallines.Size(); i++)
|
||||||
|
{
|
||||||
|
line_t *ld = block.portallines[i];
|
||||||
|
fixed_t frac;
|
||||||
|
divline_t dl;
|
||||||
|
|
||||||
|
if (ld->validcount == validcount) continue; // already processed
|
||||||
|
|
||||||
|
if (P_PointOnDivlineSidePrecise (ld->v1->x, ld->v1->y, &trace) ==
|
||||||
|
P_PointOnDivlineSidePrecise (ld->v2->x, ld->v2->y, &trace))
|
||||||
|
{
|
||||||
|
continue; // line isn't crossed
|
||||||
|
}
|
||||||
|
P_MakeDivline (ld, &dl);
|
||||||
|
if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &dl) != 0 ||
|
||||||
|
P_PointOnDivlineSidePrecise (trace.x+trace.dx, trace.y+trace.dy, &dl) != 1)
|
||||||
|
{
|
||||||
|
continue; // line isn't crossed from the front side
|
||||||
|
}
|
||||||
|
|
||||||
|
// hit the line
|
||||||
|
P_MakeDivline(ld, &dl);
|
||||||
|
frac = P_InterceptVector(&trace, &dl);
|
||||||
|
if (frac < 0 || frac > FRACUNIT) continue; // behind source
|
||||||
|
|
||||||
|
intercept_t newintercept;
|
||||||
|
|
||||||
|
newintercept.frac = frac;
|
||||||
|
newintercept.isaline = true;
|
||||||
|
newintercept.done = false;
|
||||||
|
newintercept.d.line = ld;
|
||||||
|
intercepts.Push(newintercept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
|
@ -301,6 +381,7 @@ void P_FinalizePortals()
|
||||||
P_UpdatePortal(port);
|
P_UpdatePortal(port);
|
||||||
}
|
}
|
||||||
P_CollectLinkedPortals();
|
P_CollectLinkedPortals();
|
||||||
|
BuildBlockmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
@ -601,124 +682,72 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// portal tracer code
|
// P_GetOffsetPosition
|
||||||
|
//
|
||||||
|
// Offsets a given coordinate if the trace from the origin crosses an
|
||||||
|
// interactive line-to-line portal.
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
PortalTracer::PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
|
fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy)
|
||||||
{
|
{
|
||||||
this->startx = startx;
|
fixedvec3 dest = { actor->X() + dx, actor->Y() + dy };
|
||||||
this->starty = starty;
|
if (PortalBlockmap.containsLines && actor->Sector->PortalGroup != 0)
|
||||||
this->endx = endx;
|
|
||||||
this->endy = endy;
|
|
||||||
intx = endx;
|
|
||||||
inty = endy;
|
|
||||||
intxIn = intx;
|
|
||||||
intyIn = inty;
|
|
||||||
z = 0;
|
|
||||||
angle = 0;
|
|
||||||
depth = 0;
|
|
||||||
frac = 0;
|
|
||||||
in = NULL;
|
|
||||||
out = NULL;
|
|
||||||
vx = 0;
|
|
||||||
vy = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PortalTracer::TraceStep()
|
|
||||||
{
|
|
||||||
if (depth > sv_portal_recursions)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
this->in = NULL;
|
|
||||||
this->out = NULL;
|
|
||||||
this->vx = 0;
|
|
||||||
this->vy = 0;
|
|
||||||
|
|
||||||
int oDepth = depth;
|
|
||||||
|
|
||||||
fixed_t dirx = endx-startx;
|
|
||||||
fixed_t diry = endy-starty;
|
|
||||||
P_NormalizeVXVY(dirx, diry);
|
|
||||||
|
|
||||||
dirx = 0;
|
|
||||||
diry = 0;
|
|
||||||
|
|
||||||
FPathTraverse it(startx-dirx, starty-diry, endx+dirx, endy+diry, PT_ADDLINES | PT_COMPATIBLE);
|
|
||||||
|
|
||||||
intercept_t *in;
|
|
||||||
while ((in = it.Next()))
|
|
||||||
{
|
{
|
||||||
line_t* li;
|
fixed_t actx = actor->X(), acty = actor->Y();
|
||||||
|
FLinePortalTraverse it;
|
||||||
if (in->isaline)
|
bool repeat;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
li = in->d.line;
|
it.init(actx, acty, dx, dy, PT_ADDLINES);
|
||||||
|
intercept_t *in;
|
||||||
|
|
||||||
if (li->isLinePortal())
|
repeat = false;
|
||||||
|
while ((in = it.Next()))
|
||||||
{
|
{
|
||||||
if (P_PointOnLineSide(startx-dirx, starty-diry, li))
|
// hit a portal line.
|
||||||
continue; // we're at the back side of this line
|
line_t *line = in->d.line;
|
||||||
|
FLinePortal *port = line->getPortal();
|
||||||
|
line_t* out = port->mDestination;
|
||||||
|
|
||||||
line_t* out = li->getPortalDestination();
|
// Teleport portals are intentionally ignored since skipping this stuff is their entire reason for existence.
|
||||||
|
if (port->mFlags & PORTF_INTERACTIVE)
|
||||||
this->in = li;
|
|
||||||
this->out = out;
|
|
||||||
|
|
||||||
// we only know that we crossed it, but we also need to know WHERE we crossed it
|
|
||||||
fixed_t vx = it.Trace().dx;
|
|
||||||
fixed_t vy = it.Trace().dy;
|
|
||||||
|
|
||||||
fixed_t x = it.Trace().x + FixedMul(vx, in->frac);
|
|
||||||
fixed_t y = it.Trace().y + FixedMul(vy, in->frac);
|
|
||||||
|
|
||||||
P_NormalizeVXVY(vx, vy);
|
|
||||||
|
|
||||||
this->vx = vx;
|
|
||||||
this->vy = vy;
|
|
||||||
|
|
||||||
// teleport our trace
|
|
||||||
|
|
||||||
if (!out->backsector)
|
|
||||||
{
|
{
|
||||||
intx = x + vx;
|
fixed_t hitdx = FixedMul(it.Trace().dx, in->frac);
|
||||||
inty = y + vy;
|
fixed_t hitdy = FixedMul(it.Trace().dy, in->frac);
|
||||||
}
|
|
||||||
else
|
if (port->mType == PORTT_LINKED)
|
||||||
{
|
{
|
||||||
intx = x - vx;
|
// optimized handling for linked portals where we only need to add an offset.
|
||||||
inty = y - vy;
|
actx = it.Trace().x + hitdx + port->mXDisplacement;
|
||||||
|
acty = it.Trace().y + hitdy + port->mYDisplacement;
|
||||||
|
dest.x += port->mXDisplacement;
|
||||||
|
dest.y += port->mYDisplacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// interactive ones are more complex because the vector may be rotated.
|
||||||
|
// Note: There is no z-translation here, there's just too much code in the engine that wouldn't be able to handle interactive portals with a height difference.
|
||||||
|
actx = it.Trace().x + hitdx;
|
||||||
|
acty = it.Trace().y + hitdy;
|
||||||
|
|
||||||
|
P_TranslatePortalXY(line, out, actx, acty);
|
||||||
|
P_TranslatePortalXY(line, out, dest.x, dest.y);
|
||||||
|
}
|
||||||
|
// update the fields, end this trace and restart from the new position
|
||||||
|
dx = dest.x - actx;
|
||||||
|
dy = dest.y - acty;
|
||||||
|
repeat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//P_TranslateCoordinatesAndAngle(li, out, startx, starty, noangle);
|
break;
|
||||||
//P_TranslateCoordinatesAndAngle(li, out, endx, endy, angle);
|
|
||||||
//if (hdeltaZ)
|
|
||||||
// P_TranslateZ(li, out, deltaZ);
|
|
||||||
//P_TranslateCoordinatesAndAngle(li, out, vx, vy, noangle);
|
|
||||||
|
|
||||||
P_TranslatePortalXY(li, out, startx, starty);
|
|
||||||
P_TranslatePortalVXVY(li, out, this->vx, this->vy);
|
|
||||||
intxIn = intx;
|
|
||||||
intyIn = inty;
|
|
||||||
P_TranslatePortalXY(li, out, intx, inty);
|
|
||||||
P_TranslatePortalXY(li, out, endx, endy);
|
|
||||||
P_TranslatePortalAngle(li, out, angle);
|
|
||||||
P_TranslatePortalZ(li, out, z);
|
|
||||||
frac += in->frac;
|
|
||||||
depth++;
|
|
||||||
break; // breaks to outer loop
|
|
||||||
}
|
}
|
||||||
|
} while (repeat);
|
||||||
if (!(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING))
|
|
||||||
return false; // stop tracing, 2D blocking line
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return dest;
|
||||||
//Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2DBL(this->vx), FIXED2DBL(this->vy));
|
|
||||||
|
|
||||||
return (oDepth != depth); // if a portal has been found, return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// CollectSectors
|
// CollectSectors
|
||||||
|
|
81
src/portal.h
81
src/portal.h
|
@ -62,6 +62,49 @@ struct FDisplacementTable
|
||||||
|
|
||||||
extern FDisplacementTable Displacements;
|
extern FDisplacementTable Displacements;
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A blockmap that only contains crossable portals
|
||||||
|
// This is used for quick checks if a vector crosses through one.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
struct FPortalBlock
|
||||||
|
{
|
||||||
|
TArray<line_t*> portallines;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FPortalBlockmap
|
||||||
|
{
|
||||||
|
TArray<FPortalBlock> data;
|
||||||
|
int dx, dy;
|
||||||
|
bool containsLines;
|
||||||
|
|
||||||
|
void Create(int blockx, int blocky)
|
||||||
|
{
|
||||||
|
data.Resize(blockx*blocky);
|
||||||
|
dx = blockx;
|
||||||
|
dy = blocky;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
data.Clear();
|
||||||
|
data.ShrinkToFit();
|
||||||
|
dx = dy = 0;
|
||||||
|
containsLines = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPortalBlock &operator()(int x, int y)
|
||||||
|
{
|
||||||
|
return data[x + dx*y];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern FPortalBlockmap PortalBlockmap;
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// Flags and types for linedef portals
|
// Flags and types for linedef portals
|
||||||
|
@ -143,44 +186,6 @@ void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy);
|
||||||
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
|
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
|
||||||
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
|
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
|
||||||
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
|
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// basically, this is a teleporting tracer function,
|
|
||||||
// which can be used by itself (to calculate portal-aware offsets, say, for projectiles)
|
|
||||||
// or to teleport normal tracers (like hitscan, railgun, autoaim tracers)
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
class PortalTracer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
|
|
||||||
|
|
||||||
// trace to next portal
|
|
||||||
bool TraceStep();
|
|
||||||
// trace to last available portal on the path
|
|
||||||
void TraceAll() { while (TraceStep()) continue; }
|
|
||||||
|
|
||||||
int depth;
|
|
||||||
fixed_t startx;
|
|
||||||
fixed_t starty;
|
|
||||||
fixed_t intx;
|
|
||||||
fixed_t inty;
|
|
||||||
fixed_t intxIn;
|
|
||||||
fixed_t intyIn;
|
|
||||||
fixed_t endx;
|
|
||||||
fixed_t endy;
|
|
||||||
angle_t angle;
|
|
||||||
fixed_t z;
|
|
||||||
fixed_t frac;
|
|
||||||
line_t* in;
|
|
||||||
line_t* out;
|
|
||||||
fixed_t vx;
|
|
||||||
fixed_t vy;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* new code */
|
|
||||||
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1183,6 +1183,11 @@ struct line_t
|
||||||
unsigned portalindex;
|
unsigned portalindex;
|
||||||
TObjPtr<ASkyViewpoint> skybox;
|
TObjPtr<ASkyViewpoint> skybox;
|
||||||
|
|
||||||
|
FLinePortal *getPortal() const
|
||||||
|
{
|
||||||
|
return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex];
|
||||||
|
}
|
||||||
|
|
||||||
// returns true if the portal is crossable by actors
|
// returns true if the portal is crossable by actors
|
||||||
bool isLinePortal() const
|
bool isLinePortal() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -1749,7 +1749,7 @@ JOYMNU_CONFIG = "CONFIGURE CONTROLLER";
|
||||||
JOYMNU_OPTIONS = "CONTROLLER OPTIONS";
|
JOYMNU_OPTIONS = "CONTROLLER OPTIONS";
|
||||||
|
|
||||||
// Player Setup Menu
|
// Player Setup Menu
|
||||||
PLYRMNU_PLAYERSETUP = "PLAYER SETUP";
|
MNU_PLAYERSETUP = "PLAYER SETUP";
|
||||||
PLYRMNU_NAME = "Name";
|
PLYRMNU_NAME = "Name";
|
||||||
PLYRMNU_TEAM = "Team";
|
PLYRMNU_TEAM = "Team";
|
||||||
PLYRMNU_PLAYERCOLOR = "Color";
|
PLYRMNU_PLAYERCOLOR = "Color";
|
||||||
|
@ -2258,7 +2258,7 @@ OPTVAL_FOO_DUMB = "foo_dumb";
|
||||||
OPTVAL_ALIASING = "Aliasing";
|
OPTVAL_ALIASING = "Aliasing";
|
||||||
OPTVAL_LINEAR = "Linear";
|
OPTVAL_LINEAR = "Linear";
|
||||||
OPTVAL_CUBIC = "Cubic";
|
OPTVAL_CUBIC = "Cubic";
|
||||||
OPTVAL_BLEP = "Band-limited step"
|
OPTVAL_BLEP = "Band-limited step";
|
||||||
OPTVAL_LINEARSLOW = "Linear (Slower)";
|
OPTVAL_LINEARSLOW = "Linear (Slower)";
|
||||||
OPTVAL_BLAM = "Band-limited linear";
|
OPTVAL_BLAM = "Band-limited linear";
|
||||||
OPTVAL_CUBICSLOW = "Cubic (Slower)";
|
OPTVAL_CUBICSLOW = "Cubic (Slower)";
|
||||||
|
|
|
@ -366,7 +366,7 @@ OptionValue "Gender"
|
||||||
|
|
||||||
ListMenu "PlayerMenu"
|
ListMenu "PlayerMenu"
|
||||||
{
|
{
|
||||||
StaticTextCentered 160, 6, "$PLYRMNU_PLAYERSETUP"
|
StaticTextCentered 160, 6, "$MNU_PLAYERSETUP"
|
||||||
Font "SmallFont"
|
Font "SmallFont"
|
||||||
Linespacing 14
|
Linespacing 14
|
||||||
Position 48, 36
|
Position 48, 36
|
||||||
|
|
Loading…
Reference in a new issue