// Client_RPG - top-down camera, click-to-move, and RPG windows for GameMode_RPG. // Camera v3: on dedicated servers the host owns the Camera transform; the client only // sends RPG_CamSync (yaw/dist) and uses stock moveMap + RPGClient_Input (no extra ActionMaps). exec("./ui.cs"); // The server probes with RPG_Probe; reply with serverCmdRPG_Hello(2) to play. $RPGClient::Version = 2; $RPGClient::Active = 0; $RPGClient::Yaw = 0; $RPGClient::Dist = 14; $RPGClient::TopDownPitch = 1.22; $RPGClient::Pitch = 1.22; $RPGClient::PitchMin = 0.55; $RPGClient::PitchMax = 1.38; $RPGClient::PitchSpeed = 0.025; $RPGClient::DistMin = 8; $RPGClient::DistMax = 30; $RPGClient::OrbitInit = 0; $RPGClient::HudPlaced = 0; $RPGClient::PlayBooted = 0; $RPGClient::CamTickOn = 0; $RPGClient::PanX = 0; $RPGClient::PanY = 0; $RPGClient::PanMax = 48; $RPGClient::YawSpeed = 0.045; $RPGClient::ZoomSpeed = 0.12; $RPGClient::CamTickSched = 0; $RPGClient::LastCamSync = 0; $RPGClient::CamSyncMs = 100; $RPGClient::TopDownFov = 0.85; $RPGClient::MvF = 0; $RPGClient::MvB = 0; $RPGClient::MvL = 0; $RPGClient::MvR = 0; $RPGClient::CamModeReady = 0; $RPGClient::HelloPending = 0; $RPGClient::HelloLast = ""; $RPGClient::TopDownWatchSched = 0; $RPGClient::CamSched = 0; $RPGClient::LastClickTime = 0; $RPGClient::ChatOpen = 0; function RPGClient_NormScreenPos(%pos) { if (!isObject(Canvas)) { return "0.5 0.5"; } %ext = Canvas.getExtent(); %w = getWord(%ext, 0); %h = getWord(%ext, 1); if (%w < 1) { %w = 1; } if (%h < 1) { %h = 1; } %x = getWord(%pos, 0) / %w; %y = getWord(%pos, 1) / %h; return RPGClient_ClampNorm(%x, %y); } function RPGClient_ClampNorm(%x, %y) { if (%x < 0) { %x = 0; } if (%x > 1) { %x = 1; } if (%y < 0) { %y = 0; } if (%y > 1) { %y = 1; } return %x SPC %y; } function RPGClient_NormPos(%ctrl, %pos) { if (isObject(Canvas)) { return RPGClient_NormScreenPos(%pos); } if (!isObject(%ctrl)) { return "0.5 0.5"; } %ext = %ctrl.getExtent(); %w = getWord(%ext, 0); %h = getWord(%ext, 1); if (%w < 1) { %w = 1; } if (%h < 1) { %h = 1; } %x = getWord(%pos, 0) / %w; %y = 1 - getWord(%pos, 1) / %h; if (%x < 0) { %x = 0; } if (%x > 1) { %x = 1; } if (%y < 0) { %y = 0; } if (%y > 1) { %y = 1; } return %x SPC %y; } function RPGClient_Aspect() { if (!isObject(Canvas)) { return 1.333; } %ext = Canvas.getExtent(); %w = getWord(%ext, 0); %h = getWord(%ext, 1); return %h > 0 ? %w / %h : 1.333; } function RPGClient_V3Len(%x, %y, %z) { return mSqrt(%x * %x + %y * %y + %z * %z); } function RPGClient_V3Norm(%x, %y, %z) { %l = RPGClient_V3Len(%x, %y, %z); if (%l < 0.0001) { return "0 0 0"; } return (%x / %l) @ " " @ (%y / %l) @ " " @ (%z / %l); } function RPGClient_V3Cross(%ax, %ay, %az, %bx, %by, %bz) { return (%ay * %bz - %az * %by) @ " " @ (%az * %bx - %ax * %bz) @ " " @ (%ax * %by - %ay * %bx); } function RPGClient_EyeRay(%nx, %ny) { %conn = RPGClient_GetConn(); %body = RPGClient_BodyForCamera(%conn); if (!isObject(%body)) { return ""; } %p = %body.getPosition(); %cx = getWord(%p, 0) + $RPGClient::PanX; %cy = getWord(%p, 1) + $RPGClient::PanY; %cz = getWord(%p, 2) + 1.5; %yaw = $RPGClient::Yaw; %dist = $RPGClient::Dist; %pitch = $RPGClient::Pitch > 0 ? $RPGClient::Pitch : $RPGClient::TopDownPitch; %bx = -mCos(%yaw) * mCos(%pitch) * %dist; %by = -mSin(%yaw) * mCos(%pitch) * %dist; %bz = mSin(%pitch) * %dist; %ex = %cx + %bx; %ey = %cy + %by; %ez = %cz + %bz; %fx = %cx - %ex; %fy = %cy - %ey; %fz = %cz - %ez; %fwd = RPGClient_V3Norm(%fx, %fy, %fz); %fw = getWord(%fwd, 0); %fh = getWord(%fwd, 1); %ff = getWord(%fwd, 2); %right = RPGClient_V3Norm(getWord(RPGClient_V3Cross(%fw, %fh, %ff, 0, 0, 1), 0), getWord(RPGClient_V3Cross(%fw, %fh, %ff, 0, 0, 1), 1), getWord(RPGClient_V3Cross(%fw, %fh, %ff, 0, 0, 1), 2)); %rw = getWord(%right, 0); %rh = getWord(%right, 1); %rf = getWord(%right, 2); %up = RPGClient_V3Norm(getWord(RPGClient_V3Cross(%rw, %rh, %rf, %fw, %fh, %ff), 0), getWord(RPGClient_V3Cross(%rw, %rh, %rf, %fw, %fh, %ff), 1), getWord(RPGClient_V3Cross(%rw, %rh, %rf, %fw, %fh, %ff), 2)); %uw = getWord(%up, 0); %uh = getWord(%up, 1); %uf = getWord(%up, 2); %fov = mTan($RPGClient::TopDownFov * 0.5); %aspect = RPGClient_Aspect(); %rx = (%nx - 0.5) * 2 * %fov * %aspect; %ry = (0.5 - %ny) * 2 * %fov; %dx = %fw + %rw * %rx + %uw * %ry; %dy = %fh + %rh * %rx + %uh * %ry; %dz = %ff + %rf * %rx + %uf * %ry; %dir = RPGClient_V3Norm(%dx, %dy, %dz); %dw = getWord(%dir, 0); %dh = getWord(%dir, 1); %df = getWord(%dir, 2); %eye = %ex @ " " @ %ey @ " " @ %ez; return %eye TAB (%ex + %dw * 250) @ " " @ (%ey + %dh * 250) @ " " @ (%ez + %df * 250); } function RPGClient_PickGround(%nx, %ny) { %conn = RPGClient_GetConn(); %body = RPGClient_BodyForCamera(%conn); if (!isObject(%body)) { return ""; } %ray = RPGClient_EyeRay(%nx, %ny); if (%ray $= "") { return ""; } %eye = getField(%ray, 0) SPC getField(%ray, 1) SPC getField(%ray, 2); %end = getField(%ray, 3) SPC getField(%ray, 4) SPC getField(%ray, 5); %ex = getWord(%eye, 0); %ey = getWord(%eye, 1); %ez = getWord(%eye, 2); %dx = getWord(%end, 0) - %ex; %dy = getWord(%end, 1) - %ey; %dz = getWord(%end, 2) - %ez; %dir = RPGClient_V3Norm(%dx, %dy, %dz); %dzw = getWord(%dir, 2); %refZ = getWord(%body.getPosition(), 2); if (mAbs(%dzw) < 0.02) { return ""; } %t = (%refZ - %ez) / %dzw; if (%t < 0 || %t > 400) { return ""; } return (%ex + getWord(%dir, 0) * %t) @ " " @ (%ey + getWord(%dir, 1) * %t) @ " " @ %refZ; } function RPGClient_SendClick(%button, %pos) { if (!isObject(ServerConnection)) { return; } %now = getSimTime(); if (%now - $RPGClient::LastClickTime < 80) { return; } $RPGClient::LastClickTime = %now; %norm = RPGClient_NormScreenPos(%pos); %nx = getWord(%norm, 0); %ny = getWord(%norm, 1); if (%button == 0) { %gnd = RPGClient_PickGround(%nx, %ny); if (%gnd !$= "") { commandToServer('RPG_Go', getWord(%gnd, 0), getWord(%gnd, 1), getWord(%gnd, 2)); return; } } commandToServer('RPG_Click', %button, %nx, %ny, RPGClient_Aspect(), $RPGClient::Yaw, $RPGClient::Dist, $RPGClient::Pitch, $RPGClient::PanX, $RPGClient::PanY); } function RPGClient_Mouse::onMouseDown(%this, %mod, %pos, %clicks) { if (!$RPGClient::Active) { return; } RPGClient_SendClick(0, %pos); } function RPGClient_Mouse::onRightMouseDown(%this, %mod, %pos, %clicks) { if (!$RPGClient::Active) { return; } RPGClient_SendClick(1, %pos); } function RPGClient_Mouse::onWake(%this) { if (isObject(Canvas)) { %ext = Canvas.getExtent(); %this.resize(0, 0, getWord(%ext, 0), getWord(%ext, 1)); } } function RPGClient_ClampPan() { %max = $RPGClient::PanMax; if ($RPGClient::PanX > %max) { $RPGClient::PanX = %max; } if ($RPGClient::PanX < -%max) { $RPGClient::PanX = -%max; } if ($RPGClient::PanY > %max) { $RPGClient::PanY = %max; } if ($RPGClient::PanY < -%max) { $RPGClient::PanY = -%max; } } function RPGClient_ViewTransform(%body, %yaw, %dist, %panX, %panY) { %p = %body.getPosition(); %cx = getWord(%p, 0) + %panX; %cy = getWord(%p, 1) + %panY; %cz = getWord(%p, 2) + 1.5; %pitch = $RPGClient::Pitch > 0 ? $RPGClient::Pitch : $RPGClient::TopDownPitch; %bx = -mCos(%yaw) * mCos(%pitch) * %dist; %by = -mSin(%yaw) * mCos(%pitch) * %dist; %bz = mSin(%pitch) * %dist; %ex = %cx + %bx; %ey = %cy + %by; %ez = %cz + %bz; %eye = %ex @ " " @ %ey @ " " @ %ez; %euler = (-%pitch) @ " 0 " @ (%yaw + $pi); %rot = eulerRadToMatrix(%euler); return %eye @ " " @ %rot; } function RPGClient_EnsureCursor() { if (!$RPGClient::Active || !isObject(Canvas)) { return; } if (Canvas.isCursorOn()) { return; } lockMouse(0); cursorOn(); } function RPGClient_NetCam() { return isObject(ServerConnection) && !isObject(localClientConnection); } function RPGClient_CameraTick() { $RPGClient::CamTickSched = 0; RPGClient_PollChatOpen(); if (!isObject(ServerConnection) || !$RPGClient::CamTickOn) { return; } %spin = $RPGClient::YawSpeed * 2.5; %tilt = $RPGClient::PitchSpeed * 2.5; %zoom = $RPGClient::ZoomSpeed * 2.5; %changed = 0; if ($RPGClient::MvL > 0) { $RPGClient::Yaw = $RPGClient::Yaw - %spin * $RPGClient::MvL; %changed = 1; } if ($RPGClient::MvR > 0) { $RPGClient::Yaw = $RPGClient::Yaw + %spin * $RPGClient::MvR; %changed = 1; } if ($RPGClient::MvF > 0) { $RPGClient::Pitch = getMin($RPGClient::PitchMax, $RPGClient::Pitch + %tilt * $RPGClient::MvF); %changed = 1; } if ($RPGClient::MvB > 0) { $RPGClient::Pitch = getMax($RPGClient::PitchMin, $RPGClient::Pitch - %tilt * $RPGClient::MvB); %changed = 1; } if (%changed || $RPGClient::MvF || $RPGClient::MvB || $RPGClient::MvL || $RPGClient::MvR) { RPGClient_ApplyCamera(0); } $RPGClient::CamTickSched = schedule(50, 0, RPGClient_CameraTick); } function RPGClient_StartCameraTick() { cancel($RPGClient::CamTickSched); $RPGClient::CamTickSched = schedule(50, 0, RPGClient_CameraTick); } function RPGClient_InPlay() { return isObject(ServerConnection) && ($RPGClient::Server || $RPGClient::Active); } function RPGClient_TextTyping() { return $RPGClient::ChatOpen; } function RPGClient_SetChatOpen(%open) { $RPGClient::ChatOpen = %open ? 1 : 0; } function RPGClient_PollChatOpen() { if (!$RPGClient::ChatOpen || !isObject(newChatText)) { return; } if (!newChatText.isVisible()) { $RPGClient::ChatOpen = 0; } } function RPGClient_RpgKeys() { return $RPGClient::Active && !RPGClient_TextTyping(); } function RPGClient_CamInputAllowed() { if (!RPGClient_RpgKeys()) { return 0; } if (!$RPGClient::CamTickOn) { $RPGClient::CamTickOn = 1; } return 1; } function RPGClient_BootPlay() { if (!isObject(ServerConnection)) { return; } $RPGClient::Server = 1; $RPGClient::Active = 1; $RPGClient::CamTickOn = 1; $RPGClient::PlayBooted = 1; if ($RPGClient::Dist < 6) { $RPGClient::Dist = 14; } RPGClient_StockMoveMapBinds(); RPGClient_EnsureOverlay(); RPGClient_BindKeys(); RPGClient_StartCameraTick(); RPGClient_ScheduleCamera(); RPGClient_EnsureCursor(); } function RPGClient_KeyMvForward(%val) { if (!isObject(ServerConnection)) { return; } if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { moveforward(%val); return; } $RPGClient::MvF = %val; } function RPGClient_KeyMvBackward(%val) { if (!isObject(ServerConnection)) { return; } if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { movebackward(%val); return; } $RPGClient::MvB = %val; } function RPGClient_KeyMvLeft(%val) { if (!isObject(ServerConnection)) { return; } if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { moveleft(%val); return; } $RPGClient::MvL = %val; } function RPGClient_KeyMvRight(%val) { if (!isObject(ServerConnection)) { return; } if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { moveright(%val); return; } $RPGClient::MvR = %val; } function RPGClient_StockMoveMapBinds() { if (!isObject(moveMap)) { return; } moveMap.bind(keyboard, w, moveforward); moveMap.bind(keyboard, s, movebackward); moveMap.bind(keyboard, a, moveleft); moveMap.bind(keyboard, d, moveright); moveMap.bind(keyboard, left, invLeft); moveMap.bind(keyboard, right, invRight); moveMap.bind(keyboard, equals, RPGClient_ZoomIn); moveMap.bind(keyboard, minus, RPGClient_ZoomOut); moveMap.bind(keyboard, "[", RPGClient_ZoomIn); moveMap.bind(keyboard, "]", RPGClient_ZoomOut); } function RPGClient_RestoreMoveMap() { RPGClient_StockMoveMapBinds(); } function RPGClient_SendClickFromCursor(%button) { if (!$RPGClient::Active || !isObject(Canvas)) { return; } RPGClient_SendClick(%button, Canvas.getCursorPos()); } function RPGClient_EnsureOverlay() { if (!isObject(PlayGui)) { return; } if (!isObject(RPGClient_Mouse)) { new GuiMouseEventCtrl(RPGClient_Mouse) { className = "RPGClient_Mouse"; horizSizing = "width"; vertSizing = "height"; position = "0 0"; extent = "640 480"; profile = "GuiDefaultProfile"; visible = "1"; enabled = "1"; modal = "0"; }; PlayGui.add(RPGClient_Mouse); PlayGui.pushToBack(RPGClient_Mouse); } if (isObject(RPGClient_Mouse) && isObject(Canvas)) { %ext = Canvas.getExtent(); RPGClient_Mouse.resize(0, 0, getWord(%ext, 0), getWord(%ext, 1)); } if ($RPGClient::Active) { RPGClient_StockMoveMapBinds(); } $enableDirectInput = 1; activateDirectInput(); $mvFreeLook = 0; $firstPerson = 0; if (isObject(Canvas) && !Canvas.isCursorOn()) { Canvas.cursorOn(); } if (isObject(PlayGui)) { PlayGui.killToolHud(); } } function RPGClient_EnableOverlay() { RPGClient_EnsureOverlay(); } function RPGClient_ToggleCursor(%val) { if (!$RPGClient::Active || !%val) { return; } ToggleCursor(%val); } function RPGClient_DisableOverlay() { cancel($RPGClient::CamSched); $RPGClient::CamSched = 0; cancel($RPGClient::CamTickSched); $RPGClient::CamTickSched = 0; $RPGClient::MvF = 0; $RPGClient::MvB = 0; $RPGClient::MvL = 0; $RPGClient::MvR = 0; if (isObject(RPGClient_Mouse)) { RPGClient_Mouse.delete(); } $RPGClient::Active = 0; $RPGClient::OrbitInit = 0; $RPGClient::HudPlaced = 0; $RPGClient::PlayBooted = 0; $RPGClient::CamTickOn = 0; $RPGClient::ChatOpen = 0; RPGClient_RestoreMoveMap(); } function RPGClient_Hud_Place() { if (!isObject(RPGClient_Hud) || !isObject(Canvas)) { return; } %ext = Canvas.getExtent(); %w = getWord(%ext, 0); %h = getWord(%ext, 1); if (%h < 1) { return; } %pw = %w > 520 ? 520 : %w - 16; %px = mFloor((%w - %pw) * 0.5); %py = %h - 108; if (%py < 8) { %py = 8; } RPGClient_Hud.resize(%px, %py, %pw, 20); $RPGClient::HudPlaced = 1; } function RPGClient_ApplyCamera(%forceSync) { %now = getSimTime(); %doSync = %forceSync || %now - $RPGClient::LastCamSync >= $RPGClient::CamSyncMs; if (!%doSync || !isObject(ServerConnection)) { return; } $RPGClient::LastCamSync = %now; commandToServer('RPG_CamSync', $RPGClient::Yaw, $RPGClient::Dist, $RPGClient::PanX, $RPGClient::PanY, $RPGClient::Pitch); if (RPGClient_NetCam()) { return; } %conn = RPGClient_GetConn(); if (!isObject(%conn)) { return; } %body = RPGClient_BodyForCamera(%conn); if (!isObject(%body)) { return; } %cam = %conn.Camera; if (!isObject(%cam)) { %cam = %conn.camera; } if (!isObject(%cam)) { return; } %conn.setControlObject(%cam); $mvFreeLook = 0; $firstPerson = 0; %xfm = RPGClient_ViewTransform(%body, $RPGClient::Yaw, $RPGClient::Dist, $RPGClient::PanX, $RPGClient::PanY); %cam.unmountImage(0); if (!$RPGClient::OrbitInit) { %cam.setMode("Corpse", %body); %cam.mode = "Corpse"; %cam.thirdPersonOnly = 1; $RPGClient::OrbitInit = 1; } %cam.setOrbitMode(%body, %xfm, 0, 32, $RPGClient::Dist); %cam.setTransform(%xfm); %cam.setOrbitDist($RPGClient::Dist); } function RPGClient_ScheduleCamera() { cancel($RPGClient::CamSched); RPGClient_ApplyCamera(1); } function RPGClient_YawLeft(%val) { if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { return; } $RPGClient::MvL = %val; } function RPGClient_YawRight(%val) { if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { return; } $RPGClient::MvR = %val; } function RPGClient_ZoomIn(%val) { if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { return; } if (%val) { $RPGClient::Dist = getMax($RPGClient::DistMin, $RPGClient::Dist - 2.5); RPGClient_ApplyCamera(1); } } function RPGClient_ZoomOut(%val) { if (!RPGClient_CamInputAllowed()) { return; } if (!$RPGClient::CamTickOn) { return; } if (%val) { $RPGClient::Dist = getMin($RPGClient::DistMax, $RPGClient::Dist + 2.5); RPGClient_ApplyCamera(1); } } function RPGClient_CanSendCmd() { return isObject(ServerConnection) || isObject(localClientConnection); } function RPGClient_GetConn() { if (isObject(ServerConnection)) { return ServerConnection; } if (isObject(localClientConnection)) { return localClientConnection; } return 0; } function RPGClient_BodyForCamera(%conn) { if (!isObject(%conn)) { return 0; } %body = %conn.Player; if (!isObject(%body)) { %body = %conn.player; } if (!isObject(%body)) { %co = %conn.getControlObject(); if (isObject(%co) && %co.getClassName() $= "Camera" && isObject(%co.getOrbitObject())) { %body = %co.getOrbitObject(); } } if (!isObject(%body) && isObject(%conn.Camera) && isObject(%conn.Camera.getOrbitObject())) { %body = %conn.Camera.getOrbitObject(); } return %body; } function RPGClient_SendHello() { if ($RPGClient::Server) { return; } if (!RPGClient_CanSendCmd()) { return; } %now = getSimTime(); if ($RPGClient::HelloLast !$= "" && %now - $RPGClient::HelloLast < 900) { return; } $RPGClient::HelloLast = %now; commandToServer('RPG_Hello', $RPGClient::Version); commandToServer('RPGHello', $RPGClient::Version); commandToServer('Message', "/rpg clienthello " @ $RPGClient::Version); } function clientCmdRPG_Probe() { RPGClient_SendHello(); } function clientCmdRPG_Welcome(%serverProto, %accepted) { if (%accepted && %serverProto == $RPGClient::Version) { $RPGClient::HelloPending = 0; $RPGClient::Server = 1; schedule(0, 0, RPGClient_BootPlay); schedule(2500, 0, RPGClient_TopDownWatch); } else if (!%accepted) { echo("Client_RPG: server rejected handshake (server proto " @ %serverProto @ ")"); schedule(1500, 0, RPGClient_SendHello); } } function RPGClient_TopDownWatch() { $RPGClient::TopDownWatchSched = 0; if ($RPGClient::Active || $RPGClient::Server || !RPGClient_CanSendCmd()) { return; } $RPGClient::HelloLast = ""; RPGClient_SendHello(); $RPGClient::TopDownWatchSched = schedule(2500, 0, RPGClient_TopDownWatch); } function RPGClient_EnsurePlayGui() { if (!isObject(PlayGui) || !isObject(Canvas)) { return 0; } if (Canvas.getContent() != PlayGui.getId()) { Canvas.setContent(PlayGui); } return 1; } function clientCmdRPG_Camera(%yaw, %dist, %pitch) { $RPGClient::Yaw = %yaw; if (%dist > 0) { $RPGClient::Dist = %dist; } if (%pitch > 0) { $RPGClient::Pitch = %pitch; } } function clientCmdRPG_TopDown(%on, %yaw, %dist) { if (%on) { $RPGClient::Server = 1; $RPGClient::Active = 1; $RPGClient::PlayBooted = 1; if (%dist > 0) { $RPGClient::Dist = %dist; } $RPGClient::Yaw = %yaw; if (!RPGClient_EnsurePlayGui()) { RPGClient_BootPlay(); schedule(200, 0, clientCmdRPG_TopDown, %on, %yaw, %dist); return; } cancel($RPGClient::TopDownWatchSched); $RPGClient::TopDownWatchSched = 0; if (%dist > 0) { $RPGClient::Dist = %dist; } else if ($RPGClient::Dist < 6) { $RPGClient::Dist = 14; } $RPGClient::Yaw = %yaw; $RPGClient::OrbitInit = 0; $RPGClient::HudPlaced = 0; $RPGClient::CamTickOn = 1; RPGClient_EnsureOverlay(); RPGClient_BindKeys(); RPGClient_StartCameraTick(); schedule(500, 0, RPGClient_EnsureOverlay); schedule(1500, 0, RPGClient_EnsureOverlay); RPGClient_EnsureCursor(); RPGClient_Hud_Ensure(); } else { $RPGClient::Server = 0; $RPGClient::PlayBooted = 0; RPGClient_DisableOverlay(); RPGClient_UnbindKeys(); } } function clientCmdRPG_Hud(%hp, %maxHp, %silver, %load, %cap, %skillId, %skillValue, %blocking, %tHp, %tMax) { RPGClient_BootPlay(); RPGClient_Hud_Update(%hp, %maxHp, %silver, %load, %cap, %skillId, %skillValue, %tHp, %tMax); } function clientCmdRPG_HudOff() { RPGClient_Hud_Hide(); } function clientCmdRPG_Notify(%text, %sec) { if (%text !$= "") { RPGClient_Notify_Show(%text, %sec); } } function clientCmdRPG_Dialog(%title, %body, %sec) { RPGClient_Dialog_Show(%title, %body, %sec); } function clientCmdRPG_ListBegin(%title, %page, %pages) { RPGClient_List_Begin(%title, %page, %pages); } function clientCmdRPG_ListRow(%row) { RPGClient_List_Row(%row); } function clientCmdRPG_ListEnd() { RPGClient_List_End(); } // --- HUD / list / dialog (Phase 4): thin windows on PlayGui --- function RPGClient_Hud_Ensure() { if (isObject(RPGClient_Hud)) { return; } new GuiTextCtrl(RPGClient_Hud) { horizSizing = "absolute"; vertSizing = "absolute"; position = "8 400"; extent = "520 20"; profile = "ChatHudMessageProfile"; text = ""; }; PlayGui.add(RPGClient_Hud); RPGClient_Hud_Place(); } function RPGClient_Hud_Update(%hp, %maxHp, %silver, %load, %cap, %skillId, %skillValue, %tHp, %tMax) { if (!$RPGClient::Active) { return; } RPGClient_Hud_Ensure(); if (!$RPGClient::HudPlaced) { RPGClient_Hud_Place(); } %t = ""; if (%tMax > 0) { %t = " | Target " @ %tHp @ "/" @ %tMax; } RPGClient_Hud.setText("HP " @ %hp @ "/" @ %maxHp @ %t @ " | " @ %silver @ " silver | load " @ %load @ "/" @ %cap @ " | " @ %skillId @ " " @ %skillValue); } function RPGClient_Hud_Hide() { if (isObject(RPGClient_Hud)) { RPGClient_Hud.setText(""); } } function RPGClient_Notify_Show(%text, %sec) { RPGClient_Hud_Ensure(); RPGClient_Hud.setText(%text); if (%sec > 0) { schedule(%sec * 1000, RPGClient_Hud, setText, ""); } } function RPGClient_Dialog_Show(%title, %body, %sec) { messageBoxOK(%title, %body, ""); } function RPGClient_List_Begin(%title, %page, %pages) { $RPGClient::ListBody = ""; $RPGClient::ListTitle = %title @ " (" @ (%page + 1) @ "/" @ %pages @ ")"; } function RPGClient_List_Row(%row) { $RPGClient::ListBody = $RPGClient::ListBody @ %row @ "\n"; } function RPGClient_List_End() { if ($RPGClient::ListBody !$= "") { messageBoxOK($RPGClient::ListTitle, $RPGClient::ListBody, ""); } } package RPGClient_BlockMouseFire { function mouseFire(%val) { if ($RPGClient::Active) { if (%val) { RPGClient_SendClickFromCursor(0); } return; } Parent::mouseFire(%val); } function altTrigger(%val) { if ($RPGClient::Active) { if (%val) { RPGClient_SendClickFromCursor(1); } return; } Parent::altTrigger(%val); } }; activatePackage(RPGClient_BlockMouseFire); package RPGClient_PageKeys { function PageUpNewChatHud(%val) { if (RPGClient_RpgKeys() && %val) { RPGClient_ZoomIn(1); return; } Parent::PageUpNewChatHud(%val); } function PageDownNewChatHud(%val) { if (RPGClient_RpgKeys() && %val) { RPGClient_ZoomOut(1); return; } Parent::PageDownNewChatHud(%val); } }; activatePackage(RPGClient_PageKeys); package RPGClient_Input { function moveforward(%val) { if (RPGClient_CamInputAllowed()) { RPGClient_KeyMvForward(%val); return; } Parent::moveforward(%val); } function movebackward(%val) { if (RPGClient_CamInputAllowed()) { RPGClient_KeyMvBackward(%val); return; } Parent::movebackward(%val); } function moveleft(%val) { if (RPGClient_CamInputAllowed()) { RPGClient_KeyMvLeft(%val); return; } Parent::moveleft(%val); } function moveright(%val) { if (RPGClient_CamInputAllowed()) { RPGClient_KeyMvRight(%val); return; } Parent::moveright(%val); } function invLeft(%val) { if (RPGClient_RpgKeys()) { RPGClient_YawLeft(%val); return; } Parent::invLeft(%val); } function invRight(%val) { if (RPGClient_RpgKeys()) { RPGClient_YawRight(%val); return; } Parent::invRight(%val); } function scrollInventory(%val) { if (RPGClient_RpgKeys() && %val != 0) { if (%val > 0) { $RPGClient::Dist = getMax($RPGClient::DistMin, $RPGClient::Dist - 0.5 * %val); } else { $RPGClient::Dist = getMin($RPGClient::DistMax, $RPGClient::Dist - 0.5 * %val); } RPGClient_ApplyCamera(1); return; } Parent::scrollInventory(%val); } function yaw(%val) { if (RPGClient_CamInputAllowed() && %val != 0) { %sens = $pref::Input::MouseSensitivity; $RPGClient::Yaw = $RPGClient::Yaw + %val * %sens * 0.004; RPGClient_ApplyCamera(0); return; } Parent::yaw(%val); } }; activatePackage(RPGClient_Input); package RPGClient_ZoomKeys { function shiftBrickUp(%val) { if (RPGClient_RpgKeys() && %val) { RPGClient_ZoomIn(1); return; } Parent::shiftBrickUp(%val); } function shiftBrickDown(%val) { if (RPGClient_RpgKeys() && %val) { RPGClient_ZoomOut(1); return; } Parent::shiftBrickDown(%val); } }; activatePackage(RPGClient_ZoomKeys); package RPGClient_MapStack { function noHudGui::onWake(%this) { Parent::onWake(%this); if ($RPGClient::Active) { schedule(0, 0, RPGClient_EnsureOverlay); } } }; activatePackage(RPGClient_MapStack); package RPGClient_Cursor { function GuiCanvas::checkCursor(%this) { Parent::checkCursor(%this); if ($RPGClient::Active && !%this.isCursorOn()) { lockMouse(0); %this.cursorOn(); } } function escapeMenu::toggle(%this) { if (%this.isAwake()) { Canvas.popDialog(%this); if ($RPGClient::Active) { schedule(0, 0, RPGClient_EnsureCursor); schedule(0, 0, RPGClient_EnsureOverlay); } return; } if (Canvas.getContent().getName() $= "LoadingGui") { disconnect(); return; } Canvas.pushDialog(%this); if ($RPGClient::Active) { RPGClient_SetChatOpen(0); } } }; activatePackage(RPGClient_Cursor); package RPGClient_ViewLock { function toggleFirstPerson(%val) { if ($RPGClient::Active) { return; } Parent::toggleFirstPerson(%val); } function toggleFreeLook(%val) { if ($RPGClient::Active) { return; } Parent::toggleFreeLook(%val); } function dropCameraAtPlayer(%val) { if ($RPGClient::Active) { return; } Parent::dropCameraAtPlayer(%val); } }; activatePackage(RPGClient_ViewLock); package RPGClient_Cleanup { function disconnectedCleanup(%doReconnect) { RPGClient_DisableOverlay(); RPGClient_UnbindKeys(); $RPGClient::Server = 0; $RPGClient::HelloPending = 0; $RPGClient::HelloLast = ""; cancel($RPGClient::TopDownWatchSched); $RPGClient::TopDownWatchSched = 0; $RPGClient::Server = 0; $RPGClient::PlayBooted = 0; $RPGClient::CamTickOn = 0; RPGClient_RestoreMoveMap(); Parent::disconnectedCleanup(%doReconnect); } }; activatePackage(RPGClient_Cleanup); package RPGClient_Mission { function onMissionDownloadComplete() { Parent::onMissionDownloadComplete(); schedule(250, 0, RPGClient_SendHello); } }; activatePackage(RPGClient_Mission); package RPGClient_ChatKeys { function GlobalChat(%val) { Parent::GlobalChat(%val); if ($RPGClient::Active && %val) { RPGClient_SetChatOpen(1); } } function TeamChat(%val) { Parent::TeamChat(%val); if ($RPGClient::Active && %val) { RPGClient_SetChatOpen(1); } } }; activatePackage(RPGClient_ChatKeys); echo("Client_RPG loaded (protocol " @ $RPGClient::Version @ ")");