UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_aircraft_callbacks.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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"
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
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
59 AIR_AircraftSelect(aircraft);
60}
61
68static 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));
81 if (aircraft != nullptr)
82 AIR_AircraftSelect(aircraft);
83 }
84}
85
89static 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 */
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
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;
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
229static 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
253static 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
289static 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));
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
335static 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));
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));
362 if (aircraft == nullptr)
363 return;
364
365 CL_DisplayHomebasePopup(aircraft, true);
366}
367
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
393static 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
412static 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
427{
428 cgi->Cmd_TableAddList(aircraftCallbacks);
429}
430
432{
433 cgi->Cmd_TableRemoveList(aircraftCallbacks);
434}
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define ERR_DROP
Definition common.h:211
void AIR_AircraftReturnToBase(aircraft_t *aircraft)
Calculates the way back to homebase for given aircraft and returns it.
Employee * AIR_GetPilot(const aircraft_t *aircraft)
Get pilot of an aircraft.
const char * AIR_AircraftStatusToName(const aircraft_t *aircraft)
Translates the aircraft status id to a translatable string.
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
bool AIR_SendAircraftToMission(aircraft_t *aircraft, mission_t *mission)
Sends the specified aircraft to specified mission.
int AIR_GetOperationRange(const aircraft_t *aircraft)
Calculates the range an aircraft can fly on the geoscape.
bool AIR_AircraftAllowed(const base_t *base)
Returns true if the current base is able to handle aircraft.
int AIR_AircraftMenuStatsValues(const int value, const int stat)
Some of the aircraft values needs special calculations when they are shown in the menus.
int AIR_GetTeamSize(const aircraft_t *aircraft)
Counts the number of soldiers in given aircraft.
bool AIR_BaseHasAircraft(const base_t *base)
Checks whether there is any aircraft assigned to the given base.
aircraft_t * AIR_GetAircraftFromBaseByIDXSafe(const base_t *base, int index)
bool AIR_IsAircraftInBase(const aircraft_t *aircraft)
Checks whether given aircraft is in its homebase.
aircraft_t * AIR_AircraftGetFromIDX(int aircraftIdx)
Returns aircraft for a given global index.
Header file for aircraft stuff.
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
#define MAX_AIRCRAFTSLOT
Definition cp_aircraft.h:75
@ AIR_IDLE
static void AIR_ShowChangeHomebaseAircraft_f(void)
Show change homebase popup.
static void AIR_AircraftFillList_f(void)
Update aircraft selection list with the current base aircraft names.
static const cmdList_t aircraftCallbacks[]
static void AIR_StopAircraft_f(void)
Stop aircraft on Geoscape.
void AIR_ShutdownCallbacks(void)
void AIR_InitCallbacks(void)
void AIR_AircraftSelect(aircraft_t *aircraft)
Sets aircraftCurrent and updates related cvars and menutexts.
static void AIR_GeoSelectAircraft_f(void)
Select aircraft on Geoscape.
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.
static void AIM_AircraftStart_f(void)
Starts an aircraft or stops the current mission and lets the aircraft idle around.
static void AIR_ShowAircraft_f(void)
Show aircraft in Base sections.
static void AIR_ChangeAircraftName_f(void)
Creates console command to change the name of an aircraft. Copies the value of the cvar mn_aircraftna...
static void AIM_SelectAircraft_f(void)
Select an aircraft from a base, by ID.
static void AIM_AircraftReturnToBase_f(void)
Script function for AIR_AircraftReturnToBase.
static void AIR_SendAircraftToMission_f(void)
Send aircraft to land on a mission.
Header file for menu related console command callbacks.
base_t * B_GetFoundedBaseByIDX(int baseIdx)
Array bound check for the base index.
Definition cp_base.cpp:326
base_t * B_GetCurrentSelectedBase(void)
returns the currently selected base
Definition cp_base.cpp:1578
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition cp_base.cpp:478
@ B_COMMAND
Definition cp_building.h:62
Header file for single player campaign control.
const cgame_import_t * cgi
@ EMPL_SOLDIER
Definition cp_employee.h:31
void GEO_SelectAircraft(aircraft_t *aircraft)
Select the specified aircraft on the geoscape.
Header for Geoscape management.
#define GEO_IsAircraftSelected(aircraft)
Definition cp_geoscape.h:51
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
Header for slot management related stuff.
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.
const char * MIS_GetName(const mission_t *mission)
Returns a short translated name for a mission.
mission_t * MIS_GetByIdx(int id)
Find mission corresponding to idx.
Campaign missions headers.
#define MIS_Foreach(var)
iterates through missions
@ STAGE_NOT_ACTIVE
Definition cp_missions.h:35
bool CL_DisplayHomebasePopup(aircraft_t *aircraft, bool alwaysDisplay)
Display the popup_homebase.
Definition cp_popup.cpp:67
void CP_Popup(const char *title, const char *text,...)
Wrapper around UI_Popup.
Definition cp_popup.cpp:474
void CP_UpdateActorAircraftVar(aircraft_t *aircraft, employeeType_t employeeType)
Updates data about teams in aircraft.
Definition cp_team.cpp:296
Team management for the campaign gametype headers.
#define DEBUG_CLIENT
Definition defines.h:59
@ AIR_STATS_FUELSIZE
Definition inv_shared.h:232
@ AIR_STATS_SPEED
Definition inv_shared.h:226
@ AIR_STATS_DAMAGE
Definition inv_shared.h:230
aircraftItemType_t
All different types of craft items.
Definition inv_shared.h:197
@ AC_ITEM_WEAPON
Definition inv_shared.h:201
@ AC_ITEM_ELECTRONICS
Definition inv_shared.h:205
@ AC_ITEM_SHIELD
Definition inv_shared.h:204
QGL_EXTERN GLuint index
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
bool Q_strnull(const char *string)
Definition shared.h:138
#define MAX_VAR
Definition shared.h:36
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
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition shared.cpp:475
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
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
An aircraft with all it's data.
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
int maxElectronics
struct base_s * homebase
aircraftStatus_t status
int stats[AIR_STATS_MAX]
aircraftSlot_t shield
char name[MAX_VAR]
aircraftSlot_t electronics[MAX_AIRCRAFTSLOT]
struct technology_s * tech
char * defaultName
slot of aircraft
Definition cp_aircraft.h:78
const objDef_t * item
Definition cp_aircraft.h:85
A base with all it's data.
Definition cp_base.h:84
aircraft_t * aircraftCurrent
Definition cp_base.h:100
mission definition
Definition cp_missions.h:86
@ TEXT_AIRCRAFT_INFO
Definition ui_dataids.h:41