diff --git a/QC/builtins.qc b/QC/builtins.qc index 6fa3bec..f6685c2 100644 --- a/QC/builtins.qc +++ b/QC/builtins.qc @@ -170,3 +170,4 @@ float(float v) sqrt = #108; float(float x, float y) atan2 = #109; +void(float h, float v) worldtext_hsetscale = #110; diff --git a/QC/buttons.qc b/QC/buttons.qc index 4cf2e59..76f11d8 100644 --- a/QC/buttons.qc +++ b/QC/buttons.qc @@ -79,6 +79,10 @@ void() button_fire = { bprint("Congratulations! You have hands.\n"); } + else if(self.buttonEffect == 3) // Command button + { + localcmd(self.targetname); + } }; void() button_use = @@ -209,6 +213,12 @@ void() func_button = worldtext_hsettext(wth, self.worldtext); worldtext_hsetpos(wth, realorigin(self) + '0 0 12' - dir * 6.0); worldtext_hsetangles(wth, ang); + worldtext_hsethalign(wth, self.worldtext_halign); + + if(self.worldtext_scale != 0) + { + worldtext_hsetscale(wth, self.worldtext_scale); + } } }; @@ -338,6 +348,11 @@ void() func_worldtext_banner = worldtext_hsetangles(wth, self.angles + '0 180 0'); worldtext_hsethalign(wth, self.worldtext_halign); + if(self.worldtext_scale != 0) + { + worldtext_hsetscale(wth, self.worldtext_scale); + } + if(self.lip > 1) { self.think = func_worldtext_banner_think; diff --git a/QC/vr_fields.qc b/QC/vr_fields.qc index cd19bea..8c2318b 100644 --- a/QC/vr_fields.qc +++ b/QC/vr_fields.qc @@ -125,6 +125,7 @@ .string worldtext; .float worldtext_halign; +.float worldtext_scale; .float angle; // diff --git a/Quake/cl_parse.cpp b/Quake/cl_parse.cpp index 89e2bc2..c7e378e 100644 --- a/Quake/cl_parse.cpp +++ b/Quake/cl_parse.cpp @@ -84,7 +84,7 @@ const char* svc_strings[128] = { "svc_sellscreen", "svc_cutscene", // johnfitz -- new server messages "35 svc_worldtext_hsethalign", // 35 - "36", // 36 + "36 svc_worldtext_hsetscale", // 36 "svc_skybox_fitz", // 37 // [string] skyname "38", // 38 "39", // 39 @@ -191,6 +191,11 @@ extern qvec3 v_punchangles[2]; // johnfitz //============================================================================= +template +static void readAndDrop(const T&) +{ +} + /* =============== CL_EntityNum @@ -344,19 +349,19 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, if(predbits & UFP_FORWARD) { /*news->movement[0] =*/ - MSG_ReadShort(); + readAndDrop(MSG_ReadShort()); } // else // news->movement[0] = 0; if(predbits & UFP_SIDE) { /*news->movement[1] =*/ - MSG_ReadShort(); + readAndDrop(MSG_ReadShort()); } // else // news->movement[1] = 0; if(predbits & UFP_UP) { /*news->movement[2] =*/ - MSG_ReadShort(); + readAndDrop(MSG_ReadShort()); } // else // news->movement[2] = 0; @@ -397,12 +402,12 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, { if(bits & UF_ANGLESXZ) { - /*news->vangle[0] =*/MSG_ReadShort(); - /*news->vangle[2] =*/MSG_ReadShort(); + /*news->vangle[0] =*/readAndDrop(MSG_ReadShort()); + /*news->vangle[2] =*/readAndDrop(MSG_ReadShort()); } if(bits & UF_ANGLESY) { /*news->vangle[1] =*/ - MSG_ReadShort(); + readAndDrop(MSG_ReadShort()); } } } @@ -486,11 +491,11 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, else if(enc == 16) { /*solidsize = */ - MSG_ReadShort(); // MSG_ReadSize16(&net_message); + readAndDrop(MSG_ReadShort()); // MSG_ReadSize16(&net_message); } else if(enc == 32) { - /*solidsize = */ MSG_ReadLong(); + /*solidsize = */ readAndDrop(MSG_ReadShort()); } else { @@ -499,7 +504,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, } else { - /*solidsize =*/MSG_ReadShort(); // MSG_ReadSize16(&net_message); + /*solidsize =*/readAndDrop(MSG_ReadShort()); // MSG_ReadSize16(&net_message); } // news->solidsize = solidsize; } @@ -529,7 +534,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, // &news->boneoffset); for(i = 0; i < bonecount * 7; i++) { /*bonedata[i] =*/ - MSG_ReadShort(); + readAndDrop(MSG_ReadShort()); } // news->bonecount = bonecount; } @@ -538,7 +543,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, if(fl & 0x40) { /*news->basebone =*/MSG_ReadByte(); - /*news->baseframe =*/MSG_ReadShort(); + /*news->baseframe =*/readAndDrop(MSG_ReadShort()); } /*else { @@ -577,10 +582,10 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, } if(bits & UF_LIGHT) { - /*news->light[0] =*/MSG_ReadShort(); - /*news->light[1] =*/MSG_ReadShort(); - /*news->light[2] =*/MSG_ReadShort(); - /*news->light[3] =*/MSG_ReadShort(); + /*news->light[0] =*/readAndDrop(MSG_ReadShort()); + /*news->light[1] =*/readAndDrop(MSG_ReadShort()); + /*news->light[2] =*/readAndDrop(MSG_ReadShort()); + /*news->light[3] =*/readAndDrop(MSG_ReadShort()); /*news->lightstyle =*/MSG_ReadByte(); /*news->lightpflags =*/MSG_ReadByte(); } @@ -625,7 +630,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t* news, { if(bits & UF_16BIT) { - /*news->modelindex2 =*/MSG_ReadShort(); + /*news->modelindex2 =*/readAndDrop(MSG_ReadShort()); } else { @@ -3362,6 +3367,12 @@ void CL_ParseServerMessage() break; } + case svc_worldtext_hsetscale: + { + cl.OnMsg_WorldTextHSetScale(); + break; + } + // voicechat, because we can. why reduce packet sizes if you're not // going to use that extra space?!? case svcfte_voicechat: diff --git a/Quake/client.cpp b/Quake/client.cpp index e8b0aa4..39ed58f 100644 --- a/Quake/client.cpp +++ b/Quake/client.cpp @@ -68,3 +68,16 @@ void client_state_t::OnMsg_WorldTextHSetHAlign() noexcept cl.worldTexts[wth]._hAlign = v; } } + +void client_state_t::OnMsg_WorldTextHSetScale() noexcept +{ + const WorldTextHandle wth = MSG_ReadShort(); + assert(isValidWorldTextHandle(wth)); + + const auto f = MSG_ReadFloat(); + + if(isValidWorldTextHandle(wth)) + { + cl.worldTexts[wth]._scale = f; + } +} diff --git a/Quake/client.hpp b/Quake/client.hpp index 8878cc9..e7160cd 100644 --- a/Quake/client.hpp +++ b/Quake/client.hpp @@ -371,6 +371,7 @@ struct client_state_t void OnMsg_WorldTextHSetPos() noexcept; void OnMsg_WorldTextHSetAngles() noexcept; void OnMsg_WorldTextHSetHAlign() noexcept; + void OnMsg_WorldTextHSetScale() noexcept; }; template diff --git a/Quake/common.cpp b/Quake/common.cpp index 4d84ba6..32daec2 100644 --- a/Quake/common.cpp +++ b/Quake/common.cpp @@ -2417,7 +2417,7 @@ static void COM_Game_f() if(vr_enabled.value) { - Cbuf_AddText("map start\n"); + Cbuf_AddText("map vrstart\n"); VR_ModAllModels(); } } diff --git a/Quake/gl_rmain.cpp b/Quake/gl_rmain.cpp index 8eb7f7d..5c2bfd4 100644 --- a/Quake/gl_rmain.cpp +++ b/Quake/gl_rmain.cpp @@ -877,7 +877,7 @@ void R_DrawWorldText() const auto drawString = [&](const qvec3& originalpos, const qvec3& angles, const std::string_view str, - const WorldText::HAlign hAlign) + const WorldText::HAlign hAlign, const float scale) { static std::vector lines; @@ -899,8 +899,9 @@ void R_DrawWorldText() // Angles and offsets const auto [fwd, right, up] = quake::util::getAngledVectors(angles); - const auto hInc = right * 8.f; - const auto zInc = qvec3{0, 0, -8.f} * up; + const auto charSize = 8.f * scale; + const auto hInc = right * charSize; + const auto zInc = qvec3{0, 0, -charSize} * up; // Bounds const auto absmins = originalpos; @@ -966,7 +967,7 @@ void R_DrawWorldText() for(const WorldText& wt : cl.worldTexts) { - drawString(wt._pos, wt._angles, wt._text, wt._hAlign); + drawString(wt._pos, wt._angles, wt._text, wt._hAlign, wt._scale); } glEnd(); diff --git a/Quake/gl_screen.cpp b/Quake/gl_screen.cpp index 85e868c..e38dac9 100644 --- a/Quake/gl_screen.cpp +++ b/Quake/gl_screen.cpp @@ -1472,10 +1472,12 @@ void SCR_UpdateScreen() // be split accordingly and cleaned up. qcvm_t* oldvm = qcvm; + PR_SwitchQCVM(nullptr); PR_SwitchQCVM(&sv.qcvm); VR_UpdateScreenContent(); // phoboslab + PR_SwitchQCVM(nullptr); PR_SwitchQCVM(oldvm); } else diff --git a/Quake/host.cpp b/Quake/host.cpp index 20d090a..30c000d 100644 --- a/Quake/host.cpp +++ b/Quake/host.cpp @@ -713,6 +713,7 @@ void Host_ShutdownServer(bool crash) } // QSS + PR_SwitchQCVM(nullptr); PR_SwitchQCVM(&sv.qcvm); { diff --git a/Quake/host_cmd.cpp b/Quake/host_cmd.cpp index 4e2ac21..1051e84 100644 --- a/Quake/host_cmd.cpp +++ b/Quake/host_cmd.cpp @@ -1595,6 +1595,7 @@ bool Host_Loadgame(const char* filename, const bool hasTimestamp) CL_Disconnect_f(); + PR_SwitchQCVM(nullptr); PR_SwitchQCVM(&sv.qcvm); SV_SpawnServer(mapname, SpawnServerSrc::FromSaveFile); @@ -2420,6 +2421,7 @@ void Host_Spawn_f() sv.SendMsg_WorldTextHSetPos(*host_client, wth, wt._pos); sv.SendMsg_WorldTextHSetAngles(*host_client, wth, wt._angles); sv.SendMsg_WorldTextHSetHAlign(*host_client, wth, wt._hAlign); + sv.SendMsg_WorldTextHSetScale(*host_client, wth, wt._scale); ++wth; } @@ -3107,7 +3109,7 @@ void Host_Startdemos_f() Cbuf_AddText("maxplayers 1\n"); Cbuf_AddText("deathmatch 0\n"); Cbuf_AddText("coop 0\n"); - Cbuf_AddText("map start\n"); + Cbuf_AddText("map vrstart\n"); Cbuf_AddText("centerview\n"); } diff --git a/Quake/menu.cpp b/Quake/menu.cpp index 73a856b..2437cdf 100644 --- a/Quake/menu.cpp +++ b/Quake/menu.cpp @@ -446,6 +446,7 @@ void M_Main_Key(int key) { quake::menu m{"Single Player", &M_Menu_Main_f}; + m.add_action_entry("VR Hub", [] { M_Menu_NewGame_f("vrstart"); }); m.add_action_entry("Tutorial", [] { M_Menu_NewGame_f("vrtutorial"); }); m.add_action_entry("Sandbox", [] { M_Menu_NewGame_f("vrfiringrange"); }); diff --git a/Quake/pr_cmds.cpp b/Quake/pr_cmds.cpp index 427e226..bb441c9 100644 --- a/Quake/pr_cmds.cpp +++ b/Quake/pr_cmds.cpp @@ -1272,6 +1272,23 @@ static void PF_worldtext_hsethalign() { sv.SendMsg_WorldTextHSetHAlign(client, wth, hAlign); }); } +static void PF_worldtext_hsetscale() +{ + const WorldTextHandle wth = G_INT(OFS_PARM0); + const float scale = G_FLOAT(OFS_PARM1); + + if(!sv.isValidWorldTextHandle(wth)) + { + Host_Error("Invalid world text handle '%d'", wth); + return; + } + + sv.getWorldText(wth)._scale = scale; + + forAllActiveOrSpawnedClients([&](client_t& client) + { sv.SendMsg_WorldTextHSetScale(client, wth, scale); }); +} + static void PF_strlen() { G_FLOAT(OFS_RETURN) = std::strlen(G_STRING(OFS_PARM0)); @@ -2412,6 +2429,8 @@ builtin_t pr_ssqcbuiltins[] = { PF_sqrt, // #108 PF_atan2, // #109 + + PF_worldtext_hsetscale, // #110 }; int pr_ssqcnumbuiltins = sizeof(pr_ssqcbuiltins) / sizeof(pr_ssqcbuiltins[0]); diff --git a/Quake/protocol.hpp b/Quake/protocol.hpp index 1bbcce2..b49e7e9 100644 --- a/Quake/protocol.hpp +++ b/Quake/protocol.hpp @@ -399,6 +399,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_worldtext_hsetpos 48 #define svc_worldtext_hsetangles 49 #define svc_worldtext_hsethalign 35 +#define svc_worldtext_hsetscale 36 // johnfitz // spike -- some extensions for particles. diff --git a/Quake/server.cpp b/Quake/server.cpp index dfc910b..cf8d735 100644 --- a/Quake/server.cpp +++ b/Quake/server.cpp @@ -80,3 +80,11 @@ void server_t::SendMsg_WorldTextHSetHAlign(client_t& client, MSG_WriteShort(&client.message, wth); MSG_WriteByte(&client.message, static_cast(hAlign)); } + +void server_t::SendMsg_WorldTextHSetScale(client_t& client, + const WorldTextHandle wth, const float scale) noexcept +{ + MSG_WriteByte(&client.message, svc_worldtext_hsetscale); + MSG_WriteShort(&client.message, wth); + MSG_WriteFloat(&client.message, scale); +} diff --git a/Quake/server.hpp b/Quake/server.hpp index 3541a25..4171ff3 100644 --- a/Quake/server.hpp +++ b/Quake/server.hpp @@ -150,6 +150,9 @@ struct server_t void SendMsg_WorldTextHSetHAlign(client_t& client, const WorldTextHandle wth, const WorldText::HAlign hAlign) noexcept; + + void SendMsg_WorldTextHSetScale(client_t& client, + const WorldTextHandle wth, float scale) noexcept; }; #define NUM_PING_TIMES 16 diff --git a/Quake/view.cpp b/Quake/view.cpp index da06baa..8671563 100644 --- a/Quake/view.cpp +++ b/Quake/view.cpp @@ -93,6 +93,12 @@ qvec3 v_punchangles[2]; // johnfitz -- copied from cl.punchangle. 0 is +template +[[nodiscard]] static constexpr T cvarCast(const float x) +{ + return static_cast(static_cast>(x)); +} + /* =============== V_CalcRoll @@ -701,7 +707,8 @@ void CalcGunAngle(const int wpnCvarEntry, entity_t* viewent, const qvec3& handrot, const qvec3& visual_handrot, bool horizFlip) { // Skip everything if we're doing VR Controller aiming. - if(vr_enabled.value && vr_aimmode.value == VrAimMode::e_CONTROLLER) + if(vr_enabled.value && + cvarCast(vr_aimmode.value) == VrAimMode::e_CONTROLLER) { auto [oPitch, oYaw, oRoll] = VR_GetWpnAngleOffsets(wpnCvarEntry); auto [vhrPitch, vhrYaw, vhrRoll] = visual_handrot; @@ -1055,7 +1062,8 @@ void V_CalcRefdef( cl.visual_handrot[cVR_MainHand], false); // VR controller aiming configuration - if(vr_enabled.value && vr_aimmode.value == VrAimMode::e_CONTROLLER) + if(vr_enabled.value && + cvarCast(vr_aimmode.value) == VrAimMode::e_CONTROLLER) { // VR: This sets the weapon model's position. view->origin = handpos + cl.vmeshoffset + gunOffset; @@ -1175,7 +1183,8 @@ void V_SetupOffHandWpnViewEnt( cl.visual_handrot[cVR_OffHand], true); // VR controller aiming configuration - if(vr_enabled.value && vr_aimmode.value == VrAimMode::e_CONTROLLER) + if(vr_enabled.value && + cvarCast(vr_aimmode.value) == VrAimMode::e_CONTROLLER) { view.origin = handpos + cl.vmeshoffset + gunOffset; } diff --git a/Quake/vr.cpp b/Quake/vr.cpp index 907eb90..c009baf 100644 --- a/Quake/vr.cpp +++ b/Quake/vr.cpp @@ -60,6 +60,12 @@ using quake::util::mapRange; using quake::util::pitchYawRollFromDirectionVector; using quake::util::redirectVector; +template +[[nodiscard]] static constexpr T cvarCast(const float x) +{ + return static_cast(static_cast>(x)); +} + // // // @@ -3641,8 +3647,10 @@ void VR_Draw2D() vr_menu_angles = cl.viewangles; } - if(vr_aimmode.value == VrAimMode::e_HEAD_MYAW || - vr_aimmode.value == VrAimMode::e_HEAD_MYAW_MPITCH) + if(cvarCast(vr_aimmode.value) == + VrAimMode::e_HEAD_MYAW || + cvarCast(vr_aimmode.value) == + VrAimMode::e_HEAD_MYAW_MPITCH) { vr_menu_angles[PITCH] = 0; } @@ -3757,7 +3765,7 @@ void VR_DrawSbar() glDisable(GL_DEPTH_TEST); // prevents drawing sprites on sprites from // interferring with one another - if(vr_aimmode.value == VrAimMode::e_CONTROLLER) + if(cvarCast(vr_aimmode.value) == VrAimMode::e_CONTROLLER) { const auto mode = cvarToEnum(vr_sbar_mode); @@ -3784,8 +3792,9 @@ void VR_DrawSbar() { sbar_angles = cl.aimangles; - if(vr_aimmode.value == VrAimMode::e_HEAD_MYAW || - vr_aimmode.value == VrAimMode::e_HEAD_MYAW_MPITCH) + if(cvarCast(vr_aimmode.value) == VrAimMode::e_HEAD_MYAW || + cvarCast(vr_aimmode.value) == + VrAimMode::e_HEAD_MYAW_MPITCH) { sbar_angles[PITCH] = 0; } @@ -3803,7 +3812,7 @@ void VR_DrawSbar() const auto sbarmode = cvarToEnum(vr_sbar_mode); - if(vr_aimmode.value == VrAimMode::e_CONTROLLER && + if(cvarCast(vr_aimmode.value) == VrAimMode::e_CONTROLLER && sbarmode == VrSbarMode::OffHand) { qquat m; @@ -4575,7 +4584,8 @@ void VR_Move(usercmd_t* cmd) if(vr_fakevr.value == 0) { - if(vr_movement_mode.value == VrMovementMode::e_RAW_INPUT) + if(cvarCast(vr_movement_mode.value) == + VrMovementMode::e_RAW_INPUT) { cmd->forwardmove += cl_forwardspeed.value * fwdMove; cmd->sidemove += cl_forwardspeed.value * sideMove; diff --git a/Quake/worldtext.hpp b/Quake/worldtext.hpp index 7e1afcb..04c4353 100644 --- a/Quake/worldtext.hpp +++ b/Quake/worldtext.hpp @@ -23,6 +23,7 @@ struct WorldText qvec3 _pos{}; qvec3 _angles{}; HAlign _hAlign{HAlign::Left}; + float _scale{1.f}; }; using WorldTextHandle = std::uint16_t;