/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 1998-2000, Matthes Bender * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2009-2013, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ // Engine internal C4Menus: Main menu, Options, Player join, Hostility, etc. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ----------------------------------------------------------- // C4MainMenu C4MainMenu::C4MainMenu() : C4Menu() // will be re-adjusted later { Clear(); } void C4MainMenu::Default() { C4Menu::Default(); Player=NO_OWNER; } bool C4MainMenu::InitRefSym(const C4Facet &fctSymbol, const char *szEmpty, int32_t iPlayer, int32_t iId, int32_t iStyle) { if (!DoInitRefSym(fctSymbol, szEmpty, iId, iStyle)) return false; Player=iPlayer; return true; } bool C4MainMenu::ActivateNewPlayer(int32_t iPlayer) { // league or replay game if (Game.Parameters.isLeague() || Game.C4S.Head.Replay) return false; // Max player limit if (::Players.GetCount() >= Game.Parameters.MaxPlayers) return false; // Menu symbol/init if (GfxR->fctPlayerClr.Surface) GfxR->fctPlayerClr.Surface->SetClr(0xff); InitRefSym(GfxR->fctPlayerClr, LoadResStr("IDS_MENU_CPNEWPLAYER"), iPlayer, 0, C4MN_Style_Context); for (DirectoryIterator iter(Config.General.UserDataPath); *iter; ++iter) if (WildcardMatch("*.ocp", *iter)) { char szFilename[_MAX_PATH+1], szCommand[_MAX_PATH+30+1]; SCopy(*iter, szFilename, _MAX_PATH); if (DirectoryExists(szFilename)) continue; if (::Players.FileInUse(szFilename)) continue; // Open group C4Group hGroup; if (!hGroup.Open(szFilename)) continue; // Load player info C4PlayerInfoCore C4P; if (!C4P.Load(hGroup)) { hGroup.Close(); continue; } // Load custom portrait C4FacetSurface fctSymbol; if (!fctSymbol.Load(hGroup, C4CFN_BigIcon, C4FCT_Full, C4FCT_Full, false, true)) fctSymbol.Load(hGroup, C4CFN_BigIcon, C4FCT_Full, C4FCT_Full, false, true); // Close group hGroup.Close(); // Add player item sprintf(szCommand, "JoinPlayer:%s", szFilename); StdStrBuf sItemText; sItemText.Format(LoadResStr("IDS_MENU_NEWPLAYER"), C4P.PrefName); // No custom portrait: use default player image if (!fctSymbol.Surface) { fctSymbol.Create(C4SymbolSize, C4SymbolSize); GfxR->fctPlayerClr.DrawClr(fctSymbol, true, C4P.PrefColorDw); } // Add menu item Add(sItemText.getData(), fctSymbol, szCommand); // Reset symbol facet (menu holds on to the surface) fctSymbol.Default(); } // Alignment SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::DoRefillInternal(bool &rfRefilled) { // Variables C4FacetSurface fctSymbol; C4Player *pPlayer; C4IDList ListItems; C4Facet fctTarget; bool fWasEmpty = !GetItemCount(); // Refill switch (Identification) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4MN_Hostility: { // Clear items ClearItems(); // Refill player if (!(pPlayer = ::Players.Get(Player))) return false; // Refill items C4Player *pPlr; int32_t iIndex; for (iIndex=0; (pPlr = ::Players.GetByIndex(iIndex)); iIndex++) // Ignore player self and invisible if (pPlr != pPlayer) if (!pPlr->IsInvisible()) { // Symbol fctSymbol.Create(C4SymbolSize,C4SymbolSize); pPlayer->DrawHostility(fctSymbol,iIndex); // Message StdStrBuf sMsg; bool isFriendly = pPlayer->Hostility.find(pPlr) == pPlayer->Hostility.end(); if (isFriendly) sMsg.Format(LoadResStr("IDS_MENU_ATTACK"),pPlr->GetName()); else sMsg.Format(LoadResStr("IDS_MENU_NOATTACK"),pPlr->GetName()); // Command char szCommand[1000]; sprintf(szCommand,"SetHostility:%i",pPlr->Number); // Info caption char szInfoCaption[C4MaxTitle+1],szFriendly[50],szNot[30]=""; SCopy(LoadResStr(isFriendly ? "IDS_MENU_ATTACKHOSTILE" : "IDS_MENU_ATTACKFRIENDLY"),szFriendly); if (!isFriendly) SCopy(LoadResStr("IDS_MENU_ATTACKNOT"),szNot); sprintf(szInfoCaption,LoadResStr("IDS_MENU_ATTACKINFO"),pPlr->GetName(),szFriendly,szNot); if (iIndex==pPlayer->Number) SCopy(LoadResStr("IDS_MENU_ATTACKSELF"),szInfoCaption); // Add item Add(sMsg.getData(),fctSymbol,szCommand,szInfoCaption); fctSymbol.Default(); } break; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4MN_TeamSelection: case C4MN_TeamSwitch: { // Clear items ClearItems(); // add all teams as menu items // 2do: Icon C4Team *pTeam; int32_t i=0; bool fAddNewTeam=Game.Teams.IsAutoGenerateTeams(); for (;;) { pTeam = Game.Teams.GetTeamByIndex(i); if (pTeam) { // next regular team ++i; // do not add a new team if an empty team exists if (!pTeam->GetPlayerCount()) fAddNewTeam = false; } else if (fAddNewTeam) { // join new team fAddNewTeam = false; } else { // all teams done break; } // create team symbol: Icon spec if specified; otherwise flag for empty and crew for nonempty team fctSymbol.Create(C4SymbolSize,C4SymbolSize); const char *szIconSpec = pTeam ? pTeam->GetIconSpec() : NULL; bool fHasIcon = false; if (szIconSpec && *szIconSpec) { fHasIcon = Game.DrawTextSpecImage(fctSymbol, szIconSpec, NULL, pTeam->GetColor()); } if (!fHasIcon) { if (pTeam && pTeam->GetPlayerCount()) ::GraphicsResource.fctCrewClr.DrawClr(fctSymbol, true, pTeam->GetColor()); else C4GUI::Icon::GetIconFacet(C4GUI::Ico_Team).Draw(fctSymbol, true); } StdStrBuf sTeamName; if (pTeam) { sTeamName.Take(pTeam->GetNameWithParticipants()); } else sTeamName.Ref(LoadResStr("IDS_PRC_NEWTEAM")); const char *szOperation = (Identification == C4MN_TeamSwitch) ? "TeamSwitch" : "TeamSel"; Add(sTeamName.getData(), fctSymbol,FormatString("%s:%d", szOperation, pTeam ? pTeam->GetID() : TEAMID_New).getData(), FormatString(LoadResStr("IDS_MSG_JOINTEAM"), sTeamName.getData()).getData()); fctSymbol.Default(); } break; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4MN_Observer: // observer menu { // Clear items ClearItems(); // Check validity C4Viewport *pVP = ::Viewports.GetViewport(NO_OWNER); if (!pVP) return false; int32_t iInitialSelection = 0; // Add free view AddRefSym(LoadResStr("IDS_MSG_FREEVIEW"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Star), "Observe:Free", LoadResStr("IDS_MSG_FREELYSCROLLAROUNDTHEMAP")); // Add players C4Player *pPlr; int32_t iIndex; for (iIndex=0; (pPlr = ::Players.GetByIndex(iIndex)); iIndex++) { // Ignore invisible if (!pPlr->IsInvisible()) { // Symbol fctSymbol.Create(C4SymbolSize,C4SymbolSize); ::GraphicsResource.fctPlayerClr.DrawClr(fctSymbol, true, pPlr->ColorDw); // Message StdStrBuf sMsg; DWORD dwClr = pPlr->ColorDw; sMsg.Format("%s", (unsigned int)C4GUI::MakeColorReadableOnBlack(dwClr), pPlr->GetName()); // Command StdStrBuf sCommand; sCommand.Format("Observe:%d", (int)pPlr->Number); // Info caption StdStrBuf sInfo; sInfo.Format(LoadResStr("IDS_TEXT_FOLLOWVIEWOFPLAYER"), pPlr->GetName()); // Add item Add(sMsg.getData(),fctSymbol,sCommand.getData(),sInfo.getData()); fctSymbol.Default(); // check if this is the currently selected player if (pVP->GetPlayer() == pPlr->Number) iInitialSelection = GetItemCount()-1; } // Initial selection on followed player if (fWasEmpty) SetSelection(iInitialSelection, false, true); } } break; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - default: // No internal refill needed return true; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } // Successfull internal refill rfRefilled = true; return true; } void C4MainMenu::OnSelectionChanged(int32_t iNewSelection) { // immediate player highlight in observer menu if (Identification == C4MN_Observer) { C4MenuItem *pItem = GetSelectedItem(); if (pItem) { if (SEqual2(pItem->GetCommand(), "Observe:")) MenuCommand(pItem->GetCommand(), false); } } } void C4MainMenu::OnUserSelectItem(int32_t Player, int32_t iIndex) { // direct selection for non-sync-menus SetSelection(iIndex, true, true); } void C4MainMenu::OnUserEnter(int32_t Player, int32_t iIndex) { // direct menu control // but ensure selection is Okay before SetSelection(iIndex, true, false); Enter(); } void C4MainMenu::OnUserClose() { // just close TryClose(false, true); } bool C4MainMenu::ActivateGoals(int32_t iPlayer, bool fDoActivate) { C4FacetSurface fctSymbol; C4Facet fctGF; // goal fulfilled facet if (fDoActivate) { // Menu symbol/init InitRefSym(GfxR->fctMenu.GetPhase(4),LoadResStr("IDS_MENU_CPGOALS"),iPlayer); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(false); fctGF.Set(NULL, C4SymbolSize-::GraphicsResource.fctCaptain.Wdt-2, 2, ::GraphicsResource.fctCaptain.Wdt, ::GraphicsResource.fctCaptain.Hgt); } // determine if the goals are fulfilled - do the calls even if the menu is not to be opened to ensure synchronization C4IDList GoalList, FulfilledGoalList; C4RoundResults::EvaluateGoals(GoalList, FulfilledGoalList, iPlayer); // Add Items if (fDoActivate) { int32_t iNumGoals = GoalList.GetNumberOfIDs(), cnt; C4ID idGoal; C4Def *pDef; for (int32_t i=0; iGetName(), pDef->GetDesc() pDef->Draw(fctSymbol); if (FulfilledGoalList.GetIDCount(idGoal)) { fctGF.Surface=fctSymbol.Surface; ::GraphicsResource.fctCaptain.Draw(fctGF); } StdStrBuf Command; Command.Format("Player:Goal:%s", idGoal.ToString()); Add(pDef->GetName(),fctSymbol,Command.getData(),""); } // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); } // Done return true; } bool C4MainMenu::ActivateRules(int32_t iPlayer) { // Menu symbol/init char Command[256]; C4FacetSurface fctSymbol; InitRefSym(GfxR->fctMenu.GetPhase(5),LoadResStr("IDS_MENU_CPRULES"),iPlayer); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(false); // Items int32_t cnt; C4ID idGoal; C4Def *pDef; for (cnt=0; (idGoal=::Objects.GetListID(C4D_Rule,cnt)); cnt++) if ((pDef=C4Id2Def(idGoal))) { fctSymbol.Create(C4SymbolSize,C4SymbolSize); pDef->Draw(fctSymbol); sprintf(Command, "Player:Rule:%s", idGoal.ToString()); Add(pDef->GetName(),fctSymbol,Command,""); } // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); // Done return true; } bool LooksLikeInteger(const char *szInt) { // safety if (!szInt) return false; // check sign if (*szInt == '+' || *szInt == '-') ++szInt; // check int32_t length if (!*szInt) return false; // must contain only digits now char c; while ((c = *(szInt++))) if (!Inside(c, '0', '9')) return false; // it's an int32_t return true; } bool C4MainMenu::ActivateSavegame(int32_t iPlayer) { // Check if saving is possible if (!Game.CanQuickSave()) return false; // Menu symbol/init char DirPath[_MAX_PATH+1]; char ScenName[_MAX_PATH+1]; *ScenName=0; InitRefSym(GfxR->fctMenu.GetPhase(0), LoadResStr("IDS_MENU_CPSAVEGAME"), iPlayer); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); // target file name mask // get folder & filename to store in // some magic is needed to ensure savegames are stored properly into their folders SCopy(GetFilename(Game.ScenarioFilename), DirPath); if (DirPath[strlen(DirPath) - 1] == '\\') DirPath[strlen(DirPath) - 1] = 0; RemoveExtension(DirPath); if (LooksLikeInteger(DirPath)) { // ScenTitle.ocf\%d.ocs-names (old-style savegames) // get owning folder if (Game.pParentGroup) { // owning folder determines filename SCopy(GetFilenameOnly(Game.pParentGroup->GetName()), ScenName); } else { // no owning folder known: too bad // make a vague guess based on the scenario title SCopy(GetFilenameOnly(Game.ScenarioFilename), ScenName); } } else { // DirPath is a valid filename for now... SCopy(DirPath, ScenName); // but remove trailing numbers to adjust new-style savegames char *pScenNameEnd = ScenName+SLen(ScenName); while (Inside(*--pScenNameEnd, '0', '9')) if (pScenNameEnd == ScenName) { // should not happen: digit-only-filenames should have been caught earlier SCopy("dbg_error!", ScenName); pScenNameEnd = ScenName+SLen(ScenName)-1; } pScenNameEnd[1]=0; } // New Style 2007: // * scenarios are saved into ScenName.ocf/ScenName123.ocs to keep umlauts out of filenames // * language titles are stored in folders as title component StdStrBuf strFilename, strTitle; strFilename.Format("%s.ocf%c%s%%d.ocs", ScenName, DirectorySeparator, ScenName); strTitle = Game.ScenarioTitle; // Create menu items StdStrBuf strFilenameIndexed, strCommand, strCaption, strSavePath; for (int32_t i = 1; i <= 10; i++) { // Index filename strFilenameIndexed.Format(strFilename.getData(), i); // Compose commmand strCommand.Format("Save:Game:%s:%s", strFilenameIndexed.getData(), strTitle.getData()); // Notice: the language title might contain ':' and thus confuse the segment list - but C4Menu::MenuCommand will try to handle this... // Check free slot strSavePath.Format("%s%c%s", Config.AtUserDataPath(C4CFN_Savegames), DirectorySeparator, strFilenameIndexed.getData()); bool fFree = !C4Group_IsGroup(strSavePath.getData()); // Item caption strCaption = LoadResStr("IDS_MENU_CPSAVEGAME"); // add menu item AddRefSym(strCaption.getData(), GfxR->fctMenu.GetPhase(i - 1, fFree ? 2 : 1), strCommand.getData(), LoadResStr("IDS_MENU_CPSAVEGAMEINFO")); } // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::ActivateHost(int32_t iPlayer) { // Menu symbol/init InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_Disconnect), LoadResStr("IDS_MENU_DISCONNECTCLIENT"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); // Clients for (C4Network2Client *pClient=::Network.Clients.GetNextClient(NULL); pClient; pClient=::Network.Clients.GetNextClient(pClient)) { bool fHost = (pClient->getID() == 0); StdStrBuf strText, strCommand; strText.Format("%s (%s)", pClient->getName(), pClient->getCore().getNick()); strCommand.Format("Host:Kick:%d", pClient->getID()); C4GUI::Icons iIcon = fHost ? C4GUI::Ico_Host : (pClient->isActivated() ? C4GUI::Ico_Client : C4GUI::Ico_ObserverClient); AddRefSym(strText.getData(), C4GUI::Icon::GetIconFacet(iIcon), strCommand.getData()); } // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::ActivateClient(int32_t iPlayer) { InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_Disconnect), LoadResStr("IDS_MENU_DISCONNECTFROMSERVER"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); AddRefSym(LoadResStr("IDS_BTN_YES"), GfxR->fctOKCancel.GetPhase(3,0), "Part"); AddRefSym(LoadResStr("IDS_BTN_NO"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Close), ""); SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::ActivateSurrender(int32_t iPlayer) { InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_Surrender), LoadResStr("IDS_MENU_SURRENDER"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); AddRefSym(LoadResStr("IDS_BTN_YES"), GfxR->fctOKCancel.GetPhase(3), "Surrender"); AddRefSym(LoadResStr("IDS_BTN_NO"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Close), ""); SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::ActivateOptions(int32_t iPlayer, int32_t selection) { // Menu symbol/init InitRefSym(GfxR->fctOptions.GetPhase(0), LoadResStr("IDS_MNU_OPTIONS"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); AddRefSym(LoadResStr("IDS_DLG_SOUND"), GfxR->fctOptions.GetPhase(17 + Config.Sound.RXSound),"Options:Sound"); AddRefSym(LoadResStr("IDS_MNU_MUSIC"), GfxR->fctOptions.GetPhase(1 + Config.Sound.RXMusic),"Options:Music"); AddRefSym(LoadResStr("IDS_MENU_DISPLAY"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_View), "ActivateMenu:Display"); // Restore selection SetSelection(selection, false, true); // Go back to main menu on close SetCloseCommand("ActivateMenu:Main"); // Done return true; } bool C4MainMenu::ActivateDisplay(int32_t iPlayer, int32_t selection) { // Menu symbol/init InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_View), LoadResStr("IDS_MENU_DISPLAY"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); // Crew player names AddRefSym(LoadResStr("IDS_MNU_PLAYERNAMES"), GfxR->fctOptions.GetPhase(7 + Config.Graphics.ShowCrewNames), "Display:PlayerNames", LoadResStr("IDS_MENU_PLAYERNAMES_DESC")); // Crew clonk names AddRefSym(LoadResStr("IDS_MNU_CLONKNAMES"), GfxR->fctOptions.GetPhase(9 + Config.Graphics.ShowCrewCNames), "Display:ClonkNames", LoadResStr("IDS_MENU_CLONKNAMES_DESC")); // Upper Board if (!Application.isEditor) { AddRefSym(LoadResStr("IDS_MNU_UPPERBOARD"),GfxR->fctOptions.GetPhase(3 + Config.Graphics.UpperBoard),"Display:UpperBoard"); } // FPS if (!Application.isEditor) AddRefSym(LoadResStr("IDS_MNU_FPS"), GfxR->fctOptions.GetPhase(5 + Config.General.FPS), "Display:FPS"); // Clock if (!Application.isEditor) AddRefSym(LoadResStr("IDS_MNU_CLOCK"), GfxR->fctOptions.GetPhase(15 + Config.Graphics.ShowClock), "Display:Clock"); // Restore selection SetSelection(selection, false, true); // Go back to options menu on close SetCloseCommand("ActivateMenu:Options"); // Done return true; } bool C4MainMenu::ActivateMain(int32_t iPlayer) { // Determine player C4Player *pPlr = ::Players.Get(iPlayer); // Menu symbol/init InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_Player), LoadResStr(pPlr ? "IDS_MENU_CPMAIN" : "IDS_MENU_OBSERVER"), iPlayer, 0, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); // Goals+Rules (player menu only) // Goal menu can't be shown because of script callbacks // Rule menu could be shown, but rule activation would issue script callbacks and trigger client activation // Showing rules but not showing goals would be strange anyway if (pPlr) { // Goals AddRefSym(LoadResStr("IDS_MENU_CPGOALS"),GfxR->fctMenu.GetPhase(4),"ActivateMenu:Goals",LoadResStr("IDS_MENU_CPGOALSINFO")); // Rules AddRefSym(LoadResStr("IDS_MENU_CPRULES"),GfxR->fctMenu.GetPhase(5),"ActivateMenu:Rules",LoadResStr("IDS_MENU_CPRULESINFO")); } // Observer menu in free viewport if (!pPlr) { AddRefSym(LoadResStr("IDS_TEXT_VIEW"),C4GUI::Icon::GetIconFacet(C4GUI::Ico_View),"ActivateMenu:Observer",LoadResStr("IDS_TEXT_DETERMINEPLAYERVIEWTOFOLL")); } // Hostility (player menu only) if (pPlr && (::Players.GetCount() > 1)) { GfxR->fctFlagClr.Surface->SetClr(0xff0000); AddRefSym(LoadResStr("IDS_MENU_CPATTACK"),C4GUI::Icon::GetIconFacet(C4GUI::Ico_MeleeLeague),"ActivateMenu:Hostility",LoadResStr("IDS_MENU_CPATTACKINFO")); } // Team change if (pPlr && Game.Teams.IsTeamSwitchAllowed()) { C4Facet fctTeams; fctTeams = C4GUI::Icon::GetIconFacet(C4GUI::Ico_Team); AddRefSym(LoadResStr("IDS_MSG_SELTEAM"),fctTeams,"ActivateMenu:TeamSel",LoadResStr("IDS_MSG_ALLOWSYOUTOJOINADIFFERENT")); } // Player join if ((::Players.GetCount() < Game.Parameters.MaxPlayers) && !Game.Parameters.isLeague()) { AddRefSym(LoadResStr("IDS_MENU_CPNEWPLAYER"),GfxR->fctPlayerClr.GetPhase(),"ActivateMenu:NewPlayer",LoadResStr("IDS_MENU_CPNEWPLAYERINFO")); } // Save game (player menu only - should we allow saving games with no players in it?) if (pPlr && (!::Network.isEnabled() || ::Network.isHost())) { AddRefSym(LoadResStr("IDS_MENU_CPSAVEGAME"),GfxR->fctMenu.GetPhase(0),"ActivateMenu:Save:Game",LoadResStr("IDS_MENU_CPSAVEGAMEINFO")); } // Options AddRefSym(LoadResStr("IDS_MNU_OPTIONS"), GfxR->fctOptions.GetPhase(0), "ActivateMenu:Options", LoadResStr("IDS_MNU_OPTIONSINFO")); // Disconnect if (::Network.isEnabled()) { // Host if (::Network.isHost() && Game.Clients.getClient(NULL)) AddRefSym(LoadResStr("IDS_MENU_DISCONNECT"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Disconnect), "ActivateMenu:Host", LoadResStr("IDS_TEXT_KICKCERTAINCLIENTSFROMTHE")); // Client if (!::Network.isHost()) AddRefSym(LoadResStr("IDS_MENU_DISCONNECT"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Disconnect), "ActivateMenu:Client", LoadResStr("IDS_TEXT_DISCONNECTTHEGAMEFROMTHES")); } // Surrender (player menu only) if (pPlr) AddRefSym(LoadResStr("IDS_MENU_CPSURRENDER"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Surrender), "ActivateMenu:Surrender", LoadResStr("IDS_MENU_CPSURRENDERINFO")); // Abort if (!Application.isEditor) AddRefSym(LoadResStr("IDS_MENU_ABORT"), C4GUI::Icon::GetIconFacet(C4GUI::Ico_Exit), "Abort", LoadResStr("IDS_MENU_ABORT_DESC")); // No empty menus if (GetItemCount()==0) Close(false); // Done return true; } bool C4MainMenu::ActivateHostility(int32_t iPlayer) { // Init menu InitRefSym(GfxR->fctMenu.GetPhase(7), LoadResStr("IDS_MENU_CPATTACK"), iPlayer, C4MN_Hostility); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); SetPermanent(true); Refill(); // Go back to options menu on close SetCloseCommand("ActivateMenu:Main"); return true; } bool C4MainMenu::MenuCommand(const char *szCommand, bool fIsCloseCommand) { // Determine player C4Player *pPlr = ::Players.Get(Player); // Activate if (SEqual2(szCommand,"ActivateMenu:")) { if (C4GameOverDlg::IsShown()) return false; // no new menus during game over dlg if (SEqual(szCommand+13,"Main")) return ActivateMain(Player); if (SEqual(szCommand+13,"Hostility")) return ActivateHostility(Player); if (SEqual(szCommand+13,"NewPlayer")) return ActivateNewPlayer(Player); if (SEqual(szCommand+13,"Goals")) { ::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::ActivateGoalMenu(::Players.Get(Player)), CDT_Queue); return true; } if (SEqual(szCommand+13,"Rules")) return ActivateRules(Player); if (SEqual(szCommand+13,"Host")) return ActivateHost(Player); if (SEqual(szCommand+13,"Client")) return ActivateClient(Player); if (SEqual(szCommand+13,"Options")) return ActivateOptions(Player); if (SEqual(szCommand+13,"Display")) return ActivateDisplay(Player); if (SEqual(szCommand+13,"Save:Game")) return ActivateSavegame(Player); if (SEqual(szCommand+13,"TeamSel")) return pPlr ? pPlr->ActivateMenuTeamSelection(true) : false; if (SEqual(szCommand+13,"Surrender")) return ActivateSurrender(Player); if (SEqual(szCommand+13,"Observer")) return ActivateObserver(); } // JoinPlayer if (SEqual2(szCommand,"JoinPlayer:")) { // not in league or replay mode if (Game.Parameters.isLeague() || Game.C4S.Head.Replay) return false; // join player // 2do: not for observers and such? Players.JoinNew(szCommand+11); return true; } // SetHostility if (SEqual2(szCommand,"SetHostility:")) { // only if allowed if (!Game.Teams.IsHostilityChangeAllowed()) return false; int32_t iOpponent; sscanf(szCommand+13,"%i",&iOpponent); C4Player *pOpponent = ::Players.Get(iOpponent); if (!pOpponent || pOpponent->GetType() != C4PT_User) return false; ::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::SetHostility(::Players.Get(Player), pOpponent, !::Players.HostilityDeclared(Player, pOpponent->Number)), CDT_Queue); return true; } // Abort if (SEqual2(szCommand,"Abort")) { FullScreen.ShowAbortDlg(); return true; } // Surrender if (SEqual2(szCommand,"Surrender")) { ::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::Surrender(::Players.Get(Player)), CDT_Queue); return true; } // Save game if (SEqual2(szCommand, "Save:Game:")) { char strFilename[_MAX_PATH + 1]; SCopySegment(szCommand, 2, strFilename, ':', _MAX_PATH); char strTitle[_MAX_PATH + 1]; SCopy(szCommand + SCharPos(':', szCommand, 2) + 1, strTitle, _MAX_PATH); Game.QuickSave(strFilename, strTitle); ActivateSavegame(Player); return true; } // Kick if (SEqual2(szCommand,"Host:Kick:")) { int iClientID = atoi(szCommand+10); if (iClientID && ::Network.isEnabled()) { if (Game.Parameters.isLeague() && ::Players.GetAtClient(iClientID)) ::Network.Vote(VT_Kick, true, iClientID); else { C4Client *pClient = Game.Clients.getClientByID(iClientID); if (pClient) Game.Clients.CtrlRemove(pClient, LoadResStr("IDS_MSG_KICKBYMENU")); Close(true); } } return true; } // Part if (SEqual2(szCommand,"Part")) { if (::Network.isEnabled()) { if (Game.Parameters.isLeague() && ::Players.GetLocalByIndex(0)) ::Network.Vote(VT_Kick, true, ::Control.ClientID()); else { Game.RoundResults.EvaluateNetwork(C4RoundResults::NR_NetError, LoadResStr("IDS_ERR_GAMELEFTVIAPLAYERMENU")); ::Network.Clear(); } } return true; } // Options if (SEqual2(szCommand,"Options:")) { // Music if (SEqual(szCommand + 8, "Music")) { Application.MusicSystem.ToggleOnOff(); } // Sound if (SEqual(szCommand + 8, "Sound")) { if (Config.Sound.RXSound) { Application.SoundSystem.Clear(); Config.Sound.RXSound = false; } else { Config.Sound.RXSound = true; if (!Application.SoundSystem.Init()) { Log(LoadResStr("IDS_PRC_NOSND")); } } } // Reopen with updated options ActivateOptions(Player, GetSelection()); return true; } // Display if (SEqual2(szCommand,"Display:")) { // Upper board if (SEqual(szCommand + 8, "UpperBoard")) { Config.Graphics.UpperBoard = !Config.Graphics.UpperBoard; ::Viewports.RecalculateViewports(); } // FPS if (SEqual(szCommand + 8, "FPS")) Config.General.FPS = !Config.General.FPS; // Player names if (SEqual(szCommand + 8, "PlayerNames")) Config.Graphics.ShowCrewNames = !Config.Graphics.ShowCrewNames; // Clonk names if (SEqual(szCommand + 8, "ClonkNames")) Config.Graphics.ShowCrewCNames = !Config.Graphics.ShowCrewCNames; // Clock if (SEqual(szCommand + 8, "Clock")) Config.Graphics.ShowClock = !Config.Graphics.ShowClock; // Reopen with updated options ActivateDisplay(Player, GetSelection()); return true; } // Goal info if (SEqual2(szCommand,"Player:Goal:") || SEqual2(szCommand,"Player:Rule:")) { if (!ValidPlr(Player)) return false; // observers may not look at goal/rule info, because it requires queue activation Close(true); C4Object *pObj; C4ID idItem(szCommand+12); C4Def * pDef = C4Id2Def(idItem); if (pDef && (pObj = ::Objects.Find(pDef))) ::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::ActivateGoal(::Players.Get(Player), pObj), CDT_Queue); else return false; return true; } // Team selection if (SEqual2(szCommand, "TeamSel:")) { Close(true); int32_t idTeam = atoi(szCommand+8); // OK, join this team if (pPlr) pPlr->DoTeamSelection(idTeam); return true; } // Team switch if (SEqual2(szCommand, "TeamSwitch:")) { Close(true); int32_t idTeam = atoi(szCommand+11); // check if it's still allowed if (!Game.Teams.IsTeamSwitchAllowed()) return false; // OK, join this team ::Control.DoInput(CID_PlrAction, C4ControlPlayerAction::SetTeam(::Players.Get(Player), idTeam), CDT_Queue); return true; } // Observe if (SEqual2(szCommand, "Observe:")) { const char *szObserverTarget = szCommand+8; C4Viewport *pVP = ::Viewports.GetViewport(NO_OWNER); if (pVP) // viewport may have closed meanwhile { if (SEqual(szObserverTarget, "Free")) { // free view pVP->Init(NO_OWNER, true); return true; } else { // view following player int32_t iPlr = atoi(szObserverTarget); if (ValidPlr(iPlr)) { pVP->Init(iPlr, true); return true; } } } return false; } // No valid command return false; } bool C4MainMenu::ActivateCommand(int32_t iPlayer, const char *szCommand) { // init menu for player and activate with command Player = iPlayer; return MenuCommand(szCommand, false); } bool C4MainMenu::ActivateObserver() { // Safety: Viewport lost? if (!::Viewports.GetViewport(NO_OWNER)) return false; // Menu symbol/init InitRefSym(C4GUI::Icon::GetIconFacet(C4GUI::Ico_View), LoadResStr("IDS_TEXT_VIEW"), NO_OWNER, C4MN_Observer, C4MN_Style_Context); SetAlignment(C4MN_Align_Left | C4MN_Align_Bottom); // Players added in Refill Refill(); // Go back to main menu on close SetCloseCommand("ActivateMenu:Main"); return true; }