- rewrote the condition nodes from SBARINFO in ZScript. This compiles but hasn't been tested yet.

This commit is contained in:
Christoph Oelckers 2017-03-23 00:25:26 +01:00
parent 3744c2eee7
commit 31ea33bfc4
9 changed files with 694 additions and 29 deletions

View file

@ -1541,7 +1541,8 @@ DEFINE_ACTION_FUNCTION(_CVar, FindCVar)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_NAME(name); PARAM_NAME(name);
ACTION_RETURN_POINTER(FindCVar(name, nullptr)); PARAM_POINTER_DEF(plyr, player_t);
ACTION_RETURN_POINTER(GetCVar(plyr ? plyr->mo : nullptr, name));
} }
FBaseCVar *FindCVarSub (const char *var_name, int namelen) FBaseCVar *FindCVarSub (const char *var_name, int namelen)

View file

@ -1960,6 +1960,7 @@ DEFINE_FIELD(FLevelLocals, teamdamage)
DEFINE_FIELD(FLevelLocals, fogdensity) DEFINE_FIELD(FLevelLocals, fogdensity)
DEFINE_FIELD(FLevelLocals, outsidefogdensity) DEFINE_FIELD(FLevelLocals, outsidefogdensity)
DEFINE_FIELD(FLevelLocals, skyfog) DEFINE_FIELD(FLevelLocals, skyfog)
DEFINE_FIELD_BIT(FLevelLocals, flags, noinventorybar, LEVEL_NOINVENTORYBAR)
DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG) DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG)
DEFINE_FIELD_BIT(FLevelLocals, flags, actownspecial, LEVEL_ACTOWNSPECIAL) DEFINE_FIELD_BIT(FLevelLocals, flags, actownspecial, LEVEL_ACTOWNSPECIAL)
DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL) DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL)

View file

@ -1470,24 +1470,4 @@ DEFINE_ACTION_FUNCTION(DStatusbarWidget, BeginCondition)
ACTION_RETURN_POINTER(head); ACTION_RETURN_POINTER(head);
} }
DEFINE_ACTION_FUNCTION(DStatusbarWidget, EndCondition)
{
PARAM_SELF_PROLOGUE(DObject);
auto owner = self->PointerVar<DObject>(NAME_Owner);
if (owner == nullptr || !owner->IsKindOf(NAME_StatusbarCondition))
{
ThrowAbortException(X_OTHER, "No matching BeginCondition found for EndCondition");
}
ACTION_RETURN_POINTER(owner);
}
DEFINE_ACTION_FUNCTION(DStatusbarWidget, Finish)
{
PARAM_SELF_PROLOGUE(DObject);
auto owner = self->PointerVar<DObject>(NAME_Owner);
if (owner == nullptr || owner->PointerVar<DObject>(NAME_Owner) != owner || owner->GetClass()->TypeName != NAME_StatusbarWidget)
{
ThrowAbortException(X_OTHER, "No matching Begin found for Finish");
}
ACTION_RETURN_POINTER(owner);
}

View file

@ -649,6 +649,7 @@ xx(DeathmatchStatusScreen)
xx(CoopStatusScreen) xx(CoopStatusScreen)
xx(RavenStatusScreen) xx(RavenStatusScreen)
xx(StatusbarWidget) xx(StatusbarWidget)
xx(StatusbarHead)
xx(StatusbarCondition) xx(StatusbarCondition)
xx(Next) xx(Next)
xx(Prev) xx(Prev)

View file

@ -6872,7 +6872,8 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build)
{ {
if (offsetreg == -1) offsetreg = build->GetConstantInt(0); if (offsetreg == -1) offsetreg = build->GetConstantInt(0);
auto op = membervar->Type->GetLoadOp(); auto op = membervar->Type->GetLoadOp();
if (op == OP_LO) op = OP_LOS; if (op == OP_LO)
op = OP_LOS;
build->Emit(op, loc.RegNum, build->FramePointer.RegNum, offsetreg); build->Emit(op, loc.RegNum, build->FramePointer.RegNum, offsetreg);
} }
else else

View file

