UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_messages.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "../../DateTime.h"
26#include "../../cl_shared.h"
27#include "cp_campaign.h"
28#include "cp_popup.h"
29#include "cp_messages.h"
30#include "cp_time.h"
31#include "save/save_messages.h"
32
34
41static void MS_TimestampedText (char* text, uiMessageListNodeMessage_t* message, size_t textsize)
42{
43 dateLong_t date;
44 CP_DateConvertLong(message->date, &date);
45 Com_sprintf(text, textsize, _("%i %s %02i, %02i:%02i: "), date.year,
46 Date_GetMonthName(date.month - 1), date.day, date.hour, date.min);
47}
48
63uiMessageListNodeMessage_t* MS_AddNewMessage (const char* title, const char* text, messageType_t type, technology_t* pedia, bool popup, bool playSound)
64{
65 assert(type < MSG_MAX);
66
67 /* allocate memory for new message - delete this with every new game */
69
70 switch (type) {
71 case MSG_DEBUG:
72 mess->iconName = "icons/message_debug";
73 break;
74 case MSG_INFO:
75 mess->iconName = "icons/message_info";
76 break;
77 case MSG_STANDARD:
78 mess->iconName = "icons/message_info";
79 break;
81 mess->iconName = "icons/message_research";
82 break;
84 mess->iconName = "icons/message_research";
85 break;
87 mess->iconName = "icons/message_research";
88 break;
90 mess->iconName = "icons/message_construction";
91 break;
92 case MSG_UFOSPOTTED:
93 mess->iconName = "icons/message_ufo";
94 break;
95 case MSG_TERRORSITE:
96 mess->iconName = "icons/message_ufo";
97 break;
98 case MSG_BASEATTACK:
99 mess->iconName = "icons/message_ufo";
100 break;
102 mess->iconName = "icons/message_transfer";
103 break;
104 case MSG_PROMOTION:
105 mess->iconName = "icons/message_promotion";
106 break;
107 case MSG_PRODUCTION:
108 mess->iconName = "icons/message_production";
109 break;
110 case MSG_DEATH:
111 mess->iconName = "icons/message_death";
112 break;
113 case MSG_CRASHSITE:
114 mess->iconName = "icons/message_ufo";
115 break;
116 case MSG_EVENT:
117 mess->iconName = "icons/message_info";
118 break;
119 default:
120 mess->iconName = "icons/message_info";
121 break;
122 }
123
124 /* push the new message at the beginning of the stack */
125 cgi->UI_MessageAddStack(mess);
126
127 mess->type = type;
128 mess->pedia = pedia; /* pointer to UFOpaedia entry */
129
130 mess->date = ccs.date;
131
132 Q_strncpyz(mess->title, title, sizeof(mess->title));
133 mess->text = cgi->PoolStrDup(text, cp_campaignPool, 0);
134
135 /* get formatted date text */
136 MS_TimestampedText(mess->timestamp, mess, sizeof(mess->timestamp));
137
138 /* they need to be translated already */
139 if (popup) {
141 CP_Popup(mess->title, "%s", mess->text);
142 }
143
144 if (playSound) {
145 const char* sound = nullptr;
146 switch (type) {
147 case MSG_DEBUG:
148 break;
149 case MSG_STANDARD:
150 sound = "geoscape/standard";
151 break;
152 case MSG_INFO:
154 case MSG_DEATH:
155 case MSG_CONSTRUCTION:
156 case MSG_PRODUCTION:
157 sound = "geoscape/info";
158 break;
161 assert(pedia);
163 case MSG_EVENT:
164 case MSG_NEWS:
165 /* reread the new mails in UP_GetUnreadMails */
166 ccs.numUnreadMails = -1;
167 sound = "geoscape/mail";
168 break;
169 case MSG_UFOLOST:
170 sound = "geoscape/ufolost";
171 break;
172 case MSG_UFOSPOTTED:
173 sound = "geoscape/ufospotted";
174 break;
175 case MSG_BASEATTACK:
176 sound = "geoscape/basealert";
177 break;
178 case MSG_TERRORSITE:
179 sound = "geoscape/alien-activity";
180 break;
181 case MSG_CRASHSITE:
182 sound = "geoscape/newmission";
183 break;
184 case MSG_PROMOTION:
185 sound = "geoscape/promotion";
186 break;
187 case MSG_MAX:
188 break;
189 }
190
191 cgi->S_StartLocalSample(sound, 1.0f);
192 }
193
194 return mess;
195}
196
204{
205 xmlNode_t* n;
206
207 if (!message)
208 return;
209
210 /* bottom up */
211 MS_MessageSaveXML(p, message->next);
212
213 /* don't save these message types */
214 if (message->type == MSG_INFO)
215 return;
216
217 cgi->Com_RegisterConstList(saveMessageConstants);
218 n = cgi->XML_AddNode(p, SAVE_MESSAGES_MESSAGE);
219 cgi->XML_AddString(n, SAVE_MESSAGES_TYPE, cgi->Com_GetConstVariable(SAVE_MESSAGETYPE_NAMESPACE, message->type));
220 cgi->XML_AddStringValue(n, SAVE_MESSAGES_TITLE, message->title);
221 cgi->XML_AddStringValue(n, SAVE_MESSAGES_TEXT, message->text);
222 /* store script id of event mail */
223 if (message->type == MSG_EVENT) {
224 cgi->XML_AddString(n, SAVE_MESSAGES_EVENTMAILID, message->eventMail->id);
225 cgi->XML_AddBoolValue(n, SAVE_MESSAGES_EVENTMAILREAD, message->eventMail->read);
226 }
227 if (message->pedia)
228 cgi->XML_AddString(n, SAVE_MESSAGES_PEDIAID, message->pedia->id);
229 cgi->XML_AddDate(n, SAVE_MESSAGES_DATE, message->date.getDateAsDays(), message->date.getTimeAsSeconds());
230 cgi->Com_UnregisterConstList(saveMessageConstants);
231}
232
239{
240 xmlNode_t* n = cgi->XML_AddNode(p, SAVE_MESSAGES_MESSAGES);
241
242 /* store message system items */
243 MS_MessageSaveXML(n, cgi->UI_MessageGetStack());
244 return true;
245}
246
254{
255 int i;
256 xmlNode_t* n, *sn;
257 n = cgi->XML_GetNode(p, SAVE_MESSAGES_MESSAGES);
258
259 if (!n)
260 return false;
261
262 /* we have to set this a little bit higher here, otherwise the samples that are played when adding
263 * a message to the stack would all played a few milliseconds after each other - that doesn't sound
264 * nice */
265 cgi->S_SetSampleRepeatRate(500);
266
267 cgi->Com_RegisterConstList(saveMessageConstants);
268 for (sn = cgi->XML_GetNode(n, SAVE_MESSAGES_MESSAGE), i = 0; sn; sn = cgi->XML_GetNextNode(sn, n, SAVE_MESSAGES_MESSAGE), i++) {
269 eventMail_t* mail;
270 const char* type = cgi->XML_GetString(sn, SAVE_MESSAGES_TYPE);
271 int mtype;
272 char title[MAX_VAR];
273 char text[MAX_MESSAGE_TEXT];
274 char id[MAX_VAR];
275 technology_t* tech = nullptr;
277
278 if (!cgi->Com_GetConstIntFromNamespace(SAVE_MESSAGETYPE_NAMESPACE, type, (int*) &mtype)) {
279 cgi->Com_Printf("Invalid message type '%s'\n", type);
280 continue;
281 }
282
283 /* can contain high bits due to utf8 */
284 Q_strncpyz(title, cgi->XML_GetString(sn, SAVE_MESSAGES_TITLE), sizeof(title));
285 Q_strncpyz(text, cgi->XML_GetString(sn, SAVE_MESSAGES_TEXT), sizeof(text));
286
287 if (mtype == MSG_EVENT) {
288 mail = CL_GetEventMail(cgi->XML_GetString(sn, SAVE_MESSAGES_EVENTMAILID));
289 if (mail)
290 mail->read = cgi->XML_GetBool(sn, SAVE_MESSAGES_EVENTMAILREAD, false);
291 } else
292 mail = nullptr;
293
294 /* event and not mail means, dynamic mail - we don't save or load them */
295 if (mtype == MSG_EVENT && !mail)
296 continue;
297 if (mtype == MSG_DEBUG && cgi->Cvar_GetInteger("developer") == 0)
298 continue;
299
300 Q_strncpyz(id, cgi->XML_GetString(sn, SAVE_MESSAGES_PEDIAID), sizeof(id));
301 if (id[0] != '\0')
302 tech = RS_GetTechByID(id);
303 if (!tech && (mtype == MSG_RESEARCH_PROPOSAL || mtype == MSG_RESEARCH_FINISHED)) {
305 continue;
306 }
307 mess = MS_AddNewMessage(title, text, (messageType_t)mtype, tech, false, false);
308 mess->eventMail = mail;
309 int date;
310 int time;
311 cgi->XML_GetDate(sn, SAVE_MESSAGES_DATE, &date, &time);
312 mess->date = DateTime(date, time);
313 /* redo timestamp text after setting date */
314 MS_TimestampedText(mess->timestamp, mess, sizeof(mess->timestamp));
315
316 if (mail) {
317 dateLong_t date;
318 char dateBuf[MAX_VAR] = "";
319
320 CP_DateConvertLong(mess->date, &date);
321 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"),
322 date.year, Date_GetMonthName(date.month - 1), date.day);
323 mail->date = cgi->PoolStrDup(dateBuf, cp_campaignPool, 0);
324 }
325 }
326 cgi->Com_UnregisterConstList(saveMessageConstants);
327
328 /* reset the sample repeat rate */
329 cgi->S_SetSampleRepeatRate(0);
330
331 return true;
332}
333
334void MS_MessageInit (void)
335{
336 MSO_Init();
337}
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
int getTimeAsSeconds() const
Return the time part of the DateTime as seconds.
Definition DateTime.cpp:54
int getDateAsDays() const
Return the date part of the DateTime as days.
Definition DateTime.cpp:46
memPool_t * cp_campaignPool
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
eventMail_t * CL_GetEventMail(const char *id)
Searches all event mails for a given id.
Definition cp_event.cpp:45
void MSO_Init(void)
bool MS_LoadXML(xmlNode_t *p)
Load callback for messages.
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.
static void MS_TimestampedText(char *text, uiMessageListNodeMessage_t *message, size_t textsize)
Returns formatted text of a message timestamp.
bool MS_SaveXML(xmlNode_t *p)
Save callback for messages.
static void MS_MessageSaveXML(xmlNode_t *p, uiMessageListNodeMessage_t *message)
Save a list of messages to xml.
char cp_messageBuffer[MAX_MESSAGE_TEXT]
void MS_MessageInit(void)
messageType_t
Definition cp_messages.h:32
@ MSG_CRASHSITE
Definition cp_messages.h:49
@ MSG_PRODUCTION
Definition cp_messages.h:46
@ MSG_PROMOTION
Definition cp_messages.h:45
@ MSG_CONSTRUCTION
Definition cp_messages.h:39
@ MSG_DEBUG
Definition cp_messages.h:33
@ MSG_TERRORSITE
Definition cp_messages.h:42
@ MSG_RESEARCH_FINISHED
Definition cp_messages.h:38
@ MSG_TRANSFERFINISHED
Definition cp_messages.h:44
@ MSG_DEATH
Definition cp_messages.h:48
@ MSG_UFOSPOTTED
Definition cp_messages.h:40
@ MSG_INFO
Definition cp_messages.h:34
@ MSG_RESEARCH_PROPOSAL
Definition cp_messages.h:36
@ MSG_EVENT
Definition cp_messages.h:51
@ MSG_UFOLOST
Definition cp_messages.h:41
@ MSG_STANDARD
Definition cp_messages.h:35
@ MSG_RESEARCH_HALTED
Definition cp_messages.h:37
@ MSG_BASEATTACK
Definition cp_messages.h:43
@ MSG_MAX
Definition cp_messages.h:53
@ MSG_NEWS
Definition cp_messages.h:47
#define MAX_MESSAGE_TEXT
Definition cp_messages.h:29
void CP_Popup(const char *title, const char *text,...)
Wrapper around UI_Popup.
Definition cp_popup.cpp:474
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
void CP_GameTimeStop(void)
Stop game time speed.
Definition cp_time.cpp:126
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.
#define Mem_PoolAllocType(type, pool)
Definition mem.h:43
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
XML tag constants for savegame.
#define SAVE_MESSAGES_TITLE
#define SAVE_MESSAGES_PEDIAID
#define SAVE_MESSAGES_EVENTMAILREAD
#define SAVE_MESSAGETYPE_NAMESPACE
#define SAVE_MESSAGES_TYPE
#define SAVE_MESSAGES_MESSAGE
#define SAVE_MESSAGES_MESSAGES
#define SAVE_MESSAGES_DATE
#define SAVE_MESSAGES_TEXT
#define SAVE_MESSAGES_EVENTMAILID
static const constListEntry_t saveMessageConstants[]
#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
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
Human readable time information in the game.
Definition cp_time.h:36
byte hour
Definition cp_time.h:40
byte month
Definition cp_time.h:38
byte day
Definition cp_time.h:39
byte min
Definition cp_time.h:41
short year
Definition cp_time.h:37
available mails for a tech - mail and mail_pre in script files
Definition cp_event.h:38
char * date
Definition cp_event.h:46
bool read
Definition cp_event.h:50
This is the technology parsed from research.ufo.
struct uiMessageListNodeMessage_s * next
#define xmlNode_t
Definition xml.h:24