UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_event.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
26#include "../../DateTime.h"
27#include "../../cl_shared.h"
30#include "cp_campaign.h"
31#include "cp_time.h"
32#include "cp_xvi.h"
33#include "cp_event_callbacks.h"
35
36static linkedList_t* eventMails = nullptr;
37
46{
47 int i;
48
49 for (i = 0; i < ccs.numEventMails; i++) {
50 eventMail_t* mail = &ccs.eventMails[i];
51 if (Q_streq(mail->id, id))
52 return mail;
53 }
54
56 if (Q_streq(listMail->id, id))
57 return listMail;
58 }
59
60 return nullptr;
61}
62
68{
69 /* the pointers are not freed, this is done with the
70 * pool clear in CP_ResetCampaignData */
71 cgi->LIST_Delete(&eventMails);
72}
73
75static const value_t eventMail_vals[] = {
76 {"subject", V_TRANSLATION_STRING, offsetof(eventMail_t, subject), 0},
77 {"from", V_TRANSLATION_STRING, offsetof(eventMail_t, from), 0},
78 {"to", V_TRANSLATION_STRING, offsetof(eventMail_t, to), 0},
79 {"cc", V_TRANSLATION_STRING, offsetof(eventMail_t, cc), 0},
80 {"date", V_TRANSLATION_STRING, offsetof(eventMail_t, date), 0},
81 {"body", V_TRANSLATION_STRING, offsetof(eventMail_t, body), 0},
82 {"icon", V_HUNK_STRING, offsetof(eventMail_t, icon), 0},
83 {"model", V_HUNK_STRING, offsetof(eventMail_t, model), 0},
84 {"skipmessage", V_BOOL, offsetof(eventMail_t, skipMessage), MEMBER_SIZEOF(eventMail_t, skipMessage)},
85
86 {nullptr, V_NULL, 0, 0}
87};
88
93void CL_ParseEventMails (const char* name, const char** text)
94{
95 eventMail_t* eventMail;
96
97 if (ccs.numEventMails >= MAX_EVENTMAILS) {
98 cgi->Com_Printf("CL_ParseEventMails: mail def \"%s\" with same name found, second ignored\n", name);
99 return;
100 }
101
102 /* initialize the eventMail */
103 eventMail = &ccs.eventMails[ccs.numEventMails++];
104 OBJZERO(*eventMail);
105
106 cgi->Com_DPrintf(DEBUG_CLIENT, "...found eventMail %s\n", name);
107
108 eventMail->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
109
110 cgi->Com_ParseBlock(name, text, eventMail, eventMail_vals, cp_campaignPool);
111}
112
114{
115 const campaignEvents_t* events = campaign->events;
116 int i;
117
118 /* no events for the current campaign */
119 if (!events)
120 return;
121
122 /* no events in that definition */
123 if (!events->numCampaignEvents)
124 return;
125
126 for (i = 0; i < events->numCampaignEvents; i++) {
127 const campaignEvent_t* event = &events->campaignEvents[i];
128 if (event->interest <= ccs.overallInterest) {
130 }
131 }
132}
133
140{
141 for (int i = 0; i < ccs.numCampaignEventDefinitions; i++) {
142 const campaignEvents_t* events = &ccs.campaignEvents[i];
143 if (Q_streq(events->id, name)) {
144 for (int j = 0; j < events->numCampaignEvents; j++) {
145 const campaignEvent_t* event = &events->campaignEvents[j];
146 if (!RS_GetTechByID(event->tech))
147 Sys_Error("Illegal tech '%s' given in events '%s'", event->tech, events->id);
148 }
149 return events;
150 }
151 }
152
153 return nullptr;
154}
155
156static int CP_CheckTriggerEvent (const char* expression, const void* userdata)
157{
158 if (Q_strnull(expression))
159 return -1;
160
161 const char* type;
162
163 /* check that a particular installation type is built already */
164 type = Q_strstart(expression, "installation");
165 if (type != nullptr) {
166 if (strlen(type) <= 1)
167 return -1;
168 char value[MAX_VAR];
169 Q_strncpyz(value, type + 1, sizeof(value));
170 value[strlen(value) - 1] = '\0';
171 const installationType_t insType = INS_GetType(value);
173 return 1;
174 return 0;
175 }
176
177 /* check whether a particular ufo was detected */
178 type = Q_strstart(expression, "ufo");
179 if (type != nullptr) {
180 if (strlen(type) <= 1)
181 return -1;
182 char value[MAX_VAR];
183 Q_strncpyz(value, type + 1, sizeof(value));
184 value[strlen(value) - 1] = '\0';
185 const char* detectedUFO = static_cast<const char*>(userdata);
186 if (Q_strnull(detectedUFO))
187 return -1;
188 return Q_streq(detectedUFO, value);
189 }
190
191 /* check that the given xvi level is reached in any nation */
192 type = Q_strstart(expression, "xvi");
193 if (type != nullptr) {
194 int xvi;
195 if (sscanf(type, "[%i]", &xvi) != 1)
196 return -1;
197 /* check for XVI infection rate */
198 NAT_Foreach(nation) {
199 const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
200 if (stats->xviInfection >= xvi)
201 return 1;
202 }
203 return 0;
204 }
205
206 /* check that the given tech is already researched */
207 type = Q_strstart(expression, "researched");
208 if (type != nullptr) {
209 if (strlen(type) <= 1)
210 return -1;
211 char value[MAX_VAR];
212 Q_strncpyz(value, type + 1, sizeof(value));
213 value[strlen(value) - 1] = '\0';
214 technology_t* tech = RS_GetTechByID(value);
215 if (tech == nullptr)
216 return -1;
217 if (RS_IsResearched_ptr(tech))
218 return 1;
219 return 0;
220 }
221
222 /* check for nation happiness - also see the lost conditions in the campaign */
223 type = Q_strstart(expression, "nationhappiness");
224 if (type != nullptr) {
225 int nationAmount;
226
227 if (sscanf(type, "[%i]", &nationAmount) != 1)
228 return -1;
229
230 int nationBelowLimit = 0;
231 NAT_Foreach(nation) {
232 const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
233 if (stats->happiness < ccs.curCampaign->minhappiness) {
234 nationBelowLimit++;
235 if (nationBelowLimit >= nationAmount)
236 return 1;
237 }
238 }
239 return 0;
240 }
241
242 /* check that the given average xvi level is reached */
243 type = Q_strstart(expression, "averagexvi");
244 if (type != nullptr) {
245 int xvipercent;
246 if (sscanf(type, "[%i]", &xvipercent) != 1)
247 return -1;
248 if (xvipercent < 0 || xvipercent > 100)
249 return -1;
250 const int xvi = CP_GetAverageXVIRate();
251 if (xvi > ccs.curCampaign->maxAllowedXVIRateUntilLost * xvipercent / 100)
252 return 1;
253 return 0;
254 }
255
256 type = Q_strstart(expression, "difficulty");
257 if (type != nullptr) {
258 int difficulty;
259 if (sscanf(type, "[%i]", &difficulty) != 1)
260 return -1;
261 return ccs.curCampaign->difficulty == difficulty;
262 }
263
264 /* check that these days have passed in the campaign */
265 type = Q_strstart(expression, "days");
266 if (type != nullptr) {
267 int days;
268 if (sscanf(type, "[%i]", &days) != 1)
269 return -1;
270 if ((ccs.curCampaign->date + DateTime(days, 0)) <= ccs.date)
271 return 1;
272 return 0;
273 }
274
275 type = Q_strstart(expression, "alienscaptured");
276 if (type != nullptr) {
277 if (ccs.campaignStats.capturedAliens > 0)
278 return 1;
279 return 0;
280 }
281
282 type = Q_strstart(expression, "samsitearmed");
283 if (type != nullptr) {
285 return 1;
286
288 if (installation->installationStatus == INSTALLATION_WORKING) {
289 for (int i = 0; i < installation->installationTemplate->maxBatteries; i++) {
290 const aircraftSlot_t* slot = &installation->batteries[i].slot;
291 if (slot->ammoLeft > 0)
292 return 1;
293 }
294 }
295 }
296
297 return 0;
298 }
299
300 cgi->Com_Printf("unknown expression given: '%s'\n", expression);
301
302 return -1;
303}
304
311{
312 int i;
313
314 for (i = 0; i < ccs.numCampaignTriggerEvents; i++) {
315 campaignTriggerEvent_t* event = &ccs.campaignTriggerEvents[i];
316 if (event->type != type || (!event->active && event->reactivate == nullptr))
317 continue;
318
319 if (event->active) {
320 if (!cgi->BEP_Evaluate(event->require, CP_CheckTriggerEvent, userdata))
321 continue;
322 if (Q_strvalid(event->command)) {
324 cgi->Cmd_ExecuteString("%s", event->command);
326 }
327
328 if (event->once) {
329 event->active = false;
330 }
331 } else {
332 event->active = cgi->BEP_Evaluate(event->reactivate, CP_CheckTriggerEvent, userdata);
333 }
334 }
335}
336
338static const value_t event_vals[] = {
340 {"require", V_HUNK_STRING, offsetof(campaignTriggerEvent_t, require), 0},
341 {"reactivate", V_HUNK_STRING, offsetof(campaignTriggerEvent_t, reactivate), 0},
342 {"command", V_HUNK_STRING, offsetof(campaignTriggerEvent_t, command), 0},
343 {"once", V_BOOL, offsetof(campaignTriggerEvent_t, once), MEMBER_SIZEOF(campaignTriggerEvent_t, once)},
344
345 {nullptr, V_NULL, 0, 0}
346};
347
348#define EVENTCONSTANTS_NAMESPACE "eventTrigger::"
351 {EVENTCONSTANTS_NAMESPACE "ufo_detection", UFO_DETECTION},
352 {EVENTCONSTANTS_NAMESPACE "captured_aliens_died", CAPTURED_ALIENS_DIED},
353 {EVENTCONSTANTS_NAMESPACE "captured_aliens", CAPTURED_ALIENS},
354 {EVENTCONSTANTS_NAMESPACE "alienbase_discovered", ALIENBASE_DISCOVERED},
355
356 {nullptr, -1}
357};
358
359void CP_ParseEventTrigger (const char* name, const char** text)
360{
361 const char* errhead = "CP_ParseEventTrigger: unexpected end of file (event ";
362 const char* token;
363
364 if (ccs.numCampaignTriggerEvents >= MAX_CAMPAIGN_TRIGGER_EVENTS) {
365 cgi->Com_Printf("CP_ParseEventTrigger: max event def limit hit\n");
366 return;
367 }
368
369 token = cgi->Com_EParse(text, errhead, name);
370 if (!*text)
371 return;
372
373 if (!*text || token[0] != '{') {
374 cgi->Com_Printf("CP_ParseEventTrigger: event def '%s' without body ignored\n", name);
375 return;
376 }
377
378 cgi->Com_RegisterConstList(eventConstants);
379
380 campaignTriggerEvent_t* event = &ccs.campaignTriggerEvents[ccs.numCampaignTriggerEvents];
381 OBJZERO(*event);
382 cgi->Com_DPrintf(DEBUG_CLIENT, "...found event %s\n", name);
383 ccs.numCampaignTriggerEvents++;
384 event->active = true;
385 event->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
386
387 do {
388 token = cgi->Com_EParse(text, errhead, name);
389 if (!*text)
390 break;
391 if (*token == '}')
392 break;
393 if (!cgi->Com_ParseBlockToken(name, text, event, event_vals, cp_campaignPool, token)) {
394 cgi->Com_Printf("CP_ParseEventTrigger: Ignoring unknown event value '%s'\n", token);
395 }
396 } while (*text);
397
398 cgi->Com_UnregisterConstList(eventConstants);
399}
400
402{
403 xmlNode_t* n = cgi->XML_AddNode(p, SAVE_TRIGGEREVENTS_TRIGGEREVENTS);
404 int i;
405
406 for (i = 0; i < ccs.numCampaignTriggerEvents; i++) {
407 const campaignTriggerEvent_t* event = &ccs.campaignTriggerEvents[i];
408 if (event->active)
409 continue;
410 xmlNode_t* s = cgi->XML_AddNode(n, SAVE_TRIGGEREVENTS_TRIGGEREVENT);
411
412 cgi->XML_AddString(s, SAVE_TRIGGEREVENTS_NAME, event->id);
413 cgi->XML_AddBool(s, SAVE_TRIGGEREVENTS_STATE, event->active);
414 }
415
416 return true;
417}
418
420{
421 xmlNode_t* n, *s;
422
423 n = cgi->XML_GetNode(p, SAVE_TRIGGEREVENTS_TRIGGEREVENTS);
424 if (!n)
425 return true;
426
427 for (s = cgi->XML_GetNode(n, SAVE_TRIGGEREVENTS_TRIGGEREVENT); s; s = cgi->XML_GetNextNode(s, n, SAVE_TRIGGEREVENTS_TRIGGEREVENT)) {
428 const char* id = cgi->XML_GetString(s, SAVE_TRIGGEREVENTS_NAME);
429 const bool state = cgi->XML_GetBool(s, SAVE_TRIGGEREVENTS_STATE, true);
430
431 int i;
432 for (i = 0; i < ccs.numCampaignTriggerEvents; i++) {
433 campaignTriggerEvent_t* event = &ccs.campaignTriggerEvents[i];
434 if (Q_streq(event->id, id)) {
435 event->active = state;
436 break;
437 }
438 }
439 }
440
441 return true;
442}
443
448void CL_ParseCampaignEvents (const char* name, const char** text)
449{
450 const char* errhead = "CL_ParseCampaignEvents: unexpected end of file (events ";
451 const char* token;
453
454 if (ccs.numCampaignEventDefinitions >= MAX_CAMPAIGNS) {
455 cgi->Com_Printf("CL_ParseCampaignEvents: max events def limit hit\n");
456 return;
457 }
458
459 token = cgi->Com_EParse(text, errhead, name);
460 if (!*text)
461 return;
462
463 if (!*text || token[0] != '{') {
464 cgi->Com_Printf("CL_ParseCampaignEvents: events def '%s' without body ignored\n", name);
465 return;
466 }
467
468 events = &ccs.campaignEvents[ccs.numCampaignEventDefinitions];
469 OBJZERO(*events);
470 cgi->Com_DPrintf(DEBUG_CLIENT, "...found events %s\n", name);
471 events->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
472 ccs.numCampaignEventDefinitions++;
473
474 do {
475 campaignEvent_t* event;
476 token = cgi->Com_EParse(text, errhead, name);
477 if (!*text)
478 break;
479 if (*token == '}')
480 break;
481
482 if (events->numCampaignEvents >= MAX_CAMPAIGNEVENTS) {
483 cgi->Com_Printf("CL_ParseCampaignEvents: max events per event definition limit hit\n");
484 return;
485 }
486
487 /* initialize the eventMail */
488 event = &events->campaignEvents[events->numCampaignEvents++];
489 OBJZERO(*event);
490
491 event->tech = cgi->PoolStrDup(token, cp_campaignPool, 0);
492
493 token = cgi->Com_EParse(text, errhead, name);
494 if (!*text)
495 return;
496
497 cgi->Com_EParseValue(event, token, V_INT, offsetof(campaignEvent_t, interest), sizeof(int));
498
499 if (event->interest < 0)
500 Sys_Error("Illegal interest value in events definition '%s' for tech '%s'", events->id, event->tech);
501 } while (*text);
502}
503
507void CL_EventAddMail (const char* eventMailId)
508{
509 eventMail_t* eventMail = CL_GetEventMail(eventMailId);
510 if (!eventMail) {
511 cgi->Com_Printf("CL_EventAddMail: Could not find eventmail with id '%s'\n", eventMailId);
512 return;
513 }
514
515 if (eventMail->sent) {
516 return;
517 }
518
519 if (!eventMail->from || !eventMail->to || !eventMail->subject || !eventMail->body) {
520 cgi->Com_Printf("CL_EventAddMail: mail with id '%s' has incomplete data\n", eventMailId);
521 return;
522 }
523
524 if (!eventMail->date) {
525 dateLong_t date;
526 char dateBuf[MAX_VAR] = "";
527
528 CP_DateConvertLong(ccs.date, &date);
529 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"),
530 date.year, Date_GetMonthName(date.month - 1), date.day);
531 eventMail->date = cgi->PoolStrDup(dateBuf, cp_campaignPool, 0);
532 }
533
534 eventMail->sent = true;
535
536 if (!eventMail->skipMessage) {
537 uiMessageListNodeMessage_t* m = MS_AddNewMessage("", va(_("You've got a new mail: %s"), _(eventMail->subject)), MSG_EVENT);
538 if (m)
539 m->eventMail = eventMail;
540 else
541 cgi->Com_Printf("CL_EventAddMail: Could not add message with id: %s\n", eventMailId);
542 }
543
544 UP_OpenEventMail(eventMailId);
545}
546
554{
555 if (cgi->Cmd_Argc() < 2) {
556 cgi->Com_Printf("Usage: %s <event_mail_id>\n", cgi->Cmd_Argv(0));
557 return;
558 }
559
560 CL_EventAddMail(cgi->Cmd_Argv(1));
561}
DateTime class definition.
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
Class describing a point of time.
Definition DateTime.h:31
memPool_t * cp_campaignPool
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
#define MAX_CAMPAIGNS
Definition cp_campaign.h:31
const campaignEvents_t * CP_GetEventsByID(const char *name)
Definition cp_event.cpp:139
bool CP_TriggerEventLoadXML(xmlNode_t *p)
Definition cp_event.cpp:419
eventMail_t * CL_GetEventMail(const char *id)
Searches all event mails for a given id.
Definition cp_event.cpp:45
void CL_EventAddMail(const char *eventMailId)
Adds the event mail to the message stack. This message is going to be added to the savegame.
Definition cp_event.cpp:507
static linkedList_t * eventMails
Definition cp_event.cpp:36
static const constListEntry_t eventConstants[]
Definition cp_event.cpp:349
void CP_CheckCampaignEvents(campaign_t *campaign)
Definition cp_event.cpp:113
static int CP_CheckTriggerEvent(const char *expression, const void *userdata)
Definition cp_event.cpp:156
static const value_t event_vals[]
Valid event mail parameters.
Definition cp_event.cpp:338
void CL_ParseEventMails(const char *name, const char **text)
Definition cp_event.cpp:93
void CL_ParseCampaignEvents(const char *name, const char **text)
Definition cp_event.cpp:448
#define EVENTCONSTANTS_NAMESPACE
Definition cp_event.cpp:348
void CL_EventAddMail_f(void)
Definition cp_event.cpp:553
void CP_ParseEventTrigger(const char *name, const char **text)
Definition cp_event.cpp:359
void CP_FreeDynamicEventMail(void)
Make sure, that the linked list is freed with every new game.
Definition cp_event.cpp:67
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition cp_event.cpp:310
bool CP_TriggerEventSaveXML(xmlNode_t *p)
Definition cp_event.cpp:401
static const value_t eventMail_vals[]
Valid event mail parameters.
Definition cp_event.cpp:75
#define MAX_CAMPAIGN_TRIGGER_EVENTS
Definition cp_event.h:96
campaignTriggerEventType_t
events that are triggered by the campaign
Definition cp_event.h:78
@ UFO_DETECTION
Definition cp_event.h:80
@ ALIENBASE_DISCOVERED
Definition cp_event.h:83
@ CAPTURED_ALIENS
Definition cp_event.h:82
@ NEW_DAY
Definition cp_event.h:79
@ CAPTURED_ALIENS_DIED
Definition cp_event.h:81
#define MAX_EVENTMAILS
Definition cp_event.h:28
#define MAX_CAMPAIGNEVENTS
Definition cp_event.h:29
void CP_CampaignTriggerFunctions(bool add)
Add/Remove temporary mission trigger functions.
bool INS_HasType(installationType_t type, installationStatus_t status)
Checks whether the given installation type is available.
installationType_t INS_GetType(const char *type)
installationType_t
@ INSTALLATION_DEFENCE
#define INS_ForeachOfType(var, installationType)
@ INSTALLATION_NOT_USED
@ INSTALLATION_WORKING
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.
@ MSG_EVENT
Definition cp_messages.h:51
const nationInfo_t * NAT_GetCurrentMonthInfo(const nation_t *const nation)
Get the current month nation stats.
#define NAT_Foreach(var)
iterates trough nations
Definition cp_nation.h:80
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
bool RS_MarkStoryLineEventResearched(const char *techID)
void CP_DateConvertLong(const DateTime &date, dateLong_t *dateLong)
Converts a date from the engine in a (longer) human-readable format.
Definition cp_time.cpp:73
const char * Date_GetMonthName(int month)
Returns the short monthame to the given month index.
Definition cp_time.cpp:250
Campaign geoscape time header.
void UP_OpenEventMail(const char *eventMailID)
int CP_GetAverageXVIRate(void)
Return the average XVI rate.
Definition cp_xvi.cpp:163
Campaign XVI header.
#define DEBUG_CLIENT
Definition defines.h:59
const eventRegister_t events[]
List of functions to register nodes.
Definition e_main.cpp:92
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition list.h:41
static struct mdfour * m
Definition md4.cpp:35
Shared parsing functions.
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
XML tag constants for savegame.
#define SAVE_TRIGGEREVENTS_NAME
#define SAVE_TRIGGEREVENTS_STATE
#define SAVE_TRIGGEREVENTS_TRIGGEREVENT
#define SAVE_TRIGGEREVENTS_TRIGGEREVENTS
@ V_BOOL
Definition scripts.h:50
@ V_TRANSLATION_STRING
Definition scripts.h:59
@ V_HUNK_STRING
Definition scripts.h:69
@ V_NULL
Definition scripts.h:49
@ V_INT
Definition scripts.h:52
#define MEMBER_SIZEOF(TYPE, MEMBER)
Definition scripts.h:34
#define Q_strvalid(string)
Definition shared.h:141
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
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
slot of aircraft
Definition cp_aircraft.h:78
const campaignEvents_t * events
Defines campaign events when story related technologies should be researched.
Definition cp_event.h:64
list of script aliases to register
Definition scripts.h:231
Human readable time information in the game.
Definition cp_time.h:36
byte month
Definition cp_time.h:38
byte day
Definition cp_time.h:39
short year
Definition cp_time.h:37
available mails for a tech - mail and mail_pre in script files
Definition cp_event.h:38
bool skipMessage
Definition cp_event.h:52
char * to
Definition cp_event.h:41
char * date
Definition cp_event.h:46
char * from
Definition cp_event.h:40
char * subject
Definition cp_event.h:43
char * id
Definition cp_event.h:39
bool sent
Definition cp_event.h:51
char * body
Definition cp_event.h:47
Detailed information about the nation relationship (currently per month, but could be used elsewhere)...
Definition cp_nation.h:35
float happiness
Definition cp_nation.h:39
int xviInfection
Definition cp_nation.h:40
This is the technology parsed from research.ufo.
#define xmlNode_t
Definition xml.h:24