/** * @brief Resets the ui_global.sharedData pointers from a func node * @note You can give this function a parameter to only delete a specific data * @sa ui_sharedDataIDNames */ static void UI_ResetData_f (void) { if (Cmd_Argc() == 2) { const char* dataId = Cmd_Argv(1); const int id = UI_GetDataIDByName(dataId); if (id == -1) Com_Printf("%s: invalid data ID: %s\n", Cmd_Argv(0), dataId); else UI_ResetData(id); } else { for (int i = 0; i < UI_MAX_DATAID; i++) UI_ResetData(i); } }
void GAME_SK_Shutdown (void) { Cmd_RemoveCommand("sk_start"); Cmd_RemoveCommand("sk_nextequip"); Cmd_RemoveCommand("sk_prevequip"); Cmd_RemoveCommand("game_go"); UI_ResetData(OPTION_DROPSHIPS); UI_ResetData(OPTION_UFOS); SV_Shutdown("Quitting server.", qfalse); chrDisplayList.num = 0; }
void UI_RegisterLineStrip (int dataId, lineStrip_t *lineStrip) { UI_ResetData(dataId); ui_global.sharedData[dataId].type = UI_SHARED_LINESTRIP; ui_global.sharedData[dataId].data.lineStrip = lineStrip; ui_global.sharedData[dataId].versionId++; }
/** * @brief Sets aircraftCurrent and updates related cvars and menutexts. * @param[in] aircraft Pointer to given aircraft that should be selected in the menu. */ void AIR_AircraftSelect (aircraft_t* aircraft) { static char aircraftInfo[256]; base_t *base; int id; if (aircraft != NULL) base = aircraft->homebase; else base = NULL; if (!AIR_BaseHasAircraft(base)) { UI_ResetData(TEXT_AIRCRAFT_INFO); return; } assert(aircraft); assert(aircraft->homebase == base); CP_UpdateActorAircraftVar(aircraft, EMPL_SOLDIER); Cvar_SetValue("mn_equipsoldierstate", CL_EquipSoldierState(aircraft)); Cvar_Set("mn_aircraftstatus", AIR_AircraftStatusToName(aircraft)); Cvar_Set("mn_aircraftinbase", AIR_IsAircraftInBase(aircraft) ? "1" : "0"); Cvar_Set("mn_aircraftname", aircraft->name); if (!aircraft->tech) Com_Error(ERR_DROP, "No technology assigned to aircraft '%s'", aircraft->id); Cvar_Set("mn_aircraft_model", aircraft->tech->mdl); Cvar_Set("mn_aircraft_health", va("%3.0f" , aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (double)aircraft->damage * 100 / aircraft->stats[AIR_STATS_DAMAGE] : 0)); /* generate aircraft info text */ Com_sprintf(aircraftInfo, sizeof(aircraftInfo), _("Speed:\t%i km/h\n"), AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_SPEED], AIR_STATS_SPEED)); Q_strcat(aircraftInfo, va(_("Fuel:\t%i/%i\n"), AIR_AircraftMenuStatsValues(aircraft->fuel, AIR_STATS_FUELSIZE), AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_FUELSIZE], AIR_STATS_FUELSIZE)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Weapons:\t%i on %i\n"), AIR_GetSlotItems(AC_ITEM_WEAPON, aircraft), aircraft->maxWeapons), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Armour:\t%i on 1\n"), AIR_GetSlotItems(AC_ITEM_SHIELD, aircraft)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Electronics:\t%i on %i"), AIR_GetSlotItems(AC_ITEM_ELECTRONICS, aircraft), aircraft->maxElectronics), sizeof(aircraftInfo)); UI_RegisterText(TEXT_AIRCRAFT_INFO, aircraftInfo); /** @todo This shouldn't exists. UI should use the global idx as reference */ /* compute the ID and... */ id = 0; AIR_ForeachFromBase(aircraftInBase, base) { if (aircraft == aircraftInBase) break; id++; } base->aircraftCurrent = aircraft; Cvar_SetValue("mn_aircraft_id", id); /* ...update the GUI */ UI_ExecuteConfunc("aircraft_change %i", id); }
/** * @brief share a text with a data id * @note The UI code doesn't manage the text memory, it only save a pointer */ void UI_RegisterText (int dataId, const char *text) { UI_ResetData(dataId); if (!text) return; ui_global.sharedData[dataId].type = UI_SHARED_TEXT; ui_global.sharedData[dataId].data.text = text; ui_global.sharedData[dataId].versionId++; }
void UI_RegisterOption (int dataId, uiNode_t *option) { /** Hack to disable release option memory, if we only want to update the same option */ if (ui_global.sharedData[dataId].type == UI_SHARED_OPTION && ui_global.sharedData[dataId].data.option == option) { ui_global.sharedData[dataId].versionId++; return; } UI_ResetData(dataId); ui_global.sharedData[dataId].type = UI_SHARED_OPTION; ui_global.sharedData[dataId].data.option = option; ui_global.sharedData[dataId].versionId++; }
/** * @brief share a linked list of text with a data id * @note The UI code manage the linked list memory (linked list is freed by the UI code) */ void UI_RegisterLinkedListText (int dataId, linkedList_t *text) { /** @todo FIXME It is a hack to disable release memory, if we only want to update the same list */ if (ui_global.sharedData[dataId].type == UI_SHARED_LINKEDLISTTEXT && ui_global.sharedData[dataId].data.linkedListText == text) { ui_global.sharedData[dataId].versionId++; return; } UI_ResetData(dataId); ui_global.sharedData[dataId].type = UI_SHARED_LINKEDLISTTEXT; ui_global.sharedData[dataId].data.linkedListText = text; ui_global.sharedData[dataId].versionId++; }
/** * @brief Draw a text node */ static void UI_TextListNodeDraw (uiNode_t *node) { const uiSharedData_t *shared; shared = &ui_global.sharedData[EXTRADATA(node).dataID]; /* nothing set yet? */ if (shared->type == UI_SHARED_NONE) return; if (shared->type != UI_SHARED_LINKEDLISTTEXT) { Com_Printf("UI_TextListNodeDraw: Only linkedlist text supported (dataid %d).\n", EXTRADATA(node).dataID); UI_ResetData(EXTRADATA(node).dataID); return; } UI_TextLineNodeDrawText(node, shared->data.linkedListText); }
/** * @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; }
/** * @brief Prints the description for items (weapons, armour, ...) * @param[in] od The object definition of the item * @note Not only called from UFOpaedia but also from other places to display * weapon and ammo statistics * @todo Do we need to add checks for @c od->isDummy here somewhere? */ void INV_ItemDescription (const objDef_t* od) { static char itemText[UI_MAX_SMALLTEXTLEN]; int i; int count; currentDisplayedObject = od; Cvar_Set("mn_firemodename", ""); Cvar_Set("mn_linkname", ""); if (!od) { /* If nothing selected return */ Cvar_Set("mn_itemname", ""); Cvar_Set("mn_item", ""); UI_ResetData(TEXT_ITEMDESCRIPTION); itemIndex = fireModeIndex = 0; UI_ExecuteConfunc("itemdesc_view 0 0;"); return; } /* select item */ Cvar_Set("mn_itemname", "%s", _(od->name)); Cvar_Set("mn_item", "%s", od->id); count = 0; if (GAME_ItemIsUseable(od)) { if (od->isAmmo()) { /* We display the pre/next buttons for changing weapon only if there are at least 2 researched weapons * we are counting the number of weapons that are usable with this ammo */ for (i = 0; i < od->numWeapons; i++) if (GAME_ItemIsUseable(od->weapons[i])) count++; if (itemIndex >= od->numWeapons || itemIndex < 0) itemIndex = 0; if (count > 0) { while (!GAME_ItemIsUseable(od->weapons[itemIndex])) { itemIndex++; if (itemIndex >= od->numWeapons) itemIndex = 0; } Cvar_ForceSet("mn_linkname", _(od->weapons[itemIndex]->name)); } } else if (od->weapon) { /* We display the pre/next buttons for changing ammo only if there are at least 2 researched ammo * we are counting the number of ammo that is usable with this weapon */ for (i = 0; i < od->numAmmos; i++) if (GAME_ItemIsUseable(od->ammos[i])) count++; if (itemIndex >= od->numAmmos || itemIndex < 0) itemIndex = 0; /* Only display ammos if at least one has been researched */ if (count > 0) { /* We have a weapon that uses ammos */ while (!GAME_ItemIsUseable(od->ammos[itemIndex])) { itemIndex++; if (itemIndex >= od->numAmmos) itemIndex = 0; } Cvar_ForceSet("mn_linkname", _(od->ammos[itemIndex]->name)); } } else { Cvar_ForceSet("mn_linkname", ""); } } /* set description text if item has been researched or one of its ammo/weapon has been researched */ if (count > 0 || GAME_ItemIsUseable(od)) { int numFiredefs = 0; *itemText = '\0'; if (od->isArmour()) { Com_sprintf(itemText, sizeof(itemText), _("Size:\t%i\n"), od->size); Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight); Q_strcat(itemText, sizeof(itemText), "\n"); Q_strcat(itemText, sizeof(itemText), _("^BDamage type:\tProtection:\n")); for (i = 0; i < csi.numDTs; i++) { const damageType_t* dt = &csi.dts[i]; if (!dt->showInMenu) continue; Q_strcat(itemText, sizeof(itemText), _("%s\t%i\n"), _(dt->id), od->ratings[i]); } } else if ((od->weapon && od->numAmmos) || od->isAmmo()) { const objDef_t* odAmmo; if (count > 0) { int weaponIndex; if (od->weapon) { Com_sprintf(itemText, sizeof(itemText), _("%s weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed"))); if (od->ammo > 0) Q_strcat(itemText, sizeof(itemText), _("Max ammo:\t%i\n"), od->ammo); odAmmo = (od->numAmmos) ? od->ammos[itemIndex] : od; assert(odAmmo); for (weaponIndex = 0; (weaponIndex < odAmmo->numWeapons) && (odAmmo->weapons[weaponIndex] != od); weaponIndex++) {} } else { odAmmo = od; weaponIndex = itemIndex; } Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight); /** @todo is there ammo with no firedefs? */ if (GAME_ItemIsUseable(odAmmo) && odAmmo->numFiredefs[weaponIndex] > 0) { const fireDef_t* fd; numFiredefs = odAmmo->numFiredefs[weaponIndex]; /* This contains everything common for weapons and ammos */ /* We check if the wanted firemode to display exists. */ if (fireModeIndex > numFiredefs - 1) fireModeIndex = 0; if (fireModeIndex < 0) fireModeIndex = numFiredefs - 1; fd = &odAmmo->fd[weaponIndex][fireModeIndex]; /* We always display the name of the firemode for an ammo */ Cvar_Set("mn_firemodename", "%s", _(fd->name)); /* We display the characteristics of this firemode */ Q_strcat(itemText, sizeof(itemText), _("Skill:\t%s\n"), CL_WeaponSkillToName(fd->weaponSkill)); Q_strcat(itemText, sizeof(itemText), _("Damage:\t%i\n"), (int) (fd->damage[0] + fd->spldmg[0]) * fd->shots); Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time); Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE); Q_strcat(itemText, sizeof(itemText), _("Spreads:\t%g\n"), (fd->spread[0] + fd->spread[1]) / 2); } } else { Com_sprintf(itemText, sizeof(itemText), _("%s. No detailed info available.\n"), od->isAmmo() ? _("Ammunition") : _("Weapon")); Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight); } } else if (od->weapon) { Com_sprintf(itemText, sizeof(itemText), _("%s ammo-less weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed"))); Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight); } else { /* just an item - only primary definition */ Com_sprintf(itemText, sizeof(itemText), _("%s auxiliary equipment\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed"))); Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight); if (od->numWeapons > 0 && od->numFiredefs[0] > 0) { const fireDef_t* fd = &od->fd[0][0]; Q_strcat(itemText, sizeof(itemText), _("Action:\t%s\n"), _(fd->name)); Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time); Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE); } } UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText); UI_ExecuteConfunc("itemdesc_view %i %i;", count, numFiredefs); } else { Com_sprintf(itemText, sizeof(itemText), _("Unknown - not useable")); UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText); UI_ExecuteConfunc("itemdesc_view 0 0;"); } }
/** * @brief Updates the Buy/Sell menu list. * @param[in] base Pointer to the base to buy/sell at * @sa BS_BuyType_f */ static void BS_BuyType (const base_t *base) { const objDef_t *od; int i, j = 0; char tmpbuf[MAX_VAR]; if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0) return; CP_UpdateCredits(ccs.credits); bsMarketNames = NULL; bsMarketStorage = NULL; bsMarketMarket = NULL; bsMarketPrices = NULL; UI_ResetData(TEXT_ITEMDESCRIPTION); /* hide autosell checkboxes by default */ for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) { UI_ExecuteConfunc("buy_autoselli %i", i); } switch (buyCat) { case FILTER_AIRCRAFT: /* Aircraft */ { const aircraft_t *aircraftTemplate; for (i = 0, j = 0, aircraftTemplate = ccs.aircraftTemplates; i < ccs.numAircraftTemplates; i++, aircraftTemplate++) { if (!BS_AircraftIsOnMarket(aircraftTemplate)) continue; assert(aircraftTemplate->tech); if (BS_GetStorageAmountInBase(base, aircraftTemplate->id) + BS_GetAircraftOnMarket(aircraftTemplate) > 0) { if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); } BS_AddToList(aircraftTemplate->name, BS_GetStorageAmountInBase(base, aircraftTemplate->id), BS_GetAircraftOnMarket(aircraftTemplate), BS_GetAircraftBuyingPrice(aircraftTemplate)); if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n"); buyList.l[j].item = NULL; buyList.l[j].aircraft = aircraftTemplate; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } } break; case FILTER_CRAFTITEM: /* Aircraft items */ /* get item list */ for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) { if (!BS_IsOnMarket(od)) continue; /* Check whether the item matches the proper filter, storage in current base and market. */ if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, FILTER_CRAFTITEM)) { if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { const technology_t *tech = RS_GetTechForItem(od); UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); if (RS_IsResearched_ptr(tech)) { if (ccs.eMarket.autosell[i]) UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll); else UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll); } } BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od)); if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_FILTERLIST value to handle that much items\n"); buyList.l[j].item = od; buyList.l[j].aircraft = NULL; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } break; default: /* Normal items */ if (buyCat < MAX_SOLDIER_FILTERTYPES || buyCat == FILTER_DUMMY) { /* get item list */ for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) { if (!BS_IsOnMarket(od)) continue; /* Check whether the item matches the proper filter, storage in current base and market. */ if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, buyCat)) { BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od)); /* Set state of Autosell button. */ if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { const technology_t *tech = RS_GetTechForItem(od); UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); if (RS_IsResearched_ptr(tech)) { if (ccs.eMarket.autosell[i]) UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll); else UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll); } } if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n"); buyList.l[j].item = od; buyList.l[j].aircraft = NULL; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } } break; } for (; j < MAX_MARKET_MENU_ENTRIES; j++) { /* Hide the rest of the entries. */ UI_ExecuteConfunc("buy_hide %i", j); } /* Update some menu cvars. */ /* Set up base capacities. */ Com_sprintf(tmpbuf, sizeof(tmpbuf), "%i/%i", CAP_GetCurrent(base, CAP_ITEMS), CAP_GetMax(base, CAP_ITEMS)); Cvar_Set("mn_bs_storage", tmpbuf); /* select first item */ if (buyList.length) { switch (buyCat) { /** @sa BS_MarketClick_f */ case FILTER_AIRCRAFT: BS_MarketAircraftDescription(buyList.l[0].aircraft); break; case FILTER_CRAFTITEM: Cvar_Set("mn_aircraftname", ""); /** @todo Use craftitem name here? See also BS_MarketClick_f */ /* Select current item or first one. */ if (currentSelectedMenuEntry) UP_AircraftItemDescription(currentSelectedMenuEntry); else UP_AircraftItemDescription(buyList.l[0].item); break; default: assert(buyCat != MAX_FILTERTYPES); /* Select current item or first one. */ if (currentSelectedMenuEntry) INV_ItemDescription(currentSelectedMenuEntry); else INV_ItemDescription(buyList.l[0].item); break; } } else { /* reset description */ INV_ItemDescription(NULL); } UI_RegisterLinkedListText(TEXT_MARKET_NAMES, bsMarketNames); UI_RegisterLinkedListText(TEXT_MARKET_STORAGE, bsMarketStorage); UI_RegisterLinkedListText(TEXT_MARKET_MARKET, bsMarketMarket); UI_RegisterLinkedListText(TEXT_MARKET_PRICES, bsMarketPrices); }