UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_aircraft_callbacks.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 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 #include "../../cl_shared.h"
26 #include "../../ui/ui_dataids.h"
27 #include "cp_campaign.h"
28 #include "cp_geoscape.h"
29 #include "cp_aircraft_callbacks.h"
30 #include "cp_aircraft.h"
31 #include "cp_team.h"
32 #include "cp_mapfightequip.h"
33 #include "cp_popup.h"
34 #include "cp_missions.h"
35 
43 static void AIM_AircraftReturnToBase_f (void)
44 {
45  aircraft_t* aircraft = nullptr;
46 
47  if (cgi->Cmd_Argc() >= 2) {
48  const int index = atoi(cgi->Cmd_Argv(1));
49  aircraft = AIR_AircraftGetFromIDX(index);
50  } else {
52  if (base && base->aircraftCurrent)
53  aircraft = base->aircraftCurrent;
54  }
55  if (aircraft == nullptr)
56  return;
57 
58  AIR_AircraftReturnToBase(aircraft);
59  AIR_AircraftSelect(aircraft);
60 }
61 
68 static void AIM_SelectAircraft_f (void)
69 {
71 
72  if (!base)
73  return;
74 
75  if (cgi->Cmd_Argc() < 2) {
76  if (base->aircraftCurrent)
78  } else {
79  const int i = atoi(cgi->Cmd_Argv(1));
80  aircraft_t* aircraft = AIR_GetAircraftFromBaseByIDXSafe(base, i);
81  if (aircraft != nullptr)
82  AIR_AircraftSelect(aircraft);
83  }
84 }
85 
89 static void AIM_AircraftStart_f (void)
90 {
92 
93  if (!base)
94  return;
95 
96  if (!base->aircraftCurrent) {
97  cgi->Com_DPrintf(DEBUG_CLIENT, "Error - there is no current aircraft in this base\n");
98  return;
99  }
100 
101  /* Aircraft cannot start without operational Command Centre. */
102  if (!B_GetBuildingStatus(base, B_COMMAND)) {
103  CP_Popup(_("Notice"), _("No operational Command Centre in this base.\n\nAircraft can not start.\n"));
104  return;
105  }
106 
107  aircraft_t* aircraft = base->aircraftCurrent;
108 
109  /* Aircraft cannot start without a pilot. */
110  if (!AIR_GetPilot(aircraft)) {
111  CP_Popup(_("Notice"), _("There is no pilot assigned to this aircraft.\n\nAircraft can not start.\n"));
112  return;
113  }
114 
115  if (AIR_IsAircraftInBase(aircraft)) {
116  /* reload its ammunition */
117  AII_ReloadAircraftWeapons(aircraft);
118  }
119  MS_AddNewMessage(_("Notice"), _("Aircraft started"));
120  aircraft->status = AIR_IDLE;
121 
122  GEO_SelectAircraft(aircraft);
123  /* Return to geoscape. */
124  cgi->UI_PopWindow(false);
125  cgi->UI_PopWindow(false);
126 }
127 
134 static int AIR_GetSlotItems (aircraftItemType_t type, const aircraft_t* aircraft)
135 {
136  int max;
137  const aircraftSlot_t* slot;
138 
139  assert(aircraft);
140 
141  switch (type) {
142  case AC_ITEM_SHIELD:
143  if (aircraft->shield.item)
144  return 1;
145  return 0;
146  case AC_ITEM_WEAPON:
147  slot = aircraft->weapons;
148  max = MAX_AIRCRAFTSLOT;
149  break;
150  case AC_ITEM_ELECTRONICS:
151  slot = aircraft->electronics;
152  max = MAX_AIRCRAFTSLOT;
153  break;
154  default:
155  cgi->Com_Printf("AIR_GetSlotItems: Unknown type of slot : %i", type);
156  return 0;
157  }
158 
159  int cnt = 0;
160  for (int i = 0; i < max; i++)
161  if (slot[i].item)
162  cnt++;
163 
164  return cnt;
165 }
166 
172 {
173  static char aircraftInfo[256];
174  base_t* base;
175 
176  if (aircraft != nullptr)
177  base = aircraft->homebase;
178  else
179  base = nullptr;
180 
181  if (!AIR_BaseHasAircraft(base)) {
182  cgi->UI_ResetData(TEXT_AIRCRAFT_INFO);
183  return;
184  }
185 
186  assert(aircraft);
187  assert(aircraft->homebase == base);
189 
190  cgi->Cvar_Set("mn_aircraftinbase", "%s", AIR_IsAircraftInBase(aircraft) ? "1" : "0");
191  cgi->Cvar_Set("mn_aircraftname", "%s", aircraft->name);
192  if (!aircraft->tech)
193  cgi->Com_Error(ERR_DROP, "No technology assigned to aircraft '%s'", aircraft->id);
194  cgi->Cvar_Set("mn_aircraft_model", "%s", aircraft->tech->mdl);
195  cgi->Cvar_Set("mn_aircraft_health", "%3.0f" , aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (double)aircraft->damage * 100 / aircraft->stats[AIR_STATS_DAMAGE] : 0);
196 
197  /* generate aircraft info text */
198  Com_sprintf(aircraftInfo, sizeof(aircraftInfo), _("Speed:\t%i km/h\n"),
200  Q_strcat(aircraftInfo, sizeof(aircraftInfo), _("Fuel:\t%i/%i\n"), AIR_AircraftMenuStatsValues(aircraft->fuel, AIR_STATS_FUELSIZE),
202  Q_strcat(aircraftInfo, sizeof(aircraftInfo), _("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft));
203  Q_strcat(aircraftInfo, sizeof(aircraftInfo), _("Weapons:\t%i of %i\n"), AIR_GetSlotItems(AC_ITEM_WEAPON, aircraft), aircraft->maxWeapons);
204  Q_strcat(aircraftInfo, sizeof(aircraftInfo), _("Armour:\t%i of 1\n"), AIR_GetSlotItems(AC_ITEM_SHIELD, aircraft));
205  Q_strcat(aircraftInfo, sizeof(aircraftInfo), _("Electronics:\t%i of %i"), AIR_GetSlotItems(AC_ITEM_ELECTRONICS, aircraft), aircraft->maxElectronics);
206 
207  cgi->UI_RegisterText(TEXT_AIRCRAFT_INFO, aircraftInfo);
208 
210  /* compute the ID and... */
211  int id = 0;
212  AIR_ForeachFromBase(aircraftInBase, base) {
213  if (aircraft == aircraftInBase)
214  break;
215  id++;
216  }
217 
218  base->aircraftCurrent = aircraft;
219  cgi->Cvar_SetValue("mn_aircraft_id", id);
220 
221  /* ...update the GUI */
222  cgi->UI_ExecuteConfunc("ui_aircraft_selected %i", id);
223  cgi->UI_ExecuteConfunc("aircraft_change %i", id);
224 }
225 
229 static void AIR_AircraftFillList_f (void)
230 {
232 
233  cgi->UI_ExecuteConfunc("ui_aircraft_clear");
234  int idx = 0;
235  AIR_ForeachFromBase(aircraft, base) {
236  const float health = aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (float)aircraft->damage * 100.0f / aircraft->stats[AIR_STATS_DAMAGE] : 0.0f;
237  const char* inBase = AIR_IsAircraftInBase(aircraft) ? "1" : "0";
238  char teamStr[MAX_VAR];
239  Com_sprintf(teamStr, sizeof(teamStr), _("%i of %i"), AIR_GetTeamSize(aircraft), aircraft->maxTeamSize);
240  cgi->UI_ExecuteConfunc("ui_aircraft_add %i \"%s\" %3.0f %s \"%s\" \"%s\"", idx, _(aircraft->name), health, inBase, AIR_AircraftStatusToName(aircraft), teamStr);
241  idx++;
242  }
243 }
244 
253 static void AIR_ChangeAircraftName_f (void)
254 {
255  const base_t* base = B_GetCurrentSelectedBase();
256  if (!base)
257  return;
258 
259  aircraft_t* aircraft = base->aircraftCurrent;
260  if (!aircraft)
261  return;
262 
263  /* set default name on empty new name*/
264  const char* newName = cgi->Cvar_GetString("mn_aircraftname");
265  if (Q_strnull(newName)) {
266  Q_strncpyz(aircraft->name, _(aircraft->defaultName), sizeof(aircraft->name));
267  return;
268  }
269 
270  /* refuse to set name contains only non-printable characters */
271  int i;
272  for (i = 0; newName[i] != '\0'; i++) {
273  if (newName[i] > 0x20)
274  break;
275  }
276  if (newName[i] == '\0')
277  return;
278 
279  /* aircraft name should not contain " */
280  if (!Com_IsValidName(newName))
281  return;
282 
283  Q_strncpyz(aircraft->name, newName, sizeof(aircraft->name));
284 }
285 
289 static void AIR_GeoSelectAircraft_f (void)
290 {
291  if (cgi->Cmd_Argc() < 2) {
292  return;
293  }
294 
295  const int index = atoi(cgi->Cmd_Argv(1));
296  aircraft_t* aircraft = AIR_AircraftGetFromIDX(index);
297  if (aircraft == nullptr)
298  return;
299 
300  if (!GEO_IsAircraftSelected(aircraft))
301  GEO_SelectAircraft(aircraft);
302 
304  int action_id = 0;
305  cgi->UI_ExecuteConfunc("ui_clear_aircraft_action");
306  cgi->UI_ExecuteConfunc("ui_add_aircraft_action %i \"%s\" \"%s\"",
307  action_id++, _("Change homebase"), va("ui_aircraft_changehomebase %u;", aircraft->idx));
308  cgi->UI_ExecuteConfunc("ui_add_aircraft_action %i \"%s\" \"%s\"",
309  action_id++, va("%s: %s", _("Back to base"), aircraft->homebase->name), va("aircraft_return %u;", aircraft->idx));
310  cgi->UI_ExecuteConfunc("ui_add_aircraft_action %i \"%s\" \"%s\"",
311  action_id++, _("Stop"), va("ui_aircraft_stop %u;", aircraft->idx));
312 
313  if (AIR_GetTeamSize(aircraft) > 0) {
314  MIS_Foreach(tempMission) {
315  if (AIR_GetTeamSize(aircraft) == 0)
316  continue;
317  if (tempMission->stage == STAGE_NOT_ACTIVE || !tempMission->onGeoscape)
318  continue;
319  if (!tempMission->pos)
320  continue;
321  if (!AIR_AircraftHasEnoughFuel(aircraft, tempMission->pos))
322  continue;
323  cgi->UI_ExecuteConfunc("ui_add_aircraft_action %i \"%s\" \"%s\"",
324  action_id++, va("%s: %s", _("Mission"), MIS_GetName(tempMission)),
325  va("ui_aircraft_to_mission %u %u;", aircraft->idx, tempMission->idx));
326  }
327  }
328 
329  cgi->UI_PushWindow("popup_aircraft_actions");
330 }
331 
335 static void AIR_StopAircraft_f (void)
336 {
337  if (cgi->Cmd_Argc() < 2) {
338  return;
339  }
340 
341  const int index = atoi(cgi->Cmd_Argv(1));
342  aircraft_t* aircraft = AIR_AircraftGetFromIDX(index);
343  if (aircraft == nullptr)
344  return;
345 
346  aircraft->status = AIR_IDLE;
347 }
348 
349 
355 {
356  if (cgi->Cmd_Argc() < 2) {
357  return;
358  }
359 
360  const int index = atoi(cgi->Cmd_Argv(1));
361  aircraft_t* aircraft = AIR_AircraftGetFromIDX(index);
362  if (aircraft == nullptr)
363  return;
364 
365  CL_DisplayHomebasePopup(aircraft, true);
366 }
367 
371 static void AIR_SendAircraftToMission_f (void)
372 {
373  if (cgi->Cmd_Argc() < 3) {
374  return;
375  }
376 
377  const int aircraftIdx = atoi(cgi->Cmd_Argv(1));
378  aircraft_t* aircraft = AIR_AircraftGetFromIDX(aircraftIdx);
379  if (aircraft == nullptr)
380  return;
381 
382  const int missionIdx = atoi(cgi->Cmd_Argv(2));
383  mission_t* mission = MIS_GetByIdx(missionIdx);
384  if (mission == nullptr)
385  return;
386 
387  AIR_SendAircraftToMission(aircraft, mission);
388 }
389 
393 static void AIR_ShowAircraft_f (void)
394 {
395  if (cgi->Cmd_Argc() < 2) {
396  cgi->Com_Printf("Usage: %s <base_idx>\n", cgi->Cmd_Argv(0));
397  return;
398  }
399  const base_t* const base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
400  if (base == nullptr) {
401  cgi->Com_Printf("AIR_ShowAircraft_f: Invalid base_idx!\n");
402  return;
403  }
404  if (!AIR_AircraftAllowed(base))
405  return;
406  int idx_in_base = 0;
407  AIR_ForeachFromBase(aircraft, base) {
408  cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i %i", aircraft->idx, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft), idx_in_base++);
409  }
410 }
411 
412 static const cmdList_t aircraftCallbacks[] = {
413  {"aircraft_start", AIM_AircraftStart_f, nullptr},
414  {"ui_aircraft_select", AIM_SelectAircraft_f, nullptr},
415  {"geo_aircraft_select", AIR_GeoSelectAircraft_f, nullptr},
416  {"aircraft_return", AIM_AircraftReturnToBase_f, "Sends the current aircraft back to homebase."},
417  {"ui_aircraft_changename", AIR_ChangeAircraftName_f, "Callback to change the name of the aircraft."},
418  {"ui_aircraft_fill", AIR_AircraftFillList_f, "Send the data for all the aircraft."},
419  {"ui_aircraft_stop", AIR_StopAircraft_f, "Clears an aircraft order when on the geoscape"},
420  {"ui_aircraft_to_mission", AIR_SendAircraftToMission_f, "Send aircraft to a misison"},
421  {"ui_aircraft_changehomebase", AIR_ShowChangeHomebaseAircraft_f, ""},
422  {"ui_show_aircraft", AIR_ShowAircraft_f, "Show aircraft in base sections"},
423  {nullptr, nullptr, nullptr}
424 };
425 
426 void AIR_InitCallbacks (void)
427 {
428  cgi->Cmd_TableAddList(aircraftCallbacks);
429 }
430 
432 {
433  cgi->Cmd_TableRemoveList(aircraftCallbacks);
434 }
bool Q_strnull(const char *string)
Definition: shared.h:138
static void AIR_ShowChangeHomebaseAircraft_f(void)
Show change homebase popup.
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition: cp_base.cpp:477
char * id
Definition: cp_aircraft.h:119
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
static void AIR_GeoSelectAircraft_f(void)
Select aircraft on Geoscape.
int AIR_AircraftMenuStatsValues(const int value, const int stat)
Some of the aircraft values needs special calculations when they are shown in the menus...
static void AIR_ChangeAircraftName_f(void)
Creates console command to change the name of an aircraft. Copies the value of the cvar mn_aircraftna...
#define MIS_Foreach(var)
iterates through missions
Definition: cp_missions.h:118
const char * AIR_AircraftStatusToName(const aircraft_t *aircraft)
Translates the aircraft status id to a translatable string.
#define _(String)
Definition: cl_shared.h:43
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition: cp_base.cpp:1578
aircraft_t * AIR_AircraftGetFromIDX(int aircraftIdx)
Returns aircraft for a given global index.
bool CL_DisplayHomebasePopup(aircraft_t *aircraft, bool alwaysDisplay)
Display the popup_homebase.
Definition: cp_popup.cpp:66
char name[MAX_VAR]
Definition: cp_aircraft.h:120
mission definition
Definition: cp_missions.h:85
static const cmdList_t aircraftCallbacks[]
uiMessageListNodeMessage_t * MS_AddNewMessage(const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup, bool playSound)
Adds a new message to message stack.
Definition: cp_messages.cpp:61
int maxElectronics
Definition: cp_aircraft.h:147
void CP_UpdateActorAircraftVar(aircraft_t *aircraft, employeeType_t employeeType)
Updates data about teams in aircraft.
Definition: cp_team.cpp:296
A base with all it's data.
Definition: cp_base.h:84
base_t * B_GetFoundedBaseByIDX(int baseIdx)
Array bound check for the base index.
Definition: cp_base.cpp:325
const char *IMPORT * Cvar_GetString(const char *varName)
Header file for menu related console command callbacks.
struct technology_s * tech
Definition: cp_aircraft.h:162
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
aircraft_t * aircraftCurrent
Definition: cp_base.h:100
#define ERR_DROP
Definition: common.h:211
bool AIR_AircraftHasEnoughFuel(const aircraft_t *aircraft, const vec2_t destination)
check if aircraft has enough fuel to go to destination, and then come back home
#define DEBUG_CLIENT
Definition: defines.h:59
int AIR_GetOperationRange(const aircraft_t *aircraft)
Calculates the range an aircraft can fly on the geoscape.
bool AIR_BaseHasAircraft(const base_t *base)
Checks whether there is any aircraft assigned to the given base.
Definition: cp_aircraft.cpp:65
#define MAX_VAR
Definition: shared.h:36
void AIR_AircraftReturnToBase(aircraft_t *aircraft)
Calculates the way back to homebase for given aircraft and returns it.
void CP_Popup(const char *title, const char *text,...)
Wrapper around UI_Popup.
Definition: cp_popup.cpp:473
Campaign missions headers.
const cgame_import_t * cgi
void AIR_ShutdownCallbacks(void)
static void AIM_SelectAircraft_f(void)
Select an aircraft from a base, by ID.
Definition: cmd.h:86
Employee * AIR_GetPilot(const aircraft_t *aircraft)
Get pilot of an aircraft.
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:143
Header for Geoscape management.
static void AIR_StopAircraft_f(void)
Stop aircraft on Geoscape.
slot of aircraft
Definition: cp_aircraft.h:77
QGL_EXTERN GLuint index
Definition: r_gl.h:110
bool AIR_AircraftAllowed(const base_t *base)
Returns true if the current base is able to handle aircraft.
char * defaultName
Definition: cp_aircraft.h:121
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
Definition: cp_aircraft.h:201
struct base_s * homebase
Definition: cp_aircraft.h:149
int maxWeapons
Definition: cp_aircraft.h:144
Header file for aircraft stuff.
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define MAX_AIRCRAFTSLOT
Definition: cp_aircraft.h:74
int AIR_GetTeamSize(const aircraft_t *aircraft)
Counts the number of soldiers in given aircraft.
Header for slot management related stuff.
aircraftItemType_t
All different types of craft items.
Definition: inv_shared.h:197
aircraftSlot_t shield
Definition: cp_aircraft.h:145
bool Com_IsValidName(const char *input)
Checks whether the given input string is allowed to be used as a user-given name string for aircraft...
Definition: shared.cpp:612
aircraftStatus_t status
Definition: cp_aircraft.h:125
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
static void AIM_AircraftReturnToBase_f(void)
Script function for AIR_AircraftReturnToBase.
bool AIR_SendAircraftToMission(aircraft_t *aircraft, mission_t *mission)
Sends the specified aircraft to specified mission.
Header file for single player campaign control.
void AIR_InitCallbacks(void)
aircraft_t * AIR_GetAircraftFromBaseByIDXSafe(const base_t *base, int index)
static void AIR_ShowAircraft_f(void)
Show aircraft in Base sections.
static void AIR_SendAircraftToMission_f(void)
Send aircraft to land on a mission.
int stats[AIR_STATS_MAX]
Definition: cp_aircraft.h:159
const char * MIS_GetName(const mission_t *mission)
Returns a short translated name for a mission.
static void AIM_AircraftStart_f(void)
Starts an aircraft or stops the current mission and lets the aircraft idle around.
An aircraft with all it's data.
Definition: cp_aircraft.h:114
Team management for the campaign gametype headers.
static int AIR_GetSlotItems(aircraftItemType_t type, const aircraft_t *aircraft)
Returns the amount of assigned items for a given slot of a given aircraft.
mission_t * MIS_GetByIdx(int id)
Find mission corresponding to idx.
void AIR_AircraftSelect(aircraft_t *aircraft)
Sets aircraftCurrent and updates related cvars and menutexts.
static void AIR_AircraftFillList_f(void)
Update aircraft selection list with the current base aircraft names.
const char *IMPORT * Cmd_Argv(int n)
aircraftSlot_t electronics[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:146
const objDef_t * item
Definition: cp_aircraft.h:84
void GEO_SelectAircraft(aircraft_t *aircraft)
Select the specified aircraft on the geoscape.
#define GEO_IsAircraftSelected(aircraft)
Definition: cp_geoscape.h:51