UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_installation.cpp
Go to the documentation of this file.
1
6
7/*
8Copyright (C) 2002-2025 UFO: Alien Invasion.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25*/
26
27#include "../../DateTime.h"
28#include "../../cl_shared.h"
30#include "cp_campaign.h"
31#include "cp_mapfightequip.h"
32#include "cp_aircraft.h"
33#include "cp_missions.h"
34#include "cp_installation.h"
36
40int INS_GetCount (void)
41{
42 return cgi->LIST_Count(ccs.installations);
43}
44
46{
47 if (Q_streq(type, "samsite"))
49 else if (Q_streq(type, "ufoyard"))
51 else if (Q_streq(type, "radartower"))
52 return INSTALLATION_RADAR;
53 else if (Q_streq(type, "orbit"))
54 return INSTALLATION_ORBIT;
55
56 cgi->Com_Printf("unknown type given '%s'\n", type);
57 return INSTALLATION_RADAR;
58}
59
65{
66 INS_Foreach(installation) {
67 if (status == INSTALLATION_NOT_USED || installation->installationStatus == status)
68 return true;
69 }
70
71 return false;
72}
73
80{
81 INS_ForeachOfType(installation, type) {
82 if (status == INSTALLATION_NOT_USED || installation->installationStatus == status)
83 return true;
84 }
85
86 return false;
87}
88
95{
96 INS_Foreach(installation) {
97 if (installation->idx == idx)
98 return installation;
99 }
100
101 return nullptr;
102}
103
110{
111 int idx;
112
113 for (idx = 0; idx < ccs.numInstallationTemplates; idx++) {
114 const installationTemplate_t* t = &ccs.installationTemplates[idx];
115 if (Q_streq(t->id, id))
116 return t;
117 }
118
119 return nullptr;
120}
121
128{
129 int idx;
130
131 for (idx = 0; idx < ccs.numInstallationTemplates; idx++) {
132 const installationTemplate_t* t = &ccs.installationTemplates[idx];
133 if (t->type == type)
134 return t;
135 }
136
137 return nullptr;
138}
139
146installation_t* INS_Build (const installationTemplate_t* installationTemplate, const vec2_t pos, const char* name)
147{
148 installation_t installation;
149 const int newInstallationAlienInterest = 1.0f;
150
151 OBJZERO(installation);
152
153 Vector2Copy(pos, installation.pos);
154 Q_strncpyz(installation.name, name, sizeof(installation.name));
155 installation.idx = ccs.campaignStats.installationsBuilt;
157 installation.installationTemplate = installationTemplate;
158 installation.buildStart = ccs.date.getDateAsDays();
159
160 /* a new installation is not discovered (yet) */
161 installation.alienInterest = newInstallationAlienInterest;
162
163 /* intialise hit points */
164 installation.installationDamage = installation.installationTemplate->maxDamage;
165
166 /* Reset Radar */
167 RADAR_Initialise(&(installation.radar), 0.0f, 0.0f, 0.0f, false);
168
169 ccs.campaignStats.installationsBuilt++;
170 return &LIST_Add(&ccs.installations, installation);
171}
172
178{
179 if (!installation)
180 return;
181 /* Disable radar */
182 RADAR_UpdateInstallationRadarCoverage(installation, 0, 0);
183 /* Destroy stored UFOs */
184 if (installation->ufoCapacity.max > 0) {
185 installation->ufoCapacity.max = 0;
186 US_RemoveUFOsExceedingCapacity(installation);
187 }
189
190 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Installation %s was destroyed."), installation->name);
192
193 cgi->LIST_Remove(&ccs.installations, installation);
194 cgi->Cvar_Set("mn_installation_count", "%i", INS_GetCount());
195}
196
201{
202 INS_Foreach(installation) {
203 if (installation->selected)
204 return installation;
205 }
206
207 return nullptr;
208}
209
216{
217 INS_Foreach(ins)
218 ins->selected = (ins == installation);
219
220 if (installation) {
221 cgi->Cvar_Set("mn_installation_title", "%s", installation->name);
222 cgi->Cvar_Set("mn_installation_type", "%s", installation->installationTemplate->id);
223 } else {
224 cgi->Cvar_Set("mn_installation_title", "");
225 cgi->Cvar_Set("mn_installation_type", "");
226 }
227}
228
235static void INS_FinishInstallation (installation_t* installation)
236{
237 if (!installation)
238 cgi->Com_Error(ERR_DROP, "INS_FinishInstallation: No Installation.\n");
239 if (!installation->installationTemplate)
240 cgi->Com_Error(ERR_DROP, "INS_FinishInstallation: No Installation template.\n");
242 cgi->Com_DPrintf(DEBUG_CLIENT, "INS_FinishInstallation: Installation is not being built.\n");
243 return;
244 }
245
247 /* if Radar Tower */
249 /* if SAM Site */
250 installation->numBatteries = installation->installationTemplate->maxBatteries;
252 /* if UFO Yard */
253 installation->ufoCapacity.max = installation->installationTemplate->maxUFOsStored;
254}
255
256#ifdef DEBUG
263static void INS_InstallationList_f (void)
264{
265 INS_Foreach(installation) {
266 cgi->Com_Printf("Installation idx %i\n", installation->idx);
267 cgi->Com_Printf("Installation name %s\n", installation->name);
268 cgi->Com_Printf("Installation pos %.02f:%.02f\n", installation->pos[0], installation->pos[1]);
269 cgi->Com_Printf("Installation Alien interest %f\n", installation->alienInterest);
270
271 cgi->Com_Printf("\nInstallation sensorWidth %i\n", installation->radar.range);
272 cgi->Com_Printf("\nInstallation trackingWidth %i\n", installation->radar.trackingRange);
273 cgi->Com_Printf("Installation numSensoredAircraft %i\n\n", installation->radar.numUFOs);
274
275 cgi->Com_Printf("\nInstallation numBatteries %i\n", installation->numBatteries);
277
278 cgi->Com_Printf("\nInstallation stored UFOs %i/%i\n", installation->ufoCapacity.cur, installation->ufoCapacity.max);
280
281 cgi->Com_Printf("\n\n");
282 }
283}
284
288static void INS_ConstructionFinished_f (void)
289{
290 int idx = -1;
291
292 if (cgi->Cmd_Argc() == 2) {
293 idx = atoi(cgi->Cmd_Argv(1));
294 if (idx < 0) {
295 cgi->Com_Printf("Usage: %s [installationIDX]\nWithout parameter it builds up all.\n", cgi->Cmd_Argv(0));
296 return;
297 }
298 }
299
300 INS_Foreach(ins) {
301 if (idx >= 0 && ins->idx != idx)
302 continue;
303
305 }
306}
307#endif
308
315{
317 if (free && installation->ufoCapacity.cur >= installation->ufoCapacity.max)
318 continue;
319
320 return installation;
321 }
322
323 return nullptr;
324}
325
327#ifdef DEBUG
328 {"debug_listinstallation", INS_InstallationList_f, "Print installation information to the game console"},
329 {"debug_finishinstallation", INS_ConstructionFinished_f, "Finish construction of a specified or every installation"},
330#endif
331 {nullptr, nullptr, nullptr}
332};
333
337{
338 cgi->Cmd_TableAddList(debugInstallationCmds);
339}
340
344void INS_Shutdown (void)
345{
346 cgi->LIST_Delete(&ccs.installations);
347 cgi->Cmd_TableRemoveList(debugInstallationCmds);
348}
349
355{
356 INS_Foreach(installation) {
357 if (installation->installationStatus == INSTALLATION_UNDER_CONSTRUCTION
358 && installation->buildStart
359 && installation->buildStart + installation->installationTemplate->buildTime <= ccs.date.getDateAsDays()) {
360 INS_FinishInstallation(installation);
361
362 Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("Construction of installation %s finished."), installation->name);
364 }
365 }
366}
367
368static const value_t installation_vals[] = {
369 {"name", V_TRANSLATION_STRING, offsetof(installationTemplate_t, name), 0},
370 {"description", V_TRANSLATION_STRING, offsetof(installationTemplate_t, description), 0},
371 {"radar_range", V_INT, offsetof(installationTemplate_t, radarRange), MEMBER_SIZEOF(installationTemplate_t, radarRange)},
372 {"radar_tracking_range", V_INT, offsetof(installationTemplate_t, trackingRange), MEMBER_SIZEOF(installationTemplate_t, trackingRange)},
373 {"max_batteries", V_INT, offsetof(installationTemplate_t, maxBatteries), MEMBER_SIZEOF(installationTemplate_t, maxBatteries)},
374 {"max_ufo_stored", V_INT, offsetof(installationTemplate_t, maxUFOsStored), MEMBER_SIZEOF(installationTemplate_t, maxUFOsStored)},
375 {"max_damage", V_INT, offsetof(installationTemplate_t, maxDamage), MEMBER_SIZEOF(installationTemplate_t, maxDamage)},
376 {"cost", V_INT, offsetof(installationTemplate_t, cost), MEMBER_SIZEOF(installationTemplate_t, cost)},
377 {"buildtime", V_INT, offsetof(installationTemplate_t, buildTime), MEMBER_SIZEOF(installationTemplate_t, buildTime)},
378 {"once", V_BOOL, offsetof(installationTemplate_t, once), MEMBER_SIZEOF(installationTemplate_t, once)},
379 {"model", V_HUNK_STRING, offsetof(installationTemplate_t, model), 0},
380 {"image", V_HUNK_STRING, offsetof(installationTemplate_t, image), 0},
381
382 {nullptr, V_NULL, 0, 0}
383};
384
392void INS_ParseInstallations (const char* name, const char** text)
393{
394 /* get id list body */
395 const char* token = Com_Parse(text);
396 if (!*text || *token != '{') {
397 cgi->Com_Printf("INS_ParseInstallations: installation \"%s\" without body ignored\n", name);
398 return;
399 }
400
401 if (!name) {
402 cgi->Com_Printf("INS_ParseInstallations: installation name not specified.\n");
403 return;
404 }
405
406 if (ccs.numInstallationTemplates >= MAX_INSTALLATION_TEMPLATES) {
407 cgi->Com_Printf("INS_ParseInstallations: too many installation templates\n");
408 ccs.numInstallationTemplates = MAX_INSTALLATION_TEMPLATES; /* just in case it's bigger. */
409 return;
410 }
411
412 for (int i = 0; i < ccs.numInstallationTemplates; i++) {
413 if (Q_streq(ccs.installationTemplates[i].name, name)) {
414 cgi->Com_Printf("INS_ParseInstallations: Second installation with same name found (%s) - second ignored\n", name);
415 return;
416 }
417 }
418
419 /* new entry */
420 installationTemplate_t* installation = &ccs.installationTemplates[ccs.numInstallationTemplates];
421 OBJZERO(*installation);
422 installation->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
423 installation->type = INSTALLATION_RADAR;
424
425 cgi->Com_DPrintf(DEBUG_CLIENT, "...found installation %s\n", installation->id);
426
427 ccs.numInstallationTemplates++;
428 const char* errhead = "INS_ParseInstallations: unexpected end of file (names ";
429 do {
430 /* get the name type */
431 token = cgi->Com_EParse(text, errhead, name);
432 if (!*text)
433 break;
434 if (*token == '}')
435 break;
436
437 /* check for some standard values */
438 if (!cgi->Com_ParseBlockToken(name, text, installation, installation_vals, cp_campaignPool, token)) {
439 /* other values */
440 if (Q_streq(token, "type")) {
441 token = cgi->Com_EParse(text, errhead, name);
442 if (!*text)
443 return;
444
445 installation->type = INS_GetType(token);
446 }
447 }
448 } while (*text);
449}
450
452{
453 for (int i = 0; i < ccs.numInstallationTemplates; i++) {
454 installationTemplate_t* ins = &ccs.installationTemplates[i];
455 technology_t* techLink = RS_GetTechByProvided(ins->id);
456 if (techLink)
457 ins->tech = techLink;
458 }
459}
460
468{
469 xmlNode_t* n = cgi->XML_AddNode(p, SAVE_INSTALLATION_INSTALLATIONS);
470 cgi->Com_RegisterConstList(saveInstallationConstants);
471 INS_Foreach(inst) {
472 xmlNode_t* s, *ss;
473
474 s = cgi->XML_AddNode(n, SAVE_INSTALLATION_INSTALLATION);
475 cgi->XML_AddString(s, SAVE_INSTALLATION_TEMPLATEID, inst->installationTemplate->id);
476 cgi->XML_AddInt(s, SAVE_INSTALLATION_IDX, inst->idx);
477 cgi->XML_AddString(s, SAVE_INSTALLATION_NAME, inst->name);
478 cgi->XML_AddPos3(s, SAVE_INSTALLATION_POS, inst->pos);
479 cgi->XML_AddString(s, SAVE_INSTALLATION_STATUS, cgi->Com_GetConstVariable(SAVE_INSTALLATIONSTATUS_NAMESPACE, inst->installationStatus));
480 cgi->XML_AddInt(s, SAVE_INSTALLATION_DAMAGE, inst->installationDamage);
481 cgi->XML_AddFloat(s, SAVE_INSTALLATION_ALIENINTEREST, inst->alienInterest);
482 cgi->XML_AddInt(s, SAVE_INSTALLATION_BUILDSTART, inst->buildStart);
483
484 ss = cgi->XML_AddNode(s, SAVE_INSTALLATION_BATTERIES);
485 cgi->XML_AddIntValue(ss, SAVE_INSTALLATION_NUM, inst->numBatteries);
486 B_SaveBaseSlotsXML(inst->batteries, inst->numBatteries, ss);
487 }
488 cgi->Com_UnregisterConstList(saveInstallationConstants);
489 return true;
490}
491
500{
501 xmlNode_t* n = cgi->XML_GetNode(p, SAVE_INSTALLATION_INSTALLATIONS);
502 xmlNode_t* s;
503 bool success = true;
504
505 if (!n)
506 return false;
507
508 cgi->Com_RegisterConstList(saveInstallationConstants);
509 for (s = cgi->XML_GetNode(n, SAVE_INSTALLATION_INSTALLATION); s; s = cgi->XML_GetNextNode(s, n, SAVE_INSTALLATION_INSTALLATION)) {
510 xmlNode_t* ss;
511 installation_t inst;
512 const char* instID = cgi->XML_GetString(s, SAVE_INSTALLATION_TEMPLATEID);
513 const char* instStat = cgi->XML_GetString(s, SAVE_INSTALLATION_STATUS);
514
515 OBJZERO(inst);
516 inst.idx = cgi->XML_GetInt(s, SAVE_INSTALLATION_IDX, -1);
517 if (inst.idx < 0) {
518 cgi->Com_Printf("Invalid installation index %i\n", inst.idx);
519 success = false;
520 break;
521 }
522 const installationType_t type = INS_GetType(instID);
524 if (!inst.installationTemplate) {
525 cgi->Com_Printf("Could not find installation template '%s'\n", instID);
526 success = false;
527 break;
528 }
529
530 if (!cgi->Com_GetConstIntFromNamespace(SAVE_INSTALLATIONSTATUS_NAMESPACE, instStat, (int*) &inst.installationStatus)) {
531 cgi->Com_Printf("Invalid installation status '%s'\n", instStat);
532 success = false;
533 break;
534 }
535
536 Q_strncpyz(inst.name, cgi->XML_GetString(s, SAVE_INSTALLATION_NAME), sizeof(inst.name));
537 cgi->XML_GetPos3(s, SAVE_INSTALLATION_POS, inst.pos);
538
539 inst.installationDamage = cgi->XML_GetInt(s, SAVE_INSTALLATION_DAMAGE, 0);
540 inst.alienInterest = cgi->XML_GetFloat(s, SAVE_INSTALLATION_ALIENINTEREST, 0.0);
541 inst.buildStart = cgi->XML_GetInt(s, SAVE_INSTALLATION_BUILDSTART, 0);
542
543 /* Radar */
545 RADAR_Initialise(&(inst.radar), 0.0f, 0.0f, 1.0f, true);
548 /* UFO Yard */
550 } else {
551 inst.ufoCapacity.max = 0;
552 }
553 inst.ufoCapacity.cur = 0;
554
555 /* read battery slots */
556 ss = cgi->XML_GetNode(s, SAVE_INSTALLATION_BATTERIES);
557 if (!ss) {
558 cgi->Com_Printf("INS_LoadXML: Batteries not defined!\n");
559 success = false;
560 break;
561 }
562 inst.numBatteries = cgi->XML_GetInt(ss, SAVE_INSTALLATION_NUM, 0);
564 cgi->Com_Printf("Installation has more batteries than possible, using upper bound\n");
566 }
567
568 installation_t& instp = LIST_Add(&ccs.installations, inst);
570 B_LoadBaseSlotsXML(instp.batteries, instp.numBatteries, ss);
571 }
572 cgi->Com_UnregisterConstList(saveInstallationConstants);
573 cgi->Cvar_Set("mn_installation_count", "%i", INS_GetCount());
574
575 return success;
576}
DateTime class definition.
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define ERR_DROP
Definition common.h:211
Header file for aircraft stuff.
int B_LoadBaseSlotsXML(baseWeapon_t *weapons, int max, xmlNode_t *p)
Loads the missile and laser slots of a base or sam site.
Definition cp_base.cpp:2347
void B_SaveBaseSlotsXML(const baseWeapon_t *weapons, const int numWeapons, xmlNode_t *node)
Saves the missile and laser slots of a base or sam site.
Definition cp_base.cpp:2228
memPool_t * cp_campaignPool
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
void INS_DestroyInstallation(installation_t *installation)
Destroys an installation.
static void INS_FinishInstallation(installation_t *installation)
Finishes an installation.
installation_t * INS_Build(const installationTemplate_t *installationTemplate, const vec2_t pos, const char *name)
Build a new installation.
void INS_LinkTechnologies(void)
const installationTemplate_t * INS_GetInstallationTemplateByType(installationType_t type)
Returns the installation Template for a given installation type.
static const cmdList_t debugInstallationCmds[]
const installationTemplate_t * INS_GetInstallationTemplateByID(const char *id)
Returns the installation Template for a given installation ID.
bool INS_SaveXML(xmlNode_t *p)
Save callback for savegames in xml.
void INS_ParseInstallations(const char *name, const char **text)
Copies an entry from the installation description file into the list of installation templates.
installation_t * INS_GetCurrentSelectedInstallation(void)
Returns the current selected installation.
void INS_SetCurrentSelectedInstallation(const installation_t *installation)
Sets the currently selected installation.
bool INS_HasAny(installationStatus_t status)
Checks whether any installation is available.
installation_t * INS_GetFirstUFOYard(bool free)
returns the first installation with (free) ufostoring capacity
void INS_UpdateInstallationData(void)
Check if some installation are build.
bool INS_LoadXML(xmlNode_t *p)
Load callback for savegames.
int INS_GetCount(void)
Get number of installations.
installation_t * INS_GetByIDX(int idx)
Get installation by it's index.
void INS_InitStartup(void)
Resets console commands.
bool INS_HasType(installationType_t type, installationStatus_t status)
Checks whether the given installation type is available.
void INS_Shutdown(void)
Closing operations for installations subsystem.
installationType_t INS_GetType(const char *type)
static const value_t installation_vals[]
Header for installation management related stuff.
#define MAX_INSTALLATION_TEMPLATES
installationType_t
@ INSTALLATION_UFOYARD
@ INSTALLATION_ORBIT
@ INSTALLATION_DEFENCE
@ INSTALLATION_RADAR
#define INS_ForeachOfType(var, installationType)
#define INS_Foreach(var)
installationStatus_t
Possible installation states.
@ INSTALLATION_UNDER_CONSTRUCTION
@ INSTALLATION_NOT_USED
@ INSTALLATION_WORKING
void BDEF_InitialiseInstallationSlots(installation_t *installation)
Initialise all values of installation slot defence.
Header for slot management related stuff.
uiMessageListNodeMessage_t * MSO_CheckAddNewMessage(const notify_t messagecategory, const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup)
Adds a new message to message stack. It uses message settings to verify whether sound should be playe...
@ NT_INSTALLATION_DESTROY
@ NT_INSTALLATION_BUILDFINISH
char cp_messageBuffer[MAX_MESSAGE_TEXT]
@ MSG_CONSTRUCTION
Definition cp_messages.h:39
void CP_MissionNotifyInstallationDestroyed(const installation_t *installation)
Notify missions that an installation has been destroyed.
Campaign missions headers.
void RADAR_Initialise(radar_t *radar, float range, float trackingRange, float level, bool updateSourceRadarMap)
Set radar range to new value.
Definition cp_radar.cpp:239
void RADAR_InitialiseUFOs(radar_t *radar)
Reset UFO sensored on radar.
Definition cp_radar.cpp:265
void RADAR_UpdateInstallationRadarCoverage(installation_t *installation, const float radarRange, const float trackingRadarRange)
Update radar coverage when building/destroying new radar.
Definition cp_radar.cpp:311
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
void US_RemoveUFOsExceedingCapacity(installation_t *installation)
Removes ufos which are over the storing capacity.
#define DEBUG_CLIENT
Definition defines.h:59
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
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_INSTALLATION_BATTERIES
static const constListEntry_t saveInstallationConstants[]
#define SAVE_INSTALLATION_NAME
#define SAVE_INSTALLATION_ALIENINTEREST
#define SAVE_INSTALLATIONSTATUS_NAMESPACE
#define SAVE_INSTALLATION_INSTALLATIONS
#define SAVE_INSTALLATION_STATUS
#define SAVE_INSTALLATION_NUM
#define SAVE_INSTALLATION_IDX
#define SAVE_INSTALLATION_POS
#define SAVE_INSTALLATION_BUILDSTART
#define SAVE_INSTALLATION_DAMAGE
#define SAVE_INSTALLATION_INSTALLATION
#define SAVE_INSTALLATION_TEMPLATEID
@ 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_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
#define lengthof(x)
Definition shared.h:105
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
A installation with all it's data.
char name[MAX_VAR]
struct radar_s radar
const installationTemplate_t * installationTemplate
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
capacities_t ufoCapacity
installationStatus_t installationStatus
struct technology_s * tech
installationType_t type
This is the technology parsed from research.ufo.
vec_t vec2_t[2]
Definition ufotypes.h:38
#define Vector2Copy(src, dest)
Definition vector.h:52
#define xmlNode_t
Definition xml.h:24