The F3 key now consistently works while playing and while spectating another player
alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
alias menu_showquitdialog "menu_cmd directmenu Quit"
alias menu_showgamemenudialog "menu_cmd directmenu GameMenu"
+alias menu_showforfeitdialog "menu_cmd directmenu Forfeit"
alias menu_showmonstertools "menu_cmd directmenu MonsterTools"
// command executed before loading a map by the menu
{
// they're going to spec, we can do other checks
if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
- Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
+ return MUT_SPECCMD_RETURN_FORFEIT;
return MUT_SPECCMD_FORCE;
}
{
// they're going to spec, we can do other checks
if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
- Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
+ return MUT_SPECCMD_RETURN_FORFEIT;
return MUT_SPECCMD_FORCE;
}
#include <menu/xonotic/dialog.qc>
#include <menu/xonotic/dialog_credits.qc>
#include <menu/xonotic/dialog_firstrun.qc>
+#include <menu/xonotic/dialog_forfeit.qc>
#include <menu/xonotic/dialog_gamemenu.qc>
#include <menu/xonotic/dialog_hudpanel_ammo.qc>
#include <menu/xonotic/dialog_hudpanel_centerprint.qc>
#include <menu/xonotic/dialog.qh>
#include <menu/xonotic/dialog_credits.qh>
#include <menu/xonotic/dialog_firstrun.qh>
+#include <menu/xonotic/dialog_forfeit.qh>
#include <menu/xonotic/dialog_gamemenu.qh>
#include <menu/xonotic/dialog_hudpanel_ammo.qh>
#include <menu/xonotic/dialog_hudpanel_centerprint.qh>
--- /dev/null
+#include "dialog_forfeit.qh"
+
+#include "button.qh"
+#include "commandbutton.qh"
+#include "textlabel.qh"
+
+void XonoticForfeitDialog_fill(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to observe and quit current match?")));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "spec \"\" FORFEIT", COMMANDBUTTON_CLOSE));
+ me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
--- /dev/null
+#pragma once
+
+#include "dialog.qh"
+CLASS(XonoticForfeitDialog, XonoticRootDialog)
+ METHOD(XonoticForfeitDialog, fill, void(entity));
+ ATTRIB(XonoticForfeitDialog, title, string, _("Forfeit"));
+ ATTRIB(XonoticForfeitDialog, name, string, "Forfeit");
+ ATTRIB(XonoticForfeitDialog, color, vector, SKINCOLOR_DIALOG_QUIT);
+ ATTRIB(XonoticForfeitDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticForfeitDialog, rows, float, 3);
+ ATTRIB(XonoticForfeitDialog, columns, float, 2);
+ENDCLASS(XonoticForfeitDialog)
#include "inputbox.qh"
#include "dialog_termsofservice.qh"
#include "dialog_firstrun.qh"
+#include "dialog_forfeit.qh"
#include "dialog_hudsetup_exit.qh"
#include "dialog_hudpanel_notification.qh"
#include "dialog_hudpanel_ammo.qh"
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ i = NEW(XonoticForfeitDialog);
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
i = NEW(XonoticMonsterToolsDialog);
i.configureDialog(i);
me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
return;
}
+ bool caller_wants_to_forfeit = false;
+ if (argv(2) == "FORFEIT" || warmup_stage)
+ caller_wants_to_forfeit = true; // player replied that they want to forfeit
+
+ if (IS_PLAYER(caller) && !caller_wants_to_forfeit)
+ {
+ // ask player if they want to forfeit
+ stuffcmd(caller, "menu_showforfeitdialog\n");
+ return;
+ }
+
+ if (IS_SPEC(caller) && (!observe_blocked_if_eliminated || !INGAME(caller)))
+ {
+ // turn spectator into observer
+ caller.would_spectate = false;
+ TRANSMUTE(Observer, caller);
+ PutClientInServer(caller);
+ caller.flags |= FL_CLIENT | FL_NOTARGET;
+ return;
+ }
+
int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
+ if (mutator_returnvalue == MUT_SPECCMD_RETURN_FORFEIT)
+ {
+ if (caller_wants_to_forfeit)
+ mutator_returnvalue = MUT_SPECCMD_FORCE;
+ else
+ {
+ stuffcmd(caller, "menu_showobservedialog\n");
+ return;
+ }
+ }
+
if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE || caller.wants_join))
if (autocvar_sv_spectate)
ClientKill_TeamChange(caller, -2); // observe
default:
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd spectate [<client>]\n");
+ sprint(caller, "\nUsage:^3 cmd spectate [<client>] [FORFEIT]\n");
sprint(caller, " Where <client> can be the player to spectate.\n");
+ sprint(caller, " If <client> is \"\" or not specified, caller becomes observer.\n");
+ sprint(caller, " If <client> is \"\", FORFEIT makes so that caller forcedly quits current game.\n");
return;
}
}
enum {
MUT_SPECCMD_CONTINUE, // return this flag to make the function continue as normal
MUT_SPECCMD_RETURN, // return this flag to make the function return (don't spectate)
+ MUT_SPECCMD_RETURN_FORFEIT, // like MUT_SPECCMD_RETURN and ask player if they want to forfeit
MUT_SPECCMD_FORCE // return this flag to force the player to spectate, even if they're not a player
};