// Client_RPG - top-down camera, click-to-move, and RPG windows for GameMode_RPG. 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::HelloPending = 0; $RPGClient::HelloLast = ""; function RPGClient_NormPos(%ctrl, %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_SendClick(%button, %pos) { if (!isObject(ServerConnection)) { return; } %norm = RPGClient_NormPos(RPGClient_Mouse, %pos); commandToServer('RPG_Click', %button, getWord(%norm, 0), getWord(%norm, 1), RPGClient_Aspect()); } 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_EnableOverlay() { if (!isObject(PlayGui) || isObject(RPGClient_Mouse)) { return; } new GuiMouseEventCtrl(RPGClient_Mouse) { className = "RPGClient_Mouse"; horizSizing = "width"; vertSizing = "height"; position = "0 0"; extent = "640 480"; profile = "GuiDefaultProfile"; visible = "1"; enabled = "1"; }; PlayGui.add(RPGClient_Mouse); PlayGui.pushToBack(RPGClient_Mouse); if (isObject(RPGClient_KeyMap)) { RPGClient_KeyMap.delete(); } new ActionMap(RPGClient_KeyMap); RPGClient_KeyMap.bind(keyboard0, a, RPGClient_YawLeft); RPGClient_KeyMap.bind(keyboard0, d, RPGClient_YawRight); RPGClient_KeyMap.bind(keyboard0, left, RPGClient_YawLeft); RPGClient_KeyMap.bind(keyboard0, right, RPGClient_YawRight); RPGClient_KeyMap.bind(keyboard0, "pageup", RPGClient_ZoomIn); RPGClient_KeyMap.bind(keyboard0, "pagedown", RPGClient_ZoomOut); RPGClient_KeyMap.bind(keyboard0, equals, RPGClient_ZoomIn); RPGClient_KeyMap.bind(keyboard0, minus, RPGClient_ZoomOut); Canvas.pushDialog(RPGClient_Mouse, 0); RPGClient_KeyMap.push(); if (isObject(PlayGui)) { PlayGui.killToolHud(); } } function RPGClient_DisableOverlay() { if (isObject(RPGClient_KeyMap)) { RPGClient_KeyMap.pop(); } if (isObject(RPGClient_Mouse)) { Canvas.popDialog(RPGClient_Mouse); RPGClient_Mouse.delete(); } $RPGClient::Active = 0; } function RPGClient_ApplyCamera() { if (!isObject(localClientConnection) || !isObject(localClientConnection.player)) { return; } %body = localClientConnection.player; %cam = localClientConnection.getControlObject(); if (!isObject(%cam) || %cam.getClassName() !$= "Camera") { %cam = localClientConnection.camera; } if (!isObject(%cam)) { return; } localClientConnection.setControlObject(%cam); %rot = "0 0" SPC mSin($RPGClient::Yaw / 2) SPC mCos($RPGClient::Yaw / 2); %cam.setOrbitMode(%body, %body.getTransform(), 4, 32, $RPGClient::Dist); %cam.thirdPersonOnly = 1; commandToServer('RPG_CamSync', $RPGClient::Yaw, $RPGClient::Dist); } function RPGClient_YawLeft(%val) { if (!$RPGClient::Active || %val == 0) { return; } $RPGClient::Yaw = $RPGClient::Yaw - 0.06; RPGClient_ApplyCamera(); } function RPGClient_YawRight(%val) { if (!$RPGClient::Active || %val == 0) { return; } $RPGClient::Yaw = $RPGClient::Yaw + 0.06; RPGClient_ApplyCamera(); } function RPGClient_ZoomIn(%val) { if (!$RPGClient::Active || %val == 0) { return; } $RPGClient::Dist = getMax(6, $RPGClient::Dist - 0.6); RPGClient_ApplyCamera(); } function RPGClient_ZoomOut(%val) { if (!$RPGClient::Active || %val == 0) { return; } $RPGClient::Dist = getMin(32, $RPGClient::Dist + 0.6); RPGClient_ApplyCamera(); } function RPGClient_CanSendCmd() { return isObject(ServerConnection) || isObject(localClientConnection); } 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::Server = 1; $RPGClient::HelloPending = 0; } else if (!%accepted) { echo("Client_RPG: server rejected handshake (server proto " @ %serverProto @ ")"); schedule(1500, 0, RPGClient_SendHello); } } function clientCmdRPG_TopDown(%on, %yaw, %dist) { if (%on) { $RPGClient::Active = 1; $RPGClient::Yaw = %yaw; $RPGClient::Dist = %dist > 0 ? %dist : 14; RPGClient_EnableOverlay(); RPGClient_BindKeys(); schedule(50, 0, RPGClient_ApplyCamera); schedule(200, 0, RPGClient_ApplyCamera); } else { RPGClient_DisableOverlay(); RPGClient_UnbindKeys(); } } function clientCmdRPG_Hud(%hp, %maxHp, %silver, %load, %cap, %skillId, %skillValue, %blocking, %tHp, %tMax) { 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 = "width"; vertSizing = "top"; position = "8 8"; extent = "600 24"; profile = "ChatHudMessageProfile"; text = ""; }; PlayGui.add(RPGClient_Hud); } function RPGClient_Hud_Update(%hp, %maxHp, %silver, %load, %cap, %skillId, %skillValue, %tHp, %tMax) { if (!$RPGClient::Active) { return; } RPGClient_Hud_Ensure(); %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_Cleanup { function disconnectedCleanup(%doReconnect) { RPGClient_DisableOverlay(); RPGClient_UnbindKeys(); $RPGClient::Server = 0; $RPGClient::HelloPending = 0; $RPGClient::HelloLast = ""; Parent::disconnectedCleanup(%doReconnect); } }; activatePackage(RPGClient_Cleanup); package RPGClient_Mission { function onMissionDownloadComplete() { Parent::onMissionDownloadComplete(); schedule(250, 0, RPGClient_SendHello); } }; activatePackage(RPGClient_Mission); echo("Client_RPG loaded (protocol " @ $RPGClient::Version @ ")");