1 /**
2 * @file
3 * @brief Menu related console command callbacks
4 */
5
6 /*
7 Copyright (C) 2002-2013 UFO: Alien Invasion.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18 See the GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 */
25
26 #include "../../cl_shared.h"
27 #include "../../ui/ui_dataids.h"
28 #include "cp_campaign.h"
29 #include "cp_installation_callbacks.h"
30 #include "cp_installation.h"
31 #include "cp_geoscape.h"
32 #include "cp_popup.h"
33 #include "cp_ufo.h"
34 #include "cp_uforecovery_callbacks.h"
35
36 /**
37 * @brief Sets the title of the installation to a cvar to prepare the rename menu.
38 * @note it also assigns description text
39 */
INS_SetInstallationTitle(installationType_t type)40 static void INS_SetInstallationTitle (installationType_t type)
41 {
42 const installationTemplate_t* insTemp = INS_GetInstallationTemplateByType(type);
43 cgi->Cvar_Set("mn_installation_title", "%s #%i", (insTemp) ? _(insTemp->name) : _("Installation"), ccs.campaignStats.installationsBuilt + 1);
44 if (!insTemp || !Q_strvalid(insTemp->description))
45 cgi->UI_ResetData(TEXT_BUILDING_INFO);
46 else
47 cgi->UI_RegisterText(TEXT_BUILDING_INFO, _(insTemp->description));
48 }
49
50 /**
51 * @brief Select an installation when clicking on it on geoscape
52 * @param[in] installation The installation to select
53 * @note This is (and should be) the only place where installationCurrent is set
54 * to a value that is not @c nullptr
55 */
INS_SelectInstallation(installation_t * installation)56 void INS_SelectInstallation (installation_t* installation)
57 {
58 const int timetobuild = std::max(0, installation->installationTemplate->buildTime - (ccs.date.day - installation->buildStart));
59
60 Com_DPrintf(DEBUG_CLIENT, "INS_SelectInstallation: select installation with id %i\n", installation->idx);
61 ccs.mapAction = MA_NONE;
62 if (installation->installationStatus == INSTALLATION_WORKING) {
63 cgi->Cvar_Set("mn_installation_timetobuild", "-");
64 } else {
65 cgi->Cvar_Set("mn_installation_timetobuild", ngettext("%d day", "%d days", timetobuild), timetobuild);
66 }
67 INS_SetCurrentSelectedInstallation(installation);
68
69 switch (installation->installationTemplate->type) {
70 case INSTALLATION_UFOYARD:
71 cgi->UI_PushWindow("popup_ufoyards");
72 break;
73 case INSTALLATION_DEFENCE:
74 cgi->UI_PushWindow("basedefence");
75 break;
76 default:
77 cgi->UI_PushWindow("popup_installationstatus");
78 break;
79 }
80 }
81
82 /**
83 * @brief Constructs a new installation.
84 */
INS_BuildInstallation_f(void)85 static void INS_BuildInstallation_f (void)
86 {
87 const installationTemplate_t* installationTemplate;
88
89 if (cgi->Cmd_Argc() < 1) {
90 Com_Printf("Usage: %s <installationType>\n", cgi->Cmd_Argv(0));
91 return;
92 }
93
94 /* We shouldn't build more installations than the actual limit */
95 if (B_GetInstallationLimit() <= INS_GetCount())
96 return;
97
98 installationTemplate = INS_GetInstallationTemplateByID(cgi->Cmd_Argv(1));
99 if (!installationTemplate) {
100 Com_Printf("The installation type %s passed for %s is not valid.\n", cgi->Cmd_Argv(1), cgi->Cmd_Argv(0));
101 return;
102 }
103
104 assert(installationTemplate->cost >= 0);
105
106 if (ccs.credits - installationTemplate->cost > 0) {
107 /* set up the installation */
108 installation_t* installation = INS_Build(installationTemplate, ccs.newBasePos, cgi->Cvar_GetString("mn_installation_title"));
109
110 CP_UpdateCredits(ccs.credits - installationTemplate->cost);
111 /* this cvar is used for disabling the installation build button on geoscape if MAX_INSTALLATIONS was reached */
112 cgi->Cvar_SetValue("mn_installation_count", INS_GetCount());
113
114 const nation_t* nation = GEO_GetNation(installation->pos);
115 if (nation)
116 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new installation has been built: %s (nation: %s)"), installation->name, _(nation->name));
117 else
118 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new installation has been built: %s"), installation->name);
119 MSO_CheckAddNewMessage(NT_INSTALLATION_BUILDSTART, _("Installation building"), cp_messageBuffer, MSG_CONSTRUCTION);
120 } else {
121 if (installationTemplate->type == INSTALLATION_RADAR) {
122 if (GEO_IsRadarOverlayActivated())
123 GEO_SetOverlay("radar");
124 }
125 if (ccs.mapAction == MA_NEWINSTALLATION)
126 ccs.mapAction = MA_NONE;
127
128 CP_Popup(_("Notice"), _("Not enough credits to set up a new installation."));
129 }
130 ccs.mapAction = MA_NONE;
131 }
132
133 /**
134 * @brief Called when an installation is opened or a new installation is created on geoscape.
135 * For a new installation the installationID is -1.
136 */
INS_SelectInstallation_f(void)137 static void INS_SelectInstallation_f (void)
138 {
139 int installationID;
140 installation_t* installation;
141
142 if (cgi->Cmd_Argc() < 2) {
143 Com_Printf("Usage: %s <installationID>\n", cgi->Cmd_Argv(0));
144 return;
145 }
146 installationID = atoi(cgi->Cmd_Argv(1));
147
148 installation = INS_GetByIDX(installationID);
149 if (installation != nullptr)
150 INS_SelectInstallation(installation);
151 }
152
153 /**
154 * @brief Creates console command to change the name of a installation.
155 * Copies the value of the cvar mn_installation_title over as the name of the
156 * current selected installation
157 */
INS_ChangeInstallationName_f(void)158 static void INS_ChangeInstallationName_f (void)
159 {
160 installation_t* installation = INS_GetCurrentSelectedInstallation();
161
162 /* maybe called without installation initialized or active */
163 if (!installation)
164 return;
165
166 Q_strncpyz(installation->name, cgi->Cvar_GetString("mn_installation_title"), sizeof(installation->name));
167 }
168
169 /**
170 * @brief console function for destroying an installation
171 * @sa INS_DestroyInstallation
172 */
INS_DestroyInstallation_f(void)173 static void INS_DestroyInstallation_f (void)
174 {
175 installation_t* installation;
176
177 if (cgi->Cmd_Argc() < 2 || atoi(cgi->Cmd_Argv(1)) < 0) {
178 installation = INS_GetCurrentSelectedInstallation();
179 } else {
180 installation = INS_GetByIDX(atoi(cgi->Cmd_Argv(1)));
181 if (!installation) {
182 Com_DPrintf(DEBUG_CLIENT, "Installation not founded (idx %i)\n", atoi(cgi->Cmd_Argv(1)));
183 return;
184 }
185 }
186
187 /* Ask 'Are you sure?' by default */
188 if (cgi->Cmd_Argc() < 3 || !atoi(cgi->Cmd_Argv(2))) {
189 char command[MAX_VAR];
190
191 Com_sprintf(command, sizeof(command), "mn_installation_destroy %d 1; ui_pop;", installation->idx);
192 cgi->UI_PopupButton(_("Destroy Installation"), _("Do you really want to destroy this installation?"),
193 command, _("Destroy"), _("Destroy installation"),
194 "ui_pop;", _("Cancel"), _("Forget it"),
195 nullptr, nullptr, nullptr);
196 return;
197 }
198 INS_DestroyInstallation(installation);
199 }
200
201 /**
202 * @brief updates the installation limit cvar for menus
203 */
INS_UpdateInstallationLimit_f(void)204 static void INS_UpdateInstallationLimit_f (void)
205 {
206 cgi->Cvar_SetValue("mn_installation_max", B_GetInstallationLimit());
207 }
208
209 /**
210 * @brief Fills the UI with ufo yard data
211 */
INS_FillUFOYardData_f(void)212 static void INS_FillUFOYardData_f (void)
213 {
214 installation_t* ins;
215
216 cgi->UI_ExecuteConfunc("ufolist_clear");
217 if (cgi->Cmd_Argc() < 2 || atoi(cgi->Cmd_Argv(1)) < 0) {
218 ins = INS_GetCurrentSelectedInstallation();
219 if (!ins || ins->installationTemplate->type != INSTALLATION_UFOYARD)
220 ins = INS_GetFirstUFOYard(false);
221 } else {
222 ins = INS_GetByIDX(atoi(cgi->Cmd_Argv(1)));
223 if (!ins)
224 Com_DPrintf(DEBUG_CLIENT, "Installation not founded (idx %i)\n", atoi(cgi->Cmd_Argv(1)));
225 }
226
227 if (ins) {
228 const nation_t* nat = GEO_GetNation(ins->pos);
229 const int timeToBuild = std::max(0, ins->installationTemplate->buildTime - (ccs.date.day - ins->buildStart));
230 const char* buildTime = (timeToBuild > 0 && ins->installationStatus == INSTALLATION_UNDER_CONSTRUCTION) ? va(ngettext("%d day", "%d days", timeToBuild), timeToBuild) : "-";
231 const int freeCap = std::max(0, ins->ufoCapacity.max - ins->ufoCapacity.cur);
232 const char* nationName = nat ? _(nat->name) : "";
233
234 cgi->UI_ExecuteConfunc("ufolist_addufoyard %d \"%s\" \"%s\" %d %d \"%s\"", ins->idx, ins->name, nationName, ins->ufoCapacity.max, freeCap, buildTime);
235
236 US_Foreach(ufo) {
237 if (ufo->installation != ins)
238 continue;
239
240 const char* ufoName = UFO_GetName(ufo->ufoTemplate);
241 const char* condition = va(_("Condition: %3.0f%%"), ufo->condition * 100);
242 const char* status = US_StoredUFOStatus(ufo);
243 cgi->UI_ExecuteConfunc("ufolist_addufo %d \"%s\" \"%s\" \"%s\" \"%s\"", ufo->idx, ufoName, condition, ufo->ufoTemplate->model, status);
244 }
245 }
246 }
247
248 /**
249 * @brief Fills create installation / installation type selection popup
250 */
INS_FillTypes_f(void)251 static void INS_FillTypes_f (void)
252 {
253 cgi->UI_ExecuteConfunc("installationtype_clear");
254 if (INS_GetCount() < B_GetInstallationLimit()) {
255 int i;
256 for (i = 0; i < ccs.numInstallationTemplates; i++) {
257 const installationTemplate_t* tpl = &ccs.installationTemplates[i];
258 if (tpl->once && INS_HasType(tpl->type, INSTALLATION_NOT_USED))
259 continue;
260 if (tpl->tech == nullptr || RS_IsResearched_ptr(tpl->tech)) {
261 cgi->UI_ExecuteConfunc("installationtype_add \"%s\" \"%s\" \"%s\" \"%d c\"", tpl->id, _(tpl->name),
262 (tpl->buildTime > 0) ? va("%d %s", tpl->buildTime, ngettext("day", "days", tpl->buildTime)) : "-", tpl->cost);
263 }
264 }
265 }
266
267 /** @todo Move this out from installations code */
268 if (B_GetCount() < MAX_BASES)
269 cgi->UI_ExecuteConfunc("installationtype_add base \"%s\" - \"%d c\"", _("Base"), ccs.curCampaign->basecost);
270 }
271
272 /**
273 * @brief Selects installation type to build
274 */
INS_SelectType_f(void)275 static void INS_SelectType_f (void)
276 {
277 if (cgi->Cmd_Argc() < 2)
278 return;
279
280 const char* id = cgi->Cmd_Argv(1);
281
282 if (ccs.mapAction == MA_NEWINSTALLATION) {
283 GEO_ResetAction();
284 return;
285 }
286
287 const installationTemplate_t* tpl = INS_GetInstallationTemplateByID(id);
288 if (!tpl) {
289 Com_Printf("Invalid installation template\n");
290 return;
291 }
292
293 if (INS_GetCount() >= B_GetInstallationLimit()) {
294 Com_Printf("Maximum number of installations reached\n");
295 return;
296 }
297
298 if (tpl->tech != nullptr && !RS_IsResearched_ptr(tpl->tech)) {
299 Com_Printf("This type of installation is not yet researched\n");
300 return;
301 }
302
303 if (tpl->once && INS_HasType(tpl->type, INSTALLATION_NOT_USED)) {
304 Com_Printf("Cannot build more of this installation\n");
305 return;
306 }
307
308 ccs.mapAction = MA_NEWINSTALLATION;
309
310 /* show radar overlay (if not already displayed) */
311 if (tpl->type == INSTALLATION_RADAR && !GEO_IsRadarOverlayActivated())
312 GEO_SetOverlay("radar");
313
314 INS_SetInstallationTitle(tpl->type);
315 cgi->Cvar_Set("mn_installation_type", "%s", tpl->id);
316 }
317
INS_InitCallbacks(void)318 void INS_InitCallbacks (void)
319 {
320 cgi->Cmd_AddCommand("mn_installation_select", INS_SelectInstallation_f, "Parameter is the installation index. -1 will build a new one.");
321 cgi->Cmd_AddCommand("mn_installation_build", INS_BuildInstallation_f, nullptr);
322 cgi->Cmd_AddCommand("mn_installation_changename", INS_ChangeInstallationName_f, "Called after editing the cvar installation name");
323 cgi->Cmd_AddCommand("mn_installation_destroy", INS_DestroyInstallation_f, "Destroys an installation");
324 cgi->Cmd_AddCommand("mn_installation_update_max_count", INS_UpdateInstallationLimit_f, "Updates the installation count limit");
325
326 cgi->Cmd_AddCommand("ui_fill_installationtypes", INS_FillTypes_f, "Fills create installation / installation type selection popup");
327 cgi->Cmd_AddCommand("ui_build_installationtype", INS_SelectType_f, "Selects installation type to build");
328 cgi->Cmd_AddCommand("ui_fillufoyards", INS_FillUFOYardData_f, "Fills UFOYard UI with data");
329
330 cgi->Cvar_SetValue("mn_installation_count", INS_GetCount());
331 cgi->Cvar_Set("mn_installation_title", "");
332 cgi->Cvar_Set("mn_installation_type", "");
333 cgi->Cvar_Set("mn_installation_max", "");
334 }
335
INS_ShutdownCallbacks(void)336 void INS_ShutdownCallbacks (void)
337 {
338 cgi->Cmd_RemoveCommand("ui_build_installationtype");
339 cgi->Cmd_RemoveCommand("ui_fill_installationtypes");
340 cgi->Cmd_RemoveCommand("ui_fillufoyards");
341
342 cgi->Cmd_RemoveCommand("mn_installation_select");
343 cgi->Cmd_RemoveCommand("mn_installation_build");
344 cgi->Cmd_RemoveCommand("mn_installation_changename");
345 cgi->Cmd_RemoveCommand("mn_installation_destroy");
346 cgi->Cmd_RemoveCommand("mn_installation_update_max_count");
347 cgi->Cvar_Delete("mn_installation_count");
348 cgi->Cvar_Delete("mn_installation_title");
349 cgi->Cvar_Delete("mn_installation_max");
350 cgi->Cvar_Delete("mn_installation_type");
351 }
352