UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_game_skirmish.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 
26 #include "../../cl_shared.h"
27 #include "../cl_game.h"
28 #include "cl_game_skirmish.h"
29 #include "../../ui/ui_data.h"
30 
31 static cvar_t* cl_equip;
32 static const cgame_import_t* cgi;
33 
35 
36 static void GAME_SK_InitMissionBriefing (const char** title, linkedList_t** victoryConditionsMsgIDs, linkedList_t** missionBriefingMsgIDs)
37 {
38  const mapDef_t* md = cgi->GAME_GetCurrentSelectedMap();
39  if (Q_strvalid(md->victoryCondition)) {
40  cgi->LIST_AddString(victoryConditionsMsgIDs, md->victoryCondition);
41  }
42  if (Q_strvalid(md->missionBriefing)) {
43  cgi->LIST_AddString(missionBriefingMsgIDs, md->missionBriefing);
44  }
45  if (Q_strvalid(md->description)) {
46  *title = _(md->description);
47  }
48 }
49 
50 static inline const char* GAME_SK_GetRandomMapAssemblyNameForCraft (const char* name)
51 {
52  return cgi->Com_GetRandomMapAssemblyNameForCraft(name);
53 }
54 
59 static void GAME_SK_SetMissionParameters (const mapDef_t* md)
60 {
61  cgi->Cvar_SetValue("ai_numcivilians", 8);
62  if (md->civTeam != nullptr)
63  cgi->Cvar_Set("ai_civilianteam", "%s", md->civTeam);
64  else
65  cgi->Cvar_Set("ai_civilianteam", "europe");
66 
67  cgi->Cvar_Set("sv_hurtaliens", "0");
68 
69  /* now store the alien teams in the shared csi struct to let the game dll
70  * have access to this data, too */
71  cgi->csi->numAlienTeams = 0;
72  for (int i = 0; i < cgi->csi->numTeamDefs; i++) {
73  const teamDef_t* td = &cgi->csi->teamDef[i];
74  if (CHRSH_IsTeamDefAlien(td)) {
75  cgi->csi->alienChrTemplates[cgi->csi->numAlienTeams] = nullptr;
76  cgi->csi->alienTeams[cgi->csi->numAlienTeams++] = td;
77  }
79  break;
80  }
81 }
82 
86 static void GAME_SK_Start_f (void)
87 {
88  if (cgi->GAME_IsTeamEmpty()) {
89  cgi->GAME_LoadDefaultTeam(false);
90  }
91 
92  if (cgi->GAME_IsTeamEmpty()) {
94  const char* ugvTeamDefID = "phalanx_ugv_phoenix";
95  const char* name = cgi->Cvar_GetString("cl_equip");
96  const equipDef_t* ed = cgi->INV_GetEquipmentDefinitionByID(name);
97  const size_t size = cgi->GAME_GetCharacterArraySize();
98  uint32_t maxSoldiers = cgi->Cvar_GetInteger("sv_maxsoldiersperplayer");
99  uint32_t ugvs = cgi->Cvar_GetInteger("cl_ugvs");
100 
101  if (maxSoldiers <= 0)
102  maxSoldiers = size;
103 
104  ugvs = std::min(ugvs, (uint32_t)(size - maxSoldiers));
105  cgi->Com_Printf("Starting skirmish with %i soldiers and %i ugvs\n", maxSoldiers, ugvs);
106  cgi->GAME_AutoTeam(name, maxSoldiers);
107  for (unsigned int i = 0; i < ugvs; i++)
108  cgi->GAME_AppendTeamMember(i + maxSoldiers, ugvTeamDefID, ed);
109  } else {
110  cgi->Com_Printf("Using already loaded team\n");
111  }
112 
113  const mapDef_t* md = cgi->GAME_GetCurrentSelectedMap();
114  if (!md)
115  return;
116 
118 
119  assert(md->mapTheme);
120 
121  cgi->Cbuf_AddText("map %s %s %s;", cgi->Cvar_GetInteger("mn_serverday") ? "day" : "night", md->mapTheme, md->params ? (const char*)cgi->LIST_GetRandom(md->params) : "");
122 }
123 
124 static void GAME_SK_Restart_f (void)
125 {
126  cgi->GAME_ReloadMode();
127  GAME_SK_Start_f();
128 }
129 
133 static void GAME_SK_ChangeEquip_f (void)
134 {
135  if (cgi->Cmd_Argc() < 2) {
136  cgi->Com_Printf("Usage: %s <cvarname>\n", cgi->Cmd_Argv(0));
137  return;
138  }
139 
140  const char* command = cgi->Cmd_Argv(0);
141  const char* cvarName = cgi->Cmd_Argv(1);
142 
144  if (Q_streq(command, "sk_prevequip")) {
145  type = BACKWARD;
146  } else if (Q_streq(command, "sk_nextequip")) {
147  type = FORWARD;
148  } else {
149  type = INIT;
150  }
151 
152  const equipDef_t* ed = cgi->GAME_ChangeEquip(cgi->cgameType->equipmentList, type, cgi->Cvar_GetString(cvarName));
153 
154  char cvarBuf[MAX_VAR];
155  Com_sprintf(cvarBuf, sizeof(cvarBuf), "%sname", cvarName);
156 
157  cgi->Cvar_Set(cvarName, "%s", ed->id);
158  cgi->Cvar_Set(cvarBuf, "_%s", ed->name);
159 }
160 
173 static void GAME_SK_Results (dbuffer* msg, int winner, int* numSpawned, int* numAlive, int numKilled[][MAX_TEAMS], int numStunned[][MAX_TEAMS], bool nextmap)
174 {
175  if (nextmap)
176  return;
177 
178  /* HACK: Change to the main menu now so cgame shutdown won't kill the results popup doing it */
179  cgi->UI_InitStack("main", "");
180 
181  if (winner == -1) {
182  cgi->UI_Popup(_("Game Drawn!"), "%s\n", _("The game was a draw!\n\nEnemies escaped."));
183  return;
184  }
185 
186  if (winner == 0) {
187  cgi->UI_Popup(_("Game Drawn!"), "%s\n", _("The game was a draw!\n\nNo survivors left on any side."));
188  return;
189  }
190 
191  const int team = cgi->GAME_GetCurrentTeam();
192  const int ownFriendlyFire = numKilled[team][team] + numKilled[TEAM_CIVILIAN][team];
193  const int ownLost = numSpawned[team] - numAlive[team] - ownFriendlyFire;
194  const int civFriendlyFire = numKilled[team][TEAM_CIVILIAN] + numKilled[TEAM_CIVILIAN][TEAM_CIVILIAN];
195  const int civLost = numSpawned[TEAM_CIVILIAN] - numAlive[TEAM_CIVILIAN] - civFriendlyFire;
196 
197  int enemiesStunned = 0;
198  for (int i = 0; i <= MAX_TEAMS; ++i) {
199  enemiesStunned += numStunned[i][TEAM_ALIEN];
200  }
201  const int enemiesKilled = numSpawned[TEAM_ALIEN] - numAlive[TEAM_ALIEN] - enemiesStunned;
202 
203  char resultText[1024];
204  Com_sprintf(resultText, sizeof(resultText),
205  _("\n%i of %i enemies killed, %i stunned, %i survived.\n"
206  "%i of %i team members survived, %i lost in action, %i friendly fire loses.\n"
207  "%i of %i civilians saved, %i civilian loses, %i friendly fire loses."),
208  enemiesKilled, numSpawned[TEAM_ALIEN], enemiesStunned, numAlive[TEAM_ALIEN],
209  numAlive[team], numSpawned[team], ownLost, ownFriendlyFire,
210  numAlive[TEAM_CIVILIAN], numSpawned[TEAM_CIVILIAN], civLost, civFriendlyFire);
211  if (winner == team) {
212  cgi->UI_Popup(_("Congratulations"), "%s\n%s\n", _("You won the game!"), resultText);
213  } else {
214  cgi->UI_Popup(_("Better luck next time"), "%s\n%s\n", _("You've lost the game!"), resultText);
215  }
216 
217  /* Ask the game mode to shutdown -- don't execute the shutdown here or we will crash! */
218  cgi->Cbuf_AddText("game_exit");
219 }
220 
226 static inline void GAME_SK_HideDropships (const linkedList_t* dropships)
227 {
228  const bool hide = (dropships == nullptr);
229  if (hide) {
230  cgi->UI_ExecuteConfunc("skirmish_hide_dropships true");
231  cgi->Cvar_Set("rm_drop", "%s", "");
232  } else {
233  const char* rma = GAME_SK_GetRandomMapAssemblyNameForCraft((const char*)dropships->data);
234  cgi->Cvar_Set("rm_drop", "%s", rma);
235  cgi->UI_UpdateInvisOptions(cgi->UI_GetOption(OPTION_DROPSHIPS), dropships);
236  cgi->UI_RegisterOption(OPTION_DROPSHIPS, cgi->UI_GetOption(OPTION_DROPSHIPS));
237 
238  cgi->UI_ExecuteConfunc("skirmish_hide_dropships false");
239  }
240 }
241 
247 static inline void GAME_SK_HideUFOs (const linkedList_t* ufos)
248 {
249  const bool hide = (ufos == nullptr);
250  if (hide) {
251  cgi->UI_ExecuteConfunc("skirmish_hide_ufos true");
252  cgi->Cvar_Set("rm_ufo", "%s", "");
253  } else {
254  const char* rma = GAME_SK_GetRandomMapAssemblyNameForCraft((const char*)ufos->data);
255  cgi->Cvar_Set("rm_ufo", "%s", rma);
256  cgi->UI_UpdateInvisOptions(cgi->UI_GetOption(OPTION_UFOS), ufos);
257  cgi->UI_RegisterOption(OPTION_UFOS, cgi->UI_GetOption(OPTION_UFOS));
258 
259  cgi->UI_ExecuteConfunc("skirmish_hide_ufos false");
260  }
261  cgi->Cvar_Set("rm_crashed", "%s", "");
262 }
263 
264 static const mapDef_t* GAME_SK_MapInfo (int step)
265 {
266  int i = 0;
267 
268  while (!cgi->GAME_GetCurrentSelectedMap()->singleplayer) {
269  i++;
270  cgi->GAME_SwitchCurrentSelectedMap(step ? step : 1);
271  if (i > 100000)
272  cgi->Com_Error(ERR_DROP, "no singleplayer map found");
273  }
274 
275  const mapDef_t* md = cgi->GAME_GetCurrentSelectedMap();
276 
277  cgi->Cvar_SetValue("ai_singleplayeraliens", md->maxAliens);
278 
279  if (md->mapTheme[0] == '.')
280  return nullptr;
281 
282  if (md->mapTheme[0] == '+') {
283  GAME_SK_HideUFOs(md->ufos);
285  } else {
286  GAME_SK_HideUFOs(nullptr);
287  GAME_SK_HideDropships(nullptr);
288  }
289 
290  return md;
291 }
292 
293 static void GAME_InitMenuOptions (void)
294 {
295  uiNode_t* ufoOptions = nullptr;
296  uiNode_t* aircraftOptions = nullptr;
297 
298  const short ufoIdsNum = cgi->Com_GetUFOIdsNum();
299  for (int i = 0; i < ufoIdsNum; i++) {
300  const char* shortName = cgi->Com_UFOTypeToShortName((ufoType_t)i);
301  cgi->UI_AddOption(&ufoOptions, shortName, shortName, GAME_SK_GetRandomMapAssemblyNameForCraft(shortName));
302  }
303  for (int i = 0; i < ufoIdsNum; i++) {
304  const char* shortName = cgi->Com_UFOCrashedTypeToShortName((ufoType_t)i);
305  cgi->UI_AddOption(&ufoOptions, shortName, shortName, GAME_SK_GetRandomMapAssemblyNameForCraft(shortName));
306  }
307  cgi->UI_RegisterOption(OPTION_UFOS, ufoOptions);
308 
309  const int maxDropShips = cgi->Com_GetDropShipIdsNum();
310  for (int i = 0; i < maxDropShips; i++) {
311  const char* shortName = cgi->Com_DropShipTypeToShortName((humanAircraftType_t)i);
312  cgi->UI_AddOption(&aircraftOptions, shortName, shortName, GAME_SK_GetRandomMapAssemblyNameForCraft(shortName));
313  }
314  cgi->UI_RegisterOption(OPTION_DROPSHIPS, aircraftOptions);
315 }
316 
317 static const cmdList_t skirmishCmds[] = {
318  {"sk_start", GAME_SK_Start_f, "Start the new skirmish game"},
319  {"sk_prevequip", GAME_SK_ChangeEquip_f, "Previous equipment definition"},
320  {"sk_nextequip", GAME_SK_ChangeEquip_f, "Next equipment definition"},
321  {"sk_initequip", GAME_SK_ChangeEquip_f, "Init equipment definition"},
322  {"game_go", GAME_SK_Restart_f, "Restart the skirmish mission"},
323  {nullptr, nullptr, nullptr}
324 };
325 static void GAME_SK_InitStartup (void)
326 {
327  cgi->Cvar_ForceSet("sv_maxclients", "1");
328  cl_equip = cgi->Cvar_Get("cl_equip", "multiplayer_initial", 0, "Equipment that is used for skirmish mode games");
329 
330  cgi->Cmd_TableAddList(skirmishCmds);
331 
333 }
334 
335 static void GAME_SK_Shutdown (void)
336 {
337  cgi->Cmd_TableRemoveList(skirmishCmds);
338  /* You really don't want this with campaign */
339  cgi->Cvar_ForceSet("g_endlessaliens", "0");
340 
341  cgi->UI_ResetData(OPTION_DROPSHIPS);
342  cgi->UI_ResetData(OPTION_UFOS);
343 
344  cgi->SV_Shutdown("Quitting server.", false);
345 }
346 
347 #ifndef HARD_LINKED_CGAME
349 #else
350 const cgame_export_t* GetCGameSkirmishAPI (const cgame_import_t* import)
351 #endif
352 {
353  static cgame_export_t e;
354 
355  OBJZERO(e);
356 
357  e.name ="Skirmish mode";
358  e.menu = "skirmish";
359  e.Init = GAME_SK_InitStartup;
360  e.Shutdown = GAME_SK_Shutdown;
362  e.Results = GAME_SK_Results;
363  e.InitMissionBriefing = GAME_SK_InitMissionBriefing;
364 
365  cgi = import;
366 
367  return &e;
368 }
static const cgame_import_t * cgi
const char * msg
Definition: cgame.h:320
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
static void GAME_SK_ChangeEquip_f(void)
Changed the given cvar to the next/prev equipment definition.
#define MAX_TEAMS
Definition: defines.h:98
#define TEAM_ALIEN
Definition: q_shared.h:63
short humanAircraftType_t
Definition: inv_shared.h:28
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
#define _(String)
Definition: cl_shared.h:43
void * data
Definition: list.h:31
void *IMPORT * LIST_GetRandom(linkedList_t *list)
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
short ufoType_t
Definition: scripts.h:146
csi_t * csi
Definition: cgame.h:100
bool CHRSH_IsTeamDefAlien(const teamDef_t *const td)
Check if a team definition is alien.
Definition: chr_shared.cpp:82
#define TEAM_CIVILIAN
Definition: q_shared.h:61
static void GAME_SK_Restart_f(void)
static void GAME_InitMenuOptions(void)
const char *IMPORT * Com_DropShipTypeToShortName(humanAircraftType_t type)
static void GAME_SK_HideUFOs(const linkedList_t *ufos)
Hide the ufo selection or show it with the ufos given in the parameter.
#define CGAME_HARD_LINKED_FUNCTIONS
Definition: cl_game.h:91
bool singleplayer
Definition: q_shared.h:481
const char *IMPORT * Cvar_GetString(const char *varName)
#define Q_strvalid(string)
Definition: shared.h:141
const char *IMPORT * Com_UFOCrashedTypeToShortName(ufoType_t type)
const teamDef_t * alienTeams[MAX_TEAMS_PER_MISSION]
Definition: q_shared.h:553
char * missionBriefing
Definition: q_shared.h:469
static void GAME_SK_SetMissionParameters(const mapDef_t *md)
Register some data in the shared client/server structs to ensure that e.g. every known alien race is ...
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
linkedList_t * equipmentList
Definition: cgame.h:88
#define ERR_DROP
Definition: common.h:211
const equipDef_t *IMPORT * GAME_ChangeEquip(const linkedList_t *equipmentList, changeEquipType_t changeType, const char *equipID)
GLsizei size
Definition: r_gl.h:152
#define OBJZERO(obj)
Definition: shared.h:178
const equipDef_t *IMPORT * INV_GetEquipmentDefinitionByID(const char *name)
#define MAX_VAR
Definition: shared.h:36
const mapDef_t *EXPORT * MapInfo(int step)
changeEquipType_t
Definition: cgame.h:92
const char *IMPORT * Com_UFOTypeToShortName(ufoType_t type)
static const char * GAME_SK_GetRandomMapAssemblyNameForCraft(const char *name)
linkedList_t * aircraft
Definition: q_shared.h:492
Definition: cmd.h:86
char * victoryCondition
Definition: q_shared.h:467
const equipDef_t * ed
Definition: cgame.h:138
static void GAME_SK_InitStartup(void)
teamDef_t teamDef[MAX_TEAMDEFS]
Definition: q_shared.h:548
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
cvar_t *IMPORT * Cvar_Get(const char *varName, const char *value, int flags, const char *desc)
char id[MAX_VAR]
Definition: inv_shared.h:606
int numAlienTeams
Definition: q_shared.h:555
const mapDef_t *IMPORT * GAME_GetCurrentSelectedMap(void)
static void GAME_SK_Results(dbuffer *msg, int winner, int *numSpawned, int *numAlive, int numKilled[][MAX_TEAMS], int numStunned[][MAX_TEAMS], bool nextmap)
After a mission was finished this function is called.
Definition: cgame.h:94
static void GAME_SK_Shutdown(void)
static cvar_t * cl_equip
char * mapTheme
Definition: q_shared.h:464
int numTeamDefs
Definition: q_shared.h:549
Definition: cgame.h:93
const char *IMPORT * Com_GetRandomMapAssemblyNameForCraft(const char *craftID)
Skirmish game type headers.
uiNode_t *IMPORT * UI_GetOption(int dataId)
const cgame_export_t * GetCGameAPI(const cgame_import_t *import)
QGL_EXTERN GLint i
Definition: r_gl.h:113
const cgameType_t * cgameType
Definition: cgame.h:102
static void GAME_SK_Start_f(void)
Starts a new skirmish game.
char * civTeam
Definition: q_shared.h:471
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
#define MAX_TEAMS_PER_MISSION
Definition: inv_shared.h:618
linkedList_t * ufos
Definition: q_shared.h:491
char * description
Definition: q_shared.h:466
const char * menu
Definition: cgame.h:39
static const mapDef_t * GAME_SK_MapInfo(int step)
#define Q_streq(a, b)
Definition: shared.h:136
const chrTemplate_t * alienChrTemplates[MAX_TEAMS_PER_MISSION]
Definition: q_shared.h:554
static CGAME_HARD_LINKED_FUNCTIONS void GAME_SK_InitMissionBriefing(const char **title, linkedList_t **victoryConditionsMsgIDs, linkedList_t **missionBriefingMsgIDs)
const char * name
Definition: inv_shared.h:607
const char uiNode_t *IMPORT * UI_AddOption(uiNode_t **tree, const char *name, const char *label, const char *value)
static const cmdList_t skirmishCmds[]
const char * name
Definition: cgame.h:38
const char *IMPORT * Cmd_Argv(int n)
cvar_t *IMPORT * Cvar_ForceSet(const char *varName, const char *value)
Definition: cgame.h:95
int maxAliens
Definition: q_shared.h:483
static void GAME_SK_HideDropships(const linkedList_t *dropships)
Hide the dropship selection or show it with the dropship given in the parameter.
linkedList_t * params
Definition: q_shared.h:465