From a45591134c124c85db42fd65c9e2a815b43cb31a Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Tue, 21 Mar 2023 22:03:27 -0700 Subject: [PATCH] info_waypoint: Initial implementation. This has nothing to do with AI (don't get any ideas just yet), but rather HUD information displays. --- src/client/entities.qc | 3 + src/gs-entbase/shared/info_waypoint.qc | 219 ++++++++++++++++++++++++- src/shared/entities.h | 5 +- 3 files changed, 221 insertions(+), 6 deletions(-) diff --git a/src/client/entities.qc b/src/client/entities.qc index 420bc08c..a13e3737 100644 --- a/src/client/entities.qc +++ b/src/client/entities.qc @@ -133,6 +133,9 @@ Entity_EntityUpdate(float type, float new) case ENT_CONVEYOR: func_conveyor_ReadEntity(new); break; + case ENT_WAYPOINT: + info_waypoint_ReadEntity(new); + break; case ENT_PUSH: trigger_push_ReadEntity(new); break; diff --git a/src/gs-entbase/shared/info_waypoint.qc b/src/gs-entbase/shared/info_waypoint.qc index dd7bcd6d..ac21b8d4 100644 --- a/src/gs-entbase/shared/info_waypoint.qc +++ b/src/gs-entbase/shared/info_waypoint.qc @@ -14,6 +14,16 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define WAYPOINT_METER 52.49344f + +enumflags +{ + INFWAY_CHANGED_ORIGIN, + INFWAY_CHANGED_IMAGE, + INFWAY_CHANGED_TEXT, + INFWAY_CHANGED_STATE +}; + /*!QUAKED info_waypoint (0 1 0) (-8 -8 -8) (8 8 8) # OVERVIEW When active, will display an icon and text at its position that can be seen @@ -32,14 +42,31 @@ by players. This entity was introduced in Obsidian Conflict (2006). */ class -info_waypoint +info_waypoint:NSPointTrigger { public: void info_waypoint(void); +#ifdef SERVER + virtual void SpawnKey(string,string); + virtual void Save(float); + virtual void Restore(string,string); + virtual void Input(entity,string,string); + virtual void Trigger(entity, triggermode_t); + + virtual void EvaluateEntity(void); + virtual float SendEntity(entity,float); +#endif + +#ifdef CLIENT + virtual void ReceiveEntity(float, float); + virtual void postdraw(void); +#endif + private: - string m_strIcon; - string m_strText; + PREDICTED_STRING(m_strIcon) + PREDICTED_STRING(m_strText) + PREDICTED_BOOL(m_bEnabled) }; void @@ -47,4 +74,188 @@ info_waypoint::info_waypoint(void) { m_strIcon = m_strText = __NULL__; -} \ No newline at end of file + m_bEnabled = false; +} + +#ifdef SERVER +void +info_waypoint::SpawnKey(string strKey, string strValue) +{ + switch (strKey) { + case "image": + m_strIcon = strValue; + break; + case "text": + m_strText = strValue; + break; + default: + super::SpawnKey(strKey, strValue); + } +} + +void +info_waypoint::Save(float handle) +{ + super::Save(handle); + SaveString(handle, "m_strIcon", m_strIcon); + SaveString(handle, "m_strText", m_strText); + SaveBool(handle, "m_bEnabled", m_bEnabled); +} + +void +info_waypoint::Restore(string strKey, string strValue) +{ + switch (strKey) { + case "m_strIcon": + m_strIcon = ReadString(strValue); + break; + case "m_strText": + m_strText = ReadString(strValue); + break; + case "m_bEnabled": + m_bEnabled = ReadBool(strValue); + break; + default: + super::Restore(strKey, strValue); + } +} + +void +info_waypoint::Trigger(entity act, triggermode_t state) +{ + switch (state) { + case TRIG_OFF: + m_bEnabled = false; + break; + case TRIG_ON: + m_bEnabled = true; + break; + default: + m_bEnabled = m_bEnabled ? false : true; + } +} + +void +info_waypoint::Input(entity eAct, string strInput, string strData) +{ + switch (strInput) { + case "Enable": + Trigger(eAct, TRIG_ON); + break; + case "Disable": + Trigger(eAct, TRIG_OFF); + break; + case "Toggle": + Trigger(eAct, TRIG_TOGGLE); + break; + default: + super::Input(eAct, strInput, strData); + } +} + +void +info_waypoint::EvaluateEntity(void) +{ + EVALUATE_VECTOR(origin, 0, INFWAY_CHANGED_ORIGIN) + EVALUATE_VECTOR(origin, 1, INFWAY_CHANGED_ORIGIN) + EVALUATE_VECTOR(origin, 2, INFWAY_CHANGED_ORIGIN) + EVALUATE_FIELD(m_strIcon, INFWAY_CHANGED_IMAGE) + EVALUATE_FIELD(m_strText, INFWAY_CHANGED_TEXT) + EVALUATE_FIELD(m_bEnabled, INFWAY_CHANGED_STATE) +} + +float +info_waypoint::SendEntity(entity ePEnt, float flChanged) +{ + WriteByte(MSG_ENTITY, ENT_WAYPOINT); + WriteFloat(MSG_ENTITY, flChanged); + SENDENTITY_COORD(origin[0], INFWAY_CHANGED_ORIGIN) + SENDENTITY_COORD(origin[1], INFWAY_CHANGED_ORIGIN) + SENDENTITY_COORD(origin[2], INFWAY_CHANGED_ORIGIN) + SENDENTITY_STRING(m_strIcon, INFWAY_CHANGED_IMAGE) + SENDENTITY_STRING(m_strText, INFWAY_CHANGED_TEXT) + SENDENTITY_BYTE(m_bEnabled, INFWAY_CHANGED_STATE) + return true; +} +#endif + +#ifdef CLIENT +void +info_waypoint::ReceiveEntity(float flNew, float flChanged) +{ + READENTITY_COORD(origin[0], INFWAY_CHANGED_ORIGIN) + READENTITY_COORD(origin[1], INFWAY_CHANGED_ORIGIN) + READENTITY_COORD(origin[2], INFWAY_CHANGED_ORIGIN) + READENTITY_STRING(m_strIcon, INFWAY_CHANGED_IMAGE) + READENTITY_STRING(m_strText, INFWAY_CHANGED_TEXT) + READENTITY_BYTE(m_bEnabled, INFWAY_CHANGED_STATE) + setorigin(this, origin); +} + +void +info_waypoint::postdraw(void) +{ + static float + drawicon_visible(vector p1) { + vector delta; + float fov; + vector p2 = g_view.GetCameraOrigin(); + vector ang = g_view.GetCameraAngle(); + + makevectors(ang); + delta = normalize (p1 - p2); + fov = delta * v_forward; + + /* within field of view... */ + if (fov > (g_view.GetAFOV()/180)) { + traceline(p2, p1, MOVE_WORLDONLY, self); + if (trace_fraction == 1.0) { + return (1); + } else { + return (2); + } + } + return (0); + } + + float visible; + + if (!m_bEnabled) + return; + + visible = drawicon_visible(origin); + + if (drawicon_visible(origin) != 0) { + float textLength = Font_StringWidth(m_strText, true, FONT_CON); + vector vecProj = project(origin) - [32, 32]; + vector projectedPos = project(origin) - (textLength/2) + [0, 114]; + float a = (visible == 2) ? 0.25 : 1.0f; + float dist = vlen(origin - g_view.GetCameraOrigin()) / WAYPOINT_METER; + string distText = sprintf("Distance: %d m", dist); + + drawpic(vecProj, m_strIcon, [64, 64], [1,1,1], a); + + Font_DrawText_RGBA(projectedPos + [1,1], distText, [0,0,0], a, FONT_CON); + Font_DrawText_RGBA(projectedPos, distText, [1,1,1], a, FONT_CON); + + projectedPos[1] += Font_GetHeight(FONT_CON); + + Font_DrawText_RGBA(projectedPos + [1,1], m_strText, [0,0,0], a, FONT_CON); + Font_DrawText_RGBA(projectedPos, m_strText, [1,1,1], a, FONT_CON); + } +} + +void +info_waypoint_ReadEntity(bool new) +{ + float fl; + + info_waypoint rend = (info_waypoint)self; + if (new) { + spawnfunc_info_waypoint(); + } + + fl = readfloat(); + rend.ReceiveEntity(new, fl); +} +#endif \ No newline at end of file diff --git a/src/shared/entities.h b/src/shared/entities.h index f5cee000..3914b7f9 100644 --- a/src/shared/entities.h +++ b/src/shared/entities.h @@ -45,8 +45,9 @@ typedef enum ENT_VEH_4WHEEL, /**< of type prop_vehicle_driveable */ ENT_PROPROPE, /**< of type prop_rope */ ENT_BUBBLES, /**< of type env_bubbles */ - ENT_CONVEYOR, - ENT_PUSH, + ENT_CONVEYOR, /**< of type func_conveyor */ + ENT_WAYPOINT, /**< of type info_waypoint */ + ENT_PUSH, /**< of type trigger_push */ ENT_SEPARATOR, /**< This is a separator. This separator is used by you to add game-specific networked entities. When declaring your own entity-update types, you want the first value to equal ENT_SEPARATOR at all times to ensure you'll not be overriding existing slots. */ } entupdate_t;