From 31ea33bfc452ebed5fd4f829a58a02a873106e77 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Mar 2017 00:25:26 +0100 Subject: [PATCH] - rewrote the condition nodes from SBARINFO in ZScript. This compiles but hasn't been tested yet. --- src/c_cvars.cpp | 3 +- src/g_level.cpp | 1 + src/g_statusbar/shared_sbar.cpp | 20 - src/namedef.h | 1 + src/scripting/backend/codegen.cpp | 3 +- src/scripting/vm/vmframe.cpp | 8 + src/v_video.cpp | 5 + wadsrc/static/zscript/base.txt | 5 +- .../zscript/statusbar/statusbarwidget.txt | 677 +++++++++++++++++- 9 files changed, 694 insertions(+), 29 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 5b33cc263..95da13374 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1541,7 +1541,8 @@ DEFINE_ACTION_FUNCTION(_CVar, FindCVar) { PARAM_PROLOGUE; 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) diff --git a/src/g_level.cpp b/src/g_level.cpp index a6a81840a..0347e79d3 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1960,6 +1960,7 @@ DEFINE_FIELD(FLevelLocals, teamdamage) DEFINE_FIELD(FLevelLocals, fogdensity) DEFINE_FIELD(FLevelLocals, outsidefogdensity) 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, actownspecial, LEVEL_ACTOWNSPECIAL) DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL) diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 8865192ab..e6ed9ac19 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1470,24 +1470,4 @@ DEFINE_ACTION_FUNCTION(DStatusbarWidget, BeginCondition) ACTION_RETURN_POINTER(head); } -DEFINE_ACTION_FUNCTION(DStatusbarWidget, EndCondition) -{ - PARAM_SELF_PROLOGUE(DObject); - auto owner = self->PointerVar(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(NAME_Owner); - if (owner == nullptr || owner->PointerVar(NAME_Owner) != owner || owner->GetClass()->TypeName != NAME_StatusbarWidget) - { - ThrowAbortException(X_OTHER, "No matching Begin found for Finish"); - } - ACTION_RETURN_POINTER(owner); -} diff --git a/src/namedef.h b/src/namedef.h index 4d9a06e36..ca99ff650 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -649,6 +649,7 @@ xx(DeathmatchStatusScreen) xx(CoopStatusScreen) xx(RavenStatusScreen) xx(StatusbarWidget) +xx(StatusbarHead) xx(StatusbarCondition) xx(Next) xx(Prev) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index af3ff1bbb..3e7aa1a21 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6872,7 +6872,8 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) { if (offsetreg == -1) offsetreg = build->GetConstantInt(0); 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); } else diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 3ec629e79..e2ec3865a 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -565,6 +565,14 @@ void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...) 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) { ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); diff --git a/src/v_video.cpp b/src/v_video.cpp index 4cc77cf0e..a6482a90c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1700,6 +1700,11 @@ float ActiveRatio(int width, int height, float *trueratio) 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 // screen's pixel dimensions. Can return: // 0: 4:3 diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index ce43e35b8..825e1ee41 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -165,6 +165,7 @@ struct Screen native 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 Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); + native static double GetAspectRatio(); } struct Font native @@ -275,7 +276,7 @@ struct CVar native CVAR_Color, }; - native static CVar FindCVar(Name name); + native static CVar FindCVar(Name name, PlayerInfo player = null); native int GetInt(); native double GetFloat(); native String GetString(); @@ -326,6 +327,7 @@ class Object native native static uint BAM(double angle); native static void SetMusicVolume(float vol); native static uint MSTime(); + native vararg static void ThrowAbortException(String fmt, ...); native Name GetClassName(); native virtualscope void Destroy(); @@ -486,6 +488,7 @@ struct LevelLocals native native play double airfriction; native play int airsupply; native readonly double teamdamage; + native readonly bool noinventorybar; native readonly bool monsterstelefrag; native readonly bool actownspecial; native readonly bool sndseqtotalctrl; diff --git a/wadsrc/static/zscript/statusbar/statusbarwidget.txt b/wadsrc/static/zscript/statusbar/statusbarwidget.txt index 01d8d5d86..b518caf49 100644 --- a/wadsrc/static/zscript/statusbar/statusbarwidget.txt +++ b/wadsrc/static/zscript/statusbar/statusbarwidget.txt @@ -1,31 +1,696 @@ +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + 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 Prev; StatusbarWidget Owner; native vararg StatusbarWidget AppendWidget(class cls, ...); native vararg StatusbarWidget BeginCondition(class 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 { - 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 Weap1, Weap2; + private bool Negate; + private bool CheckSister; + + void Init(class w1, class 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 PlayerClasses[6]; + private bool Negate; + + void Init(class p1, class p2, class p3, class p4, class p5, class 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 Weap1; + private int PieceNum; + private bool Negate; + + void Init(class 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 AmmoType1, AmmoType2; + private int ValidModes; + private bool Negate; + + void Init(class ammotype_1, class 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 InventoryType1, InventoryType2; + private int Amount1, Amount2; + private int ValidModes; + private bool Negate; + + void Init(class Inventorytype_1, int am1, class 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 { - private StatusbarWidget Head; + private StatusbarHead Head; StatusbarWidget Begin() { - Head = new("StatusbarWidget"); + Head = new("StatusbarHead"); 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; + } + + }