@ -565,6 +565,14 @@ void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...)
va_end(ap); va_end(ap);
} }
DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException)
{
PARAM_PROLOGUE;
FString s = FStringFormat(param, defaultparam, numparam, ret, numret);
ThrowAbortException(X_OTHER, s.GetChars());
return 0;
}
void NullParam(const char *varname) void NullParam(const char *varname)
{ {
ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); ThrowAbortException(X_READ_NIL, "In function parameter %s", varname);

View file

@ -1700,6 +1700,11 @@ float ActiveRatio(int width, int height, float *trueratio)
return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio; return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio;
} }
DEFINE_ACTION_FUNCTION(_Screen, GetAspectRatio)
{
ACTION_RETURN_FLOAT(ActiveRatio(screen->GetWidth(), screen->GetHeight(), nullptr));
}
// Tries to guess the physical dimensions of the screen based on the // Tries to guess the physical dimensions of the screen based on the
// screen's pixel dimensions. Can return: // screen's pixel dimensions. Can return:
// 0: 4:3 // 0: 4:3

View file

@ -165,6 +165,7 @@ struct Screen native
native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
native static void DrawFrame(int x, int y, int w, int h); native static void DrawFrame(int x, int y, int w, int h);
native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true);
native static double GetAspectRatio();
} }
struct Font native struct Font native
@ -275,7 +276,7 @@ struct CVar native
CVAR_Color, CVAR_Color,
}; };
native static CVar FindCVar(Name name); native static CVar FindCVar(Name name, PlayerInfo player = null);
native int GetInt(); native int GetInt();
native double GetFloat(); native double GetFloat();
native String GetString(); native String GetString();
@ -326,6 +327,7 @@ class Object native
native static uint BAM(double angle); native static uint BAM(double angle);
native static void SetMusicVolume(float vol); native static void SetMusicVolume(float vol);
native static uint MSTime(); native static uint MSTime();
native vararg static void ThrowAbortException(String fmt, ...);
native Name GetClassName(); native Name GetClassName();
native virtualscope void Destroy(); native virtualscope void Destroy();
@ -486,6 +488,7 @@ struct LevelLocals native
native play double airfriction; native play double airfriction;
native play int airsupply; native play int airsupply;
native readonly double teamdamage; native readonly double teamdamage;
native readonly bool noinventorybar;
native readonly bool monsterstelefrag; native readonly bool monsterstelefrag;
native readonly bool actownspecial; native readonly bool actownspecial;
native readonly bool sndseqtotalctrl; native readonly bool sndseqtotalctrl;

View file

