/** * @brief Pops a window from the window stack * @param[in] all If true pop all windows from stack * @sa UI_PopWindow_f */ void UI_PopWindow (bool all) { uiNode_t *oldfirst = ui_global.windowStack[0]; if (all) { UI_CloseAllWindow(); } else { uiNode_t *mainWindow = ui_global.windowStack[ui_global.windowStackPos - 1]; if (!ui_global.windowStackPos) return; if (WINDOWEXTRADATA(mainWindow).parent) mainWindow = WINDOWEXTRADATA(mainWindow).parent; UI_CloseWindowByRef(mainWindow); if (ui_global.windowStackPos == 0) { /* ui_sys_main contains the window that is the very first window and should be * pushed back onto the stack (otherwise there would be no window at all * right now) */ if (Q_streq(oldfirst->name, ui_sys_main->string)) { if (ui_sys_active->string[0] != '\0') UI_PushWindow(ui_sys_active->string); if (!ui_global.windowStackPos) UI_PushWindow(ui_sys_main->string); } else { if (ui_sys_main->string[0] != '\0') UI_PushWindow(ui_sys_main->string); if (!ui_global.windowStackPos) UI_PushWindow(ui_sys_active->string); } } } /* change from e.g. console mode to game input mode (fetch input) */ Key_SetDest(key_game); }
/** * @brief Console function to push a child window onto the window stack * @sa UI_PushWindow */ static void UI_PushChildWindow_f (void) { if (Cmd_Argc() > 1) UI_PushWindow(Cmd_Argv(1), Cmd_Argv(2)); else Com_Printf("Usage: %s <name> <parentname>\n", Cmd_Argv(0)); }
/** * @brief Popup on geoscape * @note Only use static strings here - or use popupText if you really have to * build the string */ void UI_Popup (const char *title, const char *text) { Cvar_Set("ui_sys_popup_title", title); UI_RegisterText(TEXT_POPUP_INFO, text); if (!UI_IsWindowOnStack(POPUP_WINDOW_NAME)) UI_PushWindow(POPUP_WINDOW_NAME, NULL, NULL); }
/** * @brief Console function to push a dropdown window at a position. It work like UI_PushWindow but move the window at the right position * @sa UI_PushWindow * @note The usage is "ui_push_dropdown sourcenode pointposition destinationnode pointposition" * sourcenode must be a node into the window we want to push, * we will move the window to have sourcenode over destinationnode * pointposition select for each node a position (like a corner). */ static void UI_PushDropDownWindow_f (void) { vec2_t source; vec2_t destination; uiNode_t *node; int direction; size_t writtenBytes; int result; if (Cmd_Argc() != 4 && Cmd_Argc() != 5) { Com_Printf("Usage: %s <source-anchor> <point-in-source-anchor> <dest-anchor> <point-in-dest-anchor>\n", Cmd_Argv(0)); return; } /* get the source anchor */ node = UI_GetNodeByPath(Cmd_Argv(1)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1)); return; } result = Com_ParseValue(&direction, Cmd_Argv(2), V_INT, 0, sizeof(direction), &writtenBytes); if (result != RESULT_OK) { Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(2)); return; } UI_NodeGetPoint(node, source, direction); UI_NodeRelativeToAbsolutePoint(node, source); /* get the destination anchor */ if (Q_streq(Cmd_Argv(4), "mouse")) { destination[0] = mousePosX; destination[1] = mousePosY; } else { /* get the source anchor */ node = UI_GetNodeByPath(Cmd_Argv(3)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(3)); return; } result = Com_ParseValue(&direction, Cmd_Argv(4), V_INT, 0, sizeof(direction), &writtenBytes); if (result != RESULT_OK) { Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(4)); return; } UI_NodeGetPoint(node, destination, direction); UI_NodeRelativeToAbsolutePoint(node, destination); } /* update the window and push it */ node = UI_GetNodeByPath(Cmd_Argv(1)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1)); return; } node = node->root; node->box.pos[0] += destination[0] - source[0]; node->box.pos[1] += destination[1] - source[1]; UI_PushWindow(node->name); }
/** * @brief Pushes the webauth window if the password is not yet set * @return @c true if the user is authenticated, @c false otherwise */ bool WEB_CheckAuth (void) { if (Q_strnull(web_password->string)) { UI_PushWindow("webauth"); return false; } return true; }
/** * @brief Check cvars for some initial values that should/must be set */ static void CL_CheckCvars_f (void) { for (cvarList_t* c = checkcvar; c->name != nullptr; c++) { cvar_t* var = Cvar_Get(c->name); if (var->string[0] == '\0') { Com_Printf("%s has no value\n", var->name); UI_PushWindow("checkcvars"); break; } } }
/** * @brief Checks whether there is a quicksave file and opens the quickload menu if there is one * @note This does not work while we are in the battlescape */ static void SAV_GameQuickLoadInit_f (void) { qFILE f; if (cgi->CL_OnBattlescape()) { return; } FS_OpenFile(va("save/slotquick.%s", SAVEGAME_EXTENSION), &f, FILE_READ); if (f.f || f.z) { UI_PushWindow("quickload", NULL, NULL); FS_CloseFile(&f); } }
/** * @brief Open research menu. */ static void AC_ResearchAlien_f (void) { const technology_t *tech; /* Can be called from everywhere. */ if (!aliencontCurrent) return; tech = aliencontCurrent->tech; if (!tech) Com_Error(ERR_DROP, "aliencontCurrent without tech pointer"); if (!RS_IsResearched_ptr(tech)) UI_PushWindow("research", NULL, NULL); }
/** * @brief Generates a popup that contains up to 3 buttons. * @param[in] title Title of the popup. * @param[in] text Text to display in the popup (use popupText if text is NULL). * @param[in] clickAction1 Action to perform when one clicked on the first button. * @param[in] clickText1 String that will be written in first button. * @param[in] tooltip1 Tooltip of first button. * @param[in] clickAction2 Action to perform when one clicked on the second button. * @param[in] clickText2 String that will be written in second button. * @param[in] tooltip2 Tooltip of second button. * @param[in] clickAction3 Action to perform when one clicked on the third button. * @param[in] clickText3 String that will be written in third button. * @param[in] tooltip3 Tooltip of third button. * @note clickAction AND clickText must be NULL if button should be invisible. */ void UI_PopupButton (const char *title, const char *text, const char *clickAction1, const char *clickText1, const char *tooltip1, const char *clickAction2, const char *clickText2, const char *tooltip2, const char *clickAction3, const char *clickText3, const char *tooltip3) { uiNode_t* window; Cvar_Set("ui_sys_popup_title", title); if (text) UI_RegisterText(TEXT_POPUP_INFO, text); else UI_RegisterText(TEXT_POPUP_INFO, popupText); window = UI_GetWindow(POPUPBUTTON_WINDOW_NAME); if (!window) Com_Error(ERR_FATAL, "Could not get \""POPUPBUTTON_WINDOW_NAME"\" window"); Cvar_Set("ui_sys_popup_button_text1", clickText1); Cvar_Set("ui_sys_popup_button_tooltip1", tooltip1); if (!clickAction1 && !clickText1) { UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME), clickAction1 ? clickAction1 : popupAction1); } Cvar_Set("ui_sys_popup_button_text2", clickText2); Cvar_Set("ui_sys_popup_button_tooltip2", tooltip2); if (!clickAction2 && !clickText2) { UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME), clickAction2 ? clickAction2 : popupAction2); } Cvar_Set("ui_sys_popup_button_text3", clickText3); Cvar_Set("ui_sys_popup_button_tooltip3", tooltip3); if (!clickAction3 && !clickText3) { UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME), clickAction3 ? clickAction3 : popupAction3); } if (!UI_IsWindowOnStack(window->name)) UI_PushWindow(window->name, NULL, NULL); }
/** * @brief Console function to push a window onto the window stack * @sa UI_PushWindow */ static void UI_PushWindow_f (void) { linkedList_t *params = NULL; int i; if (Cmd_Argc() == 0) { Com_Printf("Usage: %s <name> <params>\n", Cmd_Argv(0)); return; } for (i = 2; i < Cmd_Argc(); i++) { LIST_AddString(¶ms, Cmd_Argv(i)); } UI_PushWindow(Cmd_Argv(1), NULL, params); LIST_Delete(¶ms); }
/** * @brief Reloads the ui scripts and reinitializes the ui */ static void UI_Restart_f (void) { typedef std::vector<std::string> Names; Names names; for (int i = 0; i < ui_global.windowStackPos; i++) { names.push_back(std::string(ui_global.windowStack[i]->name)); } UI_Shutdown(); CLMN_Shutdown(); R_FontShutdown(); UI_Init(); R_FontInit(); Com_Printf("%i ui script files\n", FS_BuildFileList("ufos/ui/*.ufo")); FS_NextScriptHeader(nullptr, nullptr, nullptr); const char* type, *name, *text; text = nullptr; while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != nullptr) { if (Q_streq(type, "font")) UI_ParseFont(name, &text); else if (Q_streq(type, "menu_model")) UI_ParseUIModel(name, &text); else if (Q_streq(type, "sprite")) UI_ParseSprite(name, &text); } UI_Reinit(); FS_NextScriptHeader(nullptr, nullptr, nullptr); text = nullptr; while ((type = FS_NextScriptHeader("ufos/ui/*.ufo", &name, &text)) != nullptr) { if (Q_streq(type, "window")) UI_ParseWindow(type, name, &text); else if (Q_streq(type, "component")) UI_ParseComponent(type, name, &text); else if (Q_streq(type, "menu_model")) UI_ParseUIModel(name, &text); else if (Q_streq(type, "sprite")) UI_ParseSprite(name, &text); else if (Q_streq(type, "lua")) UI_ParseAndLoadLuaScript(name, &text); } CLMN_Init(); for (Names::iterator i = names.begin(); i != names.end(); ++i) { UI_PushWindow(i->c_str()); } }
/** * @brief Init the stack to start with a window, and have an alternative window with ESC * @param[in] activeWindow The first active window of the stack, else NULL * @param[in] mainWindow The alternative window, else NULL if nothing * @param[in] popAll If true, clean up the stack first * @param[in] pushActive If true, push the active window into the stack * @todo remove Cvar_Set we have direct access to the cvar * @todo check why activeWindow can be NULL. It should never be NULL: a stack must not be empty * @todo We should only call it a very few time. When we switch from/to this different par of the game: main-option-interface / geoscape-and-base / battlescape * @todo Update the code: popAll should be every time true * @todo Update the code: pushActive should be every time true * @todo Illustration about when/how we should use UI_InitStack http://ufoai.org/wiki/index.php/Image:UI_InitStack.jpg */ void UI_InitStack (const char* activeWindow, const char* mainWindow, bool popAll, bool pushActive) { UI_FinishInit(); if (popAll) UI_PopWindow(true); if (activeWindow) { Cvar_Set("ui_sys_active", activeWindow); /* prevent calls before UI script initialization */ if (ui_global.numWindows != 0) { if (pushActive) UI_PushWindow(activeWindow); } } if (mainWindow) Cvar_Set("ui_sys_main", mainWindow); }
/** * @brief Generates a popup that contains a list of selectable choices. * @param[in] title Title of the popup. * @param[in] headline First line of text written in the popup. * @param[in] entries List of the selectables choices. * @param[in] clickAction Action to perform when one clicked on the popup. */ uiNode_t *UI_PopupList (const char *title, const char *headline, linkedList_t* entries, const char *clickAction) { uiNode_t* window; uiNode_t* listNode; Cvar_Set("ui_sys_popup_title", title); UI_RegisterText(TEXT_POPUP_INFO, headline); /* make sure, that we are using the linked list */ UI_ResetData(TEXT_LIST); UI_RegisterLinkedListText(TEXT_LIST, entries); window = UI_GetWindow(POPUPLIST_WINDOW_NAME); if (!window) Com_Error(ERR_FATAL, "Could not get "POPUPLIST_WINDOW_NAME" window"); listNode = UI_GetNode(window, POPUPLIST_NODE_NAME); if (!listNode) Com_Error(ERR_FATAL, "Could not get "POPUPLIST_NODE_NAME" node in "POPUPLIST_WINDOW_NAME" window"); /* free previous actions */ if (listNode->onClick) { assert(listNode->onClick->d.terminal.d1.data); Mem_Free(listNode->onClick->d.terminal.d1.data); Mem_Free(listNode->onClick); listNode->onClick = NULL; } if (clickAction) { UI_PoolAllocAction(&listNode->onClick, EA_CMD, clickAction); } else { listNode->onClick = NULL; } if (!UI_IsWindowOnStack(window->name)) UI_PushWindow(window->name, NULL, NULL); return listNode; }
static void CL_BattlescapeRadarOpen_f (void) { UI_PushWindow("radarwindow"); }
/** * @brief Responses to broadcasts, etc * @sa CL_ReadPackets * @sa CL_Frame * @sa SVC_DirectConnect * @param[in,out] msg The client stream message buffer to read from */ static void CL_ConnectionlessPacket (dbuffer* msg) { char s[512]; NET_ReadStringLine(msg, s, sizeof(s)); Cmd_TokenizeString(s, false); const char* c = Cmd_Argv(0); Com_DPrintf(DEBUG_CLIENT, "server OOB: %s (%s)\n", c, Cmd_Args()); /* server connection */ if (Q_streq(c, CL_CMD_CLIENT_CONNECT)) { int i; for (i = 1; i < Cmd_Argc(); i++) { if (char const* const p = Q_strstart(Cmd_Argv(i), "dlserver=")) { Com_sprintf(cls.downloadReferer, sizeof(cls.downloadReferer), "ufo://%s", cls.servername); CL_SetHTTPServer(p); if (cls.downloadServer[0]) Com_Printf("HTTP downloading enabled, URL: %s\n", cls.downloadServer); } } if (cls.state == ca_connected) { Com_Printf("Dup connect received. Ignored.\n"); return; } dbuffer buf(5); NET_WriteByte(&buf, clc_stringcmd); NET_WriteString(&buf, NET_STATE_NEW "\n"); NET_WriteMsg(cls.netStream, buf); GAME_InitMissionBriefing(_("Loading")); return; } /* remote command from gui front end */ if (Q_streq(c, CL_CMD_COMMAND)) { if (!NET_StreamIsLoopback(cls.netStream)) { Com_Printf("Command packet from remote host. Ignored.\n"); return; } else { char str[512]; NET_ReadString(msg, str, sizeof(str)); Cbuf_AddText("%s\n", str); } return; } /* ping from server */ if (Q_streq(c, CL_CMD_PING)) { NET_OOB_Printf(cls.netStream, SV_CMD_ACK); return; } /* echo request from server */ if (Q_streq(c, CL_CMD_ECHO)) { NET_OOB_Printf(cls.netStream, "%s", Cmd_Argv(1)); return; } /* print */ if (Q_streq(c, SV_CMD_PRINT)) { NET_ReadString(msg, popupText, sizeof(popupText)); /* special reject messages needs proper handling */ if (strstr(popupText, REJ_PASSWORD_REQUIRED_OR_INCORRECT)) { UI_PushWindow("serverpassword"); if (Q_strvalid(Cvar_GetString("password"))) { Cvar_Set("password", ""); CL_Drop(); UI_Popup(_("Connection failure"), _("The password you specified was wrong.")); } else { CL_Drop(); UI_Popup(_("Connection failure"), _("This server requires a password.")); } } else if (strstr(popupText, REJ_SERVER_FULL)) { CL_Drop(); UI_Popup(_("Connection failure"), _("This server is full.")); } else if (strstr(popupText, REJ_BANNED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("You are banned on this server.")); } else if (strstr(popupText, REJ_GAME_ALREADY_STARTED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The game has already started.")); } else if (strstr(popupText, REJ_SERVER_VERSION_MISMATCH)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server is running a different version of the game.")); } else if (strstr(popupText, BAD_RCON_PASSWORD)) { Cvar_Set("rcon_password", ""); UI_Popup(_("Bad rcon password"), _("The rcon password you specified was wrong.")); } else if (strstr(popupText, REJ_CONNECTION_REFUSED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server refused the connection.")); } else if (Q_strvalid(popupText)) { UI_Popup(_("Notice"), _(popupText)); } return; } if (!GAME_HandleServerCommand(c, msg)) Com_Printf("Unknown command received \"%s\"\n", c); }
/** * @todo only call/register it when we are on the battlescape */ static void CL_HudRadarDown_f (void) { if (!CL_BattlescapeRunning()) return; UI_PushWindow("radarmenu", NULL, NULL); }
/** * @brief Start Base Attack. * @note Base attack mission -- Stage 2 */ void CP_BaseAttackStartMission (mission_t *mission) { base_t *base = mission->data.base; linkedList_t *hiredSoldiersInBase = NULL; employee_t *employee; assert(base); mission->stage = STAGE_BASE_ATTACK; CP_MissionDisableTimeLimit(mission); if (mission->ufo) { /* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/ CP_UFORemoveFromGeoscape(mission, qfalse); } /* we always need at least one command centre in the base - because the * phalanx soldiers have their starting positions here. * There should also always be an entrance - the aliens start there * but we don't need to check that as entrance can't be destroyed */ if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, B_COMMAND)) { /** @todo handle command centre properly */ Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no Command Center: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } base->baseStatus = BASE_UNDER_ATTACK; ccs.campaignStats.basesAttacked++; #if 0 /** @todo implement onattack: add it to basemanagement.ufo and implement functions */ if (base->onAttack[0] != '\0') /* execute next frame */ Cbuf_AddText(va("%s %i", base->onAttack, base->id)); #endif MAP_SelectMission(mission); mission->active = qtrue; ccs.mapAction = MA_BASEATTACK; Com_DPrintf(DEBUG_CLIENT, "Base attack: %s at %.0f:%.0f\n", mission->id, mission->pos[0], mission->pos[1]); /** @todo EMPL_ROBOT */ E_GetHiredEmployees(base, EMPL_SOLDIER, &hiredSoldiersInBase); /* Fill the fake aircraft */ OBJZERO(baseAttackFakeAircraft); baseAttackFakeAircraft.homebase = base; /* needed for transfer of alien corpses */ VectorCopy(base->pos, baseAttackFakeAircraft.pos); #if 0 /** @todo active this once more than 8 soldiers are working */ /* needed to spawn soldiers on map */ baseAttackFakeAircraft.maxTeamSize = LIST_Count(hiredSoldiersInBase); #else baseAttackFakeAircraft.maxTeamSize = MAX_ACTIVETEAM; #endif if (!hiredSoldiersInBase) { Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } LIST_Foreach(hiredSoldiersInBase, employee_t, employee) { if (E_IsAwayFromBase(employee)) continue; AIR_AddToAircraftTeam(&baseAttackFakeAircraft, employee); } if (AIR_GetTeamSize(&baseAttackFakeAircraft) == 0) { Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers at home: it can't defend itself. Destroy base.\n", base->name); CP_BaseAttackMissionDestroyBase(mission); return; } #if 0 /** @todo active this once more than 8 soldiers are working */ /* all soldiers in the base should get used */ baseAttackFakeAircraft.maxTeamSize = AIR_GetTeamSize(&baseAttackFakeAircraft); #endif LIST_Delete(&hiredSoldiersInBase); base->aircraftCurrent = &baseAttackFakeAircraft; MAP_SetMissionAircraft(&baseAttackFakeAircraft); /** @todo remove me - this is not needed because we are using the base->aircraftCurrent * pointer for resolving the aircraft - only CL_GameAutoGo needs this */ MAP_SetInterceptorAircraft(&baseAttackFakeAircraft); /* needed for updating soldier stats sa CL_UpdateCharacterStats*/ B_SetCurrentSelectedBase(base); /* needed for equipment menu */ Com_sprintf(popupText, sizeof(popupText), _("Base '%s' is under attack! What to do ?"), base->name); UI_RegisterText(TEXT_POPUP, popupText); CL_GameTimeStop(); UI_PushWindow("popup_baseattack", NULL, NULL); }