@ -1,31 +1,696 @@
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class StatusbarWidget ui class StatusbarWidget ui
{ {
enum EAlign
{
TOP = 0x1,
VMIDDLE = 0x2,
BOTTOM = 0x4,
LEFT = 0x10,
RIGHT = 0x20,
HMIDDLE = 0x40,
CENTER = VMIDDLE|HMIDDLE,
CENTER_BOTTOM = BOTTOM|HMIDDLE
};
StatusbarWidget Next; StatusbarWidget Next;
StatusbarWidget Prev; StatusbarWidget Prev;
StatusbarWidget Owner; StatusbarWidget Owner;
native vararg StatusbarWidget AppendWidget(class<StatusbarWidget> cls, ...); native vararg StatusbarWidget AppendWidget(class<StatusbarWidget> cls, ...);
native vararg StatusbarWidget BeginCondition(class<StatusbarCondition> cls, ...); native vararg StatusbarWidget BeginCondition(class<StatusbarCondition> cls, ...);
native StatusbarWidget EndCondition();
native void Finish(); void Init()
{
} }
StatusbarCondition EndCondition()
{
if (owner == null || !(owner is "StatusbarCondition"))
{
ThrowAbortException("No matching BeginCondition found for EndCondition");
}
return StatusbarCondition(owner);
}
StatusbarWidget ElseCondition()
{
let condi = StatusbarCondition(owner);
if (condi == null)
{
ThrowAbortException("No matching BeginCondition found for EndCondition");
}
if (condi.FalseChildren != null)
{
ThrowAbortException("Duplicate ElseCondition()");
}
condi.FalseChildren = new("StatusbarWidget");
condi.FalseChildren.Owner = condi;
return condi.FalseChildren;
}
StatusbarHead Finish()
{
if (owner == null || !(Owner is "StatusbarHead"))
{
ThrowAbortException("No matching Begin found for Finish");
}
return StatusbarHead(owner);
}
virtual void Draw(WidgetStatusBar stbar) {}
virtual void Reset() {}
virtual void Tick(WidgetStatusBar stbar, bool change) {}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class StatusbarHead : StatusbarWidget
{
StatusbarWidget Children;
override void Draw(WidgetStatusBar stbar)
{
for(let p = Children; p != null; p = p.Next)
{
p.Draw(stbar);
}
}
override void Reset()
{
for(let p = Children; p != null; p = p.Next)
{
p.Reset();
}
}
override void Tick(WidgetStatusBar stbar, bool change)
{
for(let p = Children; p != null; p = p.Next)
{
p.Tick(stbar, change);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class StatusbarCondition : StatusbarWidget class StatusbarCondition : StatusbarWidget
{ {
StatusbarWidget Children; StatusbarWidget TrueChildren;
StatusbarWidget FalseChildren;
bool LastCondition;
virtual int Condition(WidgetStatusBar stbar) { return -1; }
void Init()
{
LastCondition = true;
} }
override void Draw(WidgetStatusBar stbar)
{
for(let p = LastCondition? TrueChildren : FalseChildren; p != null; p = p.Next)
{
p.Draw(stbar);
}
}
override void Reset()
{
for(let p = TrueChildren; p != null; p = p.Next)
{
p.Reset();
}
for(let p = FalseChildren; p != null; p = p.Next)
{
p.Reset();
}
}
override void Tick(WidgetStatusBar stbar, bool change)
{
for(let p = LastCondition? TrueChildren : FalseChildren; p != null; p = p.Next)
{
p.Tick(stbar, change);
}
int i = Condition(stbar);
if (i >= 0 && LastCondition != !!i)
{
LastCondition = !!i;
for(let p = LastCondition? TrueChildren : FalseChildren; p != null; p = p.Next)
{
p.Tick(stbar, true);
}
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionGamemode : StatusbarCondition
{
enum GameModes
{
SINGLEPLAYER = 0x1,
COOPERATIVE = 0x2,
DEATHMATCH = 0x4,
TEAMGAME = 0x8
};
private int ValidModes;
void Init(int modemask)
{
ValidModes = modemask;
}
override int Condition(WidgetStatusBar stbar)
{
return (!multiplayer && (ValidModes & SINGLEPLAYER)) ||
(deathmatch && (ValidModes & DEATHMATCH)) ||
(multiplayer && !deathmatch && (ValidModes & COOPERATIVE)) ||
(teamplay && (ValidModes & TEAMGAME));
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionUsesAmmo : StatusbarCondition
{
enum AmmoModes
{
AMMO1,
AMMO2,
AMMO_ANY,
AMMO_BOTH
};
private int ValidModes;
private bool Negate;
void Init(int modemask, bool neg = false)
{
ValidModes = modemask;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
let w = stbar.CPlayer.ReadyWeapon;
if (w == null) return false;
bool usesammo1 = w.AmmoType1 != NULL;
bool usesammo2 = w.AmmoType2 != NULL;
if (ValidModes == AMMO1) return usesammo1 ^ Negate;
else if (ValidModes == AMMO2) return usesammo2 ^ Negate;
if (ValidModes == AMMO_ANY) return (usesammo1 || usesammo2) ^ Negate;
if (ValidModes == AMMO_BOTH) return (usesammo1 && usesammo2) ^ Negate;
return -1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionInventoryBarVisible : StatusbarCondition
{
private bool Negate;
void Init(bool neg = false)
{
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
return (stbar.CPlayer.inventorytics <= 0 || level.NoInventoryBar) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionAspectRatio : StatusbarCondition
{
private double MinValid, MaxValid;
private bool Negate;
void Init(double min, double max, bool neg = false)
{
MinValid = min;
MaxValid = max;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
double aspect = screen.GetAspectRatio();
return (aspect >= MinValid && aspect < MaxValid) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
// uses two names, like SBARINFO
//
//---------------------------------------------------------------------------
class SBConditionWeaponSelected : StatusbarCondition
{
private class<Weapon> Weap1, Weap2;
private bool Negate;
private bool CheckSister;
void Init(class<Weapon> w1, class<Weapon> w2, bool sister = false, bool neg = false)
{
Weap1 = w1;
Weap2 = w2;
CheckSister = sister;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
let w = stbar.CPlayer.ReadyWeapon;
return (w != null && ((w.GetClass() == Weap1 || w.GetClass() == Weap2) || (CheckSister && w.SisterWeapon != null && (w.SisterWeapon.GetClass() == Weap1 || w.SisterWeapon.GetClass() == Weap2)))) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionPlayerclass : StatusbarCondition
{
private Name PlayerClasses[6];
private bool Negate;
void Init(Name p1, Name p2 = 'none', Name p3 = 'none', Name p4 = 'none', Name p5 = 'none', Name p6 = 'none', bool neg = false)
{
PlayerClasses[0] = p1;
PlayerClasses[1] = p2;
PlayerClasses[2] = p3;
PlayerClasses[3] = p4;
PlayerClasses[4] = p5;
PlayerClasses[5] = p6;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
Name dn = PlayerPawn.GetPrintableDisplayName(stbar.CPlayer.mo.GetClass());
for(int i=0; i<6; i++)
{
if (PlayerClasses[i] != 'none' && dn == PlayerPawn.GetPrintableDisplayName(PlayerClasses[i])) return !Negate;
}
return Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionPlayerType : StatusbarCondition
{
private class<PlayerPawn> PlayerClasses[6];
private bool Negate;
void Init(class<PlayerPawn> p1, class<PlayerPawn> p2, class<PlayerPawn> p3, class<PlayerPawn> p4, class<PlayerPawn> p5, class<PlayerPawn> p6, bool neg = false)
{
PlayerClasses[0] = p1;
PlayerClasses[1] = p2;
PlayerClasses[2] = p3;
PlayerClasses[3] = p4;
PlayerClasses[4] = p5;
PlayerClasses[5] = p6;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
for(int i=0; i<6; i++)
{
if (PlayerClasses[i] != null && stbar.CPlayer.mo is PlayerClasses[i]) return !Negate;
}
return Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionHasWeaponPiece : StatusbarCondition
{
private class<Weapon> Weap1;
private int PieceNum;
private bool Negate;
void Init(class<Weapon> w1, int piecenum, bool neg = false)
{
Weap1 = w1;
PieceNum = piecenum - 1;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
for(let inv = stbar.CPlayer.mo.Inv; inv != NULL; inv = inv.Inv)
{
let wh = WeaponHolder(inv);
if (wh.PieceWeapon == Weap1)
{
return (!!(wh.PieceMask & (1 << PieceNum))) ^ Negate;
}
}
return Negate;
}
}
//---------------------------------------------------------------------------
//
// Checks if the current weapon uses the given ammo types.
//
//---------------------------------------------------------------------------
class SBConditionWeaponUsesAmmo : StatusbarCondition
{
enum AmmoModes
{
AMMO1,
AMMO2,
AMMO_ANY,
AMMO_BOTH
};
private class<Ammo> AmmoType1, AmmoType2;
private int ValidModes;
private bool Negate;
void Init(class<Ammo> ammotype_1, class<Ammo> ammotype_2, int modemask, bool neg = false)
{
AmmoType1 = ammotype_1;
AmmoType2 = ammotype_2;
ValidModes = modemask;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
let w = stbar.CPlayer.ReadyWeapon;
if (w == NULL) return false;
let WeapType1 = w.AmmoType1;
let WeapType2 = w.AmmoType2;
bool usesammo1 = WeapType1 != NULL;
bool usesammo2 = WeapType2 != NULL;
if(AmmoType2 != NULL)
{
bool match1 = ((usesammo1 && (AmmoType1 == WeapType1 || AmmoType2 == WeapType1)) || !usesammo1);
bool match2 = ((usesammo1 && (AmmoType1 == WeapType2 || AmmoType2 == WeapType2)) || !usesammo2);
if (ValidModes == AMMO1) return match1 ^ Negate;
if (ValidModes == AMMO2) return match2 ^ Negate;
if (ValidModes == AMMO_ANY) return (match1 || match2) ^ Negate;
if (ValidModes == AMMO_BOTH) return (match1 && match2) ^ Negate;
return -1;
}
else
{
if((usesammo1 && (WeapType1 == AmmoType1)) || (usesammo2 && (WeapType2 == AmmoType1)))
{
return !Negate;
}
}
return Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionHealth : StatusbarCondition
{
private int amount;
private bool Negate;
private bool percentage;
void Init(int amt, bool percent, bool neg = false)
{
amount = amt;
percentage = percent;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
int phealth = percentage ? stbar.CPlayer.mo.health * 100 / stbar.CPlayer.mo.GetMaxHealth() : stbar.CPlayer.mo.health;
return (phealth >= Amount) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionInvulnerable : StatusbarCondition
{
private bool Negate;
void Init(bool neg = false)
{
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
return ((stbar.CPlayer.mo.bInvulnerable) || (stbar.CPlayer.cheats & (CF_GODMODE | CF_GODMODE2))) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionWaterLevel : StatusbarCondition
{
private int amount;
private bool Negate;
void Init(int amt, bool neg = false)
{
amount = amt;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
return (stbar.CPlayer.mo.waterlevel >= amount) ^ Negate;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionCVarNumeric : StatusbarCondition
{
enum EOp
{
LESS,
LESSEQ,
EQ,
NEQ,
GREATEREQ,
GREATER
};
private String cv;
private int Operator;
private double Value;
void Init(String cvname, int op, double val)
{
cv = cvname;
Operator = op;
Value = val;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
let cvr = CVar.FindCVar(cv, stbar.CPlayer);
if (cvr == null) return -1;
double val = cvr.GetFloat();
switch (Operator)
{
case LESS:
return val < Value;
case LESSEQ:
return val <= Value;
case EQ:
return val ~== Value;
case NEQ:
return !(val ~== Value);
case GREATEREQ:
return val >= Value;
case GREATER:
return val > Value;
}
return -1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class SBConditionInInventory : StatusbarCondition
{
enum AmmoModes
{
ITEM1,
ITEM2,
ITEM_ANY,
ITEM_BOTH
};
private class<Inventory> InventoryType1, InventoryType2;
private int Amount1, Amount2;
private int ValidModes;
private bool Negate;
void Init(class<Inventory> Inventorytype_1, int am1, class<Inventory> Inventorytype_2, int am2, int modemask, bool neg = false)
{
InventoryType1 = Inventorytype_1;
InventoryType2 = Inventorytype_2;
Amount1 = am1;
Amount2 = am2;
ValidModes = modemask;
Negate = neg;
}
override int Condition(WidgetStatusBar stbar)
{
if (stbar.CPlayer == null) return -1;
let it1 = stbar.CPlayer.mo.FindInventory(InventoryType1);
let it2 = stbar.CPlayer.mo.FindInventory(InventoryType2);
if (it1 != NULL && amount1 > 0 && it1.Amount < amount1) it1 = NULL;
if (it2 != NULL && amount2 > 0 && it2.Amount < amount2) it2 = NULL;
if (ValidModes == ITEM1) return (!!it1) ^ Negate;
if (ValidModes == ITEM2) return (!!it2) ^ Negate;
if (ValidModes == ITEM_ANY) return (it1 || it2) ^ Negate;
if (ValidModes == ITEM_BOTH) return (it1 && it2) ^ Negate;
return -1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
class WidgetStatusBar : BaseStatusBar class WidgetStatusBar : BaseStatusBar
{ {
private StatusbarWidget Head; private StatusbarHead Head;
StatusbarWidget Begin() StatusbarWidget Begin()
{ {
Head = new("StatusbarWidget"); Head = new("StatusbarHead");
Head.Owner = Head; Head.Owner = Head;
return Head; Head.Children = new ("StatusbarWidget");
Head.Children.Owner = Head;
return Head.Children;
} }
// this is just copied from SBARINFO. We may need it.
static Vector2 adjustRelCenter(bool relX, bool relY, Vector2 pos, Vector3 scale)
{
Vector2 outvec;
if(relX)
outvec.X = pos.X + (screen.GetWidth()/(hud_scale ? Scale.X*2 : 2));
else
outvec.X = pos.X;
if(relY)
outvec.Y = pos.y + (screen.GetHeight()/(hud_scale ? Scale.Y*2 : 2));
else
outvec.Y = pos.y;
return outvec;
}
} }