UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_ufopedia.cpp
Go to the documentation of this file.
1
7
8/*
9Copyright (C) 2002-2025 UFO: Alien Invasion.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26*/
27
28#include "../../DateTime.h"
29#include "../../cl_shared.h"
30#include "../../cl_inventory.h"
31#include "../../ui/ui_dataids.h"
32#include "../../ui/node/ui_node_option.h" /* OPTIONEXTRADATA */
34#include "cp_campaign.h"
35#include "cp_mapfightequip.h"
36#include "cp_time.h"
37
40
43
46
47#define MAX_UPTEXT 4096
48static char upBuffer[MAX_UPTEXT];
49
54enum {
58
60};
62
70static bool UP_TechGetsDisplayed (const technology_t* tech)
71{
72 const objDef_t* item;
73
74 assert(tech);
75 /* virtual items are hidden */
77 if (item && item->isVirtual)
78 return false;
79 /* Is already researched OR has collected items OR (researchable AND have description)
80 * AND not a logical block AND not redirected */
81 return (RS_IsResearched_ptr(tech) || RS_Collected_(tech)
83 && tech->type != RS_LOGIC && !tech->redirect;
84}
85
90static void UP_ChangeDisplay (int newDisplay)
91{
92 if (newDisplay < UFOPEDIA_DISPLAYEND && newDisplay >= 0)
93 upDisplay = newDisplay;
94 else
95 cgi->Com_Printf("Error in UP_ChangeDisplay (%i)\n", newDisplay);
96
97 cgi->Cvar_SetValue("mn_uppreavailable", 0);
98
99 /* make sure, that we leave the mail header space */
100 cgi->UI_ResetData(TEXT_UFOPEDIA_MAILHEADER);
101 cgi->UI_ResetData(TEXT_UFOPEDIA_MAIL);
102 cgi->UI_ResetData(TEXT_UFOPEDIA_REQUIREMENT);
103 cgi->UI_ResetData(TEXT_ITEMDESCRIPTION);
104 cgi->UI_ResetData(TEXT_UFOPEDIA);
105
106 switch (upDisplay) {
108 currentChapter = nullptr;
109 upCurrentTech = nullptr;
110 cgi->Cvar_Set("mn_upmodel_top", "");
111 cgi->Cvar_Set("mn_upmodel_bottom", "");
112 cgi->Cvar_Set("mn_upimage_top", "base/empty");
113 cgi->UI_ExecuteConfunc("mn_up_empty");
114 cgi->Cvar_Set("mn_uptitle", _("UFOpaedia"));
115 break;
116 case UFOPEDIA_INDEX:
117 cgi->Cvar_Set("mn_upmodel_top", "");
118 cgi->Cvar_Set("mn_upmodel_bottom", "");
119 cgi->Cvar_Set("mn_upimage_top", "base/empty");
120 /* fall through */
121 case UFOPEDIA_ARTICLE:
122 cgi->UI_ExecuteConfunc("mn_up_article");
123 break;
124 }
125 cgi->Cvar_SetValue("mn_updisplay", upDisplay);
126}
127
133static const char* UP_AircraftStatToName (int stat)
134{
135 switch (stat) {
136 case AIR_STATS_SPEED:
137 return _("Cruising speed");
139 return _("Maximum speed");
140 case AIR_STATS_SHIELD:
141 return _("Armour");
142 case AIR_STATS_ECM:
143 return _("Evasion");
144 case AIR_STATS_DAMAGE:
145 return _("Hull strength");
147 return _("Accuracy");
149 return _("Fuel size");
150 case AIR_STATS_WRANGE:
151 return _("Weapon range");
153 return _("Antimatter need");
154 default:
155 return _("Unknown");
156 }
157}
158
165static void UP_DisplayTechTree (const technology_t* t)
166{
167 linkedList_t* upTechtree;
168 const requirements_t* required;
169
170 required = &t->requireAND;
171 upTechtree = nullptr;
172
173 if (required->numLinks <= 0)
174 cgi->LIST_AddString(&upTechtree, _("No requirements"));
175 else {
176 for (int i = 0; i < required->numLinks; i++) {
177 const requirement_t* req = &required->links[i];
178 if (req->type == RS_LINK_TECH) {
179 const technology_t* techRequired = req->link.tech;
180 if (!techRequired)
181 cgi->Com_Error(ERR_DROP, "Could not find the tech for '%s'", req->id);
182
185 if (!UP_TechGetsDisplayed(techRequired))
186 continue;
187
188 cgi->LIST_AddString(&upTechtree, _(techRequired->name));
189 }
190 }
191 }
192
193 /* and now register the buffer */
194 cgi->Cvar_Set("mn_uprequirement", "1");
195 cgi->UI_RegisterLinkedListText(TEXT_UFOPEDIA_REQUIREMENT, upTechtree);
196}
197
203{
205
206 if (!b) {
207 Com_sprintf(upBuffer, sizeof(upBuffer), _("Error - could not find building"));
208 } else {
209 Com_sprintf(upBuffer, sizeof(upBuffer), _("Needs:\t%s\n"), b->dependsBuilding ? _(b->dependsBuilding->name) : _("None"));
210 Q_strcat(upBuffer, sizeof(upBuffer), ngettext("Construction time:\t%i day\n", "Construction time:\t%i days\n", b->buildTime), b->buildTime);
211 Q_strcat(upBuffer, sizeof(upBuffer), _("Cost:\t%i c\n"), b->fixCosts);
212 Q_strcat(upBuffer, sizeof(upBuffer), _("Running costs:\t%i c\n"), b->varCosts);
213 }
214
215 cgi->Cvar_Set("mn_upmetadata", "1");
216 cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer);
218}
219
229{
230 static char itemText[1024];
231 const technology_t* tech;
232
233 /* Set menu text node content to null. */
234 cgi->INV_ItemDescription(nullptr);
235 *itemText = '\0';
236
237 /* no valid item id given */
238 if (!item) {
239 cgi->Cvar_Set("mn_item", "");
240 cgi->Cvar_Set("mn_itemname", "");
241 cgi->Cvar_Set("mn_upmodel_top", "");
242 cgi->UI_ResetData(TEXT_ITEMDESCRIPTION);
243 return;
244 }
245
246 tech = RS_GetTechForItem(item);
247 /* select item */
248 cgi->Cvar_Set("mn_item", "%s", item->id);
249 cgi->Cvar_Set("mn_itemname", "%s", _(item->name));
250 if (tech->mdl)
251 cgi->Cvar_Set("mn_upmodel_top", "%s", tech->mdl);
252 else
253 cgi->Cvar_Set("mn_upmodel_top", "");
254
255 /* set description text */
256 if (RS_IsResearched_ptr(tech)) {
257 const objDef_t* ammo = nullptr;
258
259 switch (item->craftitem.type) {
260 case AC_ITEM_WEAPON:
261 Q_strcat(itemText, sizeof(itemText), _("Weight:\t%s\n"), AII_WeightToName(AII_GetItemWeightBySize(item)));
262 break;
265 Q_strcat(itemText, sizeof(itemText), _("Weapon for air defence system\n"));
266 break;
267 case AC_ITEM_AMMO:
268 ammo = item;
269 break;
270 default:
271 break;
272 }
273
274 /* check ammo of weapons */
275 if (item->craftitem.type <= AC_ITEM_WEAPON) {
276 for(int i = 0; i < item->numAmmos; i++)
277 if (item->ammos[i]->isVirtual) {
278 ammo = item->ammos[i];
279 break;
280 }
281 }
282
283 if (ammo) {
284 /* We display the characteristics of this ammo */
285 Q_strcat(itemText, sizeof(itemText), _("Ammo:\t%i\n"), ammo->ammo);
286 if (!EQUAL(ammo->craftitem.weaponDamage, 0))
287 Q_strcat(itemText, sizeof(itemText), _("Damage:\t%i\n"), (int) ammo->craftitem.weaponDamage);
288 Q_strcat(itemText, sizeof(itemText), _("Reloading time:\t%i\n"), (int) ammo->craftitem.weaponDelay);
289 }
290 /* We write the range of the weapon */
291 if (!EQUAL(item->craftitem.stats[AIR_STATS_WRANGE], 0))
292 Q_strcat(itemText, sizeof(itemText), "%s:\t%i\n", UP_AircraftStatToName(AIR_STATS_WRANGE),
294
295 /* we scan all stats except weapon range */
296 for (int i = 0; i < AIR_STATS_MAX; i++) {
297 const char* statsName = UP_AircraftStatToName(i);
298 if (i == AIR_STATS_WRANGE)
299 continue;
300 if (item->craftitem.stats[i] > 2.0f)
301 Q_strcat(itemText, sizeof(itemText), "%s:\t+%i\n", statsName, AIR_AircraftMenuStatsValues(item->craftitem.stats[i], i));
302 else if (item->craftitem.stats[i] < -2.0f)
303 Q_strcat(itemText, sizeof(itemText), "%s:\t%i\n", statsName, AIR_AircraftMenuStatsValues(item->craftitem.stats[i], i));
304 else if (item->craftitem.stats[i] > 1.0f)
305 Q_strcat(itemText, sizeof(itemText), _("%s:\t+%i %%\n"), statsName, (int)(item->craftitem.stats[i] * 100) - 100);
306 else if (!EQUAL(item->craftitem.stats[i], 0))
307 Q_strcat(itemText, sizeof(itemText), _("%s:\t%i %%\n"), statsName, (int)(item->craftitem.stats[i] * 100) - 100);
308 }
309 } else {
310 Q_strcat(itemText, sizeof(itemText), _("Unknown - need to research this"));
311 }
312
313 cgi->Cvar_Set("mn_upmetadata", "1");
314 cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText);
315}
316
324{
325 cgi->INV_ItemDescription(nullptr);
326
327 /* ensure that the buffer is emptied in every case */
328 upBuffer[0] = '\0';
329
330 if (RS_IsResearched_ptr(tech)) {
331 const aircraft_t* aircraft = AIR_GetAircraft(tech->provides);
332 for (int i = 0; i < AIR_STATS_MAX; i++) {
333 switch (i) {
334 case AIR_STATS_DAMAGE:
335 Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i),
336 AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
337 break;
338 case AIR_STATS_SPEED:
339 /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */
340 Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i),
341 AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
342 break;
344 /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */
345 Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i),
346 AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
347 break;
349 Q_strcat(upBuffer, sizeof(upBuffer), _("Operational range:\t%i km\n"),
350 AIR_GetOperationRange(aircraft));
351 break;
353 Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i),
354 AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
355 break;
357 if (aircraft->stats[i] <= 0)
358 break;
359 Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i),
360 AIR_AircraftMenuStatsValues(aircraft->stats[i], i));
361 break;
362 default:
363 break;
364 }
365 }
366
367 const baseCapacities_t cap = AIR_GetHangarCapacityType(aircraft);
368 const buildingType_t buildingType = B_GetBuildingTypeByCapacity(cap);
369 const building_t* building = B_GetBuildingTemplateByType(buildingType);
370 if (building != nullptr)
371 Q_strcat(upBuffer, sizeof(upBuffer), _("Required Hangar:\t%s\n"), _(building->name));
372
373 /* @note: while MAX_ACTIVETEAM limits the number of soldiers on a craft
374 * there is no use to show this in case of an UFO (would be misleading): */
375 if (!AIR_IsUFO(aircraft))
376 Q_strcat(upBuffer, sizeof(upBuffer), _("Max. soldiers:\t%i\n"), aircraft->maxTeamSize);
377
378 /* Weapon/equipment slots */
379 Q_strcat(upBuffer, sizeof(upBuffer), _("Equipment slots:\t%i %s, %i %s\n"),
380 aircraft->maxWeapons, _("weapon"),
381 aircraft->maxElectronics, _("electronics")
382 );
383 } else if (RS_Collected_(tech)) {
385 Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this"));
386 } else {
387 Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this"));
388 }
389
390 cgi->Cvar_Set("mn_upmetadata", "1");
391 cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer);
392 UP_DisplayTechTree(tech);
393}
394
401void UP_UGVDescription (const ugv_t* ugvType)
402{
403 static char itemText[512];
404 const technology_t* tech;
405
406 assert(ugvType);
407
408 tech = RS_GetTechByProvided(ugvType->id);
409 assert(tech);
410
411 cgi->INV_ItemDescription(nullptr);
412
413 /* Set name of ugv/robot */
414 cgi->Cvar_Set("mn_itemname", "%s", _(tech->name));
415 cgi->Cvar_Set("mn_item", "%s", tech->provides);
416
417 cgi->Cvar_Set("mn_upmetadata", "1");
418 if (RS_IsResearched_ptr(tech)) {
420 Com_sprintf(itemText, sizeof(itemText), _("%s\n%s"), _(tech->name), ugvType->weapon);
421 } else if (RS_Collected_(tech)) {
423 Com_sprintf(itemText, sizeof(itemText), _("Unknown - need to research this"));
424 } else {
425 Com_sprintf(itemText, sizeof(itemText), _("Unknown - need to research this"));
426 }
427 cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText);
428}
429
437{
438 const uiMessageListNodeMessage_t* m = cgi->UI_MessageGetStack();
439
440 if (ccs.numUnreadMails != -1)
441 return ccs.numUnreadMails;
442
443 ccs.numUnreadMails = 0;
444
445 while (m) {
446 switch (m->type) {
448 assert(m->pedia);
449 if (m->pedia->mail[TECHMAIL_PRE].from && !m->pedia->mail[TECHMAIL_PRE].read)
450 ccs.numUnreadMails++;
451 break;
453 assert(m->pedia);
454 if (m->pedia->mail[TECHMAIL_RESEARCHED].from && RS_IsResearched_ptr(m->pedia) && !m->pedia->mail[TECHMAIL_RESEARCHED].read)
455 ccs.numUnreadMails++;
456 break;
457 case MSG_NEWS:
458 assert(m->pedia);
459 if (m->pedia->mail[TECHMAIL_PRE].from && !m->pedia->mail[TECHMAIL_PRE].read)
460 ccs.numUnreadMails++;
461 if (m->pedia->mail[TECHMAIL_RESEARCHED].from && !m->pedia->mail[TECHMAIL_RESEARCHED].read)
462 ccs.numUnreadMails++;
463 break;
464 case MSG_EVENT:
465 assert(m->eventMail);
466 if (!m->eventMail->read)
467 ccs.numUnreadMails++;
468 break;
469 default:
470 break;
471 }
472 m = m->next;
473 }
474
475 /* use strings here */
476 cgi->Cvar_Set("mn_upunreadmail", "%i", ccs.numUnreadMails);
477 return ccs.numUnreadMails;
478}
479
491{
492 static char mailHeader[8 * MAX_VAR] = ""; /* bigger as techMail_t (utf8) */
493 char dateBuf[MAX_VAR] = "";
494 const char* subjectType = "";
495 const char* from, *to, *subject, *model;
496 dateLong_t date;
497
498 if (mail) {
499 from = mail->from;
500 to = mail->to;
501 model = mail->model;
502 subject = mail->subject;
503 Q_strncpyz(dateBuf, _(mail->date), sizeof(dateBuf));
504 mail->read = true;
505 /* reread the unread mails in UP_GetUnreadMails */
506 ccs.numUnreadMails = -1;
507 } else {
508 techMail_t* mail;
509 assert(tech);
510 assert(type < TECHMAIL_MAX);
511
512 mail = &tech->mail[type];
513 from = mail->from;
514 to = mail->to;
515 subject = mail->subject;
516 model = mail->model;
517
518 if (mail->date) {
519 Q_strncpyz(dateBuf, _(mail->date), sizeof(dateBuf));
520 } else {
521 switch (type) {
522 case TECHMAIL_PRE:
524 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"),
525 date.year, Date_GetMonthName(date.month - 1), date.day);
526 break;
529 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"),
530 date.year, Date_GetMonthName(date.month - 1), date.day);
531 break;
532 default:
533 cgi->Com_Error(ERR_DROP, "UP_SetMailHeader: unhandled techMailType_t %i for date.", type);
534 }
535 }
536 if (from != nullptr) {
537 if (!mail->read) {
538 mail->read = true;
539 /* reread the unread mails in UP_GetUnreadMails */
540 ccs.numUnreadMails = -1;
541 }
542 /* only if mail and mail_pre are available */
543 if (tech->numTechMails == TECHMAIL_MAX) {
544 switch (type) {
545 case TECHMAIL_PRE:
546 subjectType = _("Proposal: ");
547 break;
549 subjectType = _("Re: ");
550 break;
551 default:
552 cgi->Com_Error(ERR_DROP, "UP_SetMailHeader: unhandled techMailType_t %i for subject.", type);
553 }
554 }
555 } else {
556 cgi->UI_ResetData(TEXT_UFOPEDIA_MAILHEADER);
557 return;
558 }
559 }
560 from = cgi->CL_Translate(from);
561 to = cgi->CL_Translate(to);
562 subject = cgi->CL_Translate(subject);
563 Com_sprintf(mailHeader, sizeof(mailHeader), _("FROM: %s\nTO: %s\nDATE: %s"), from, to, dateBuf);
564 cgi->Cvar_Set("mn_mail_sender_head", "%s", model ? model : "");
565 cgi->Cvar_Set("mn_mail_from", "%s", from);
566 cgi->Cvar_Set("mn_mail_subject", "%s%s", subjectType, _(subject));
567 cgi->Cvar_Set("mn_mail_to", "%s", to);
568 cgi->Cvar_Set("mn_mail_date", "%s", dateBuf);
569 cgi->UI_RegisterText(TEXT_UFOPEDIA_MAILHEADER, mailHeader);
570}
571
577static void UP_DrawAssociatedAmmo (const technology_t* tech)
578{
579 const objDef_t* od = INVSH_GetItemByID(tech->provides);
580 /* If this is a weapon, we display the model of the associated ammunition in the lower right */
581 if (od->numAmmos > 0) {
582 const technology_t* associated = RS_GetTechForItem(od->ammos[0]);
583 cgi->Cvar_Set("mn_upmodel_bottom", "%s", associated->mdl);
584 }
585}
586
593static void UP_Article (technology_t* tech, eventMail_t* mail)
594{
596
597 if (tech) {
598 if (tech->mdl)
599 cgi->Cvar_Set("mn_upmodel_top", "%s", tech->mdl);
600 else
601 cgi->Cvar_Set("mn_upmodel_top", "");
602
603 if (tech->image)
604 cgi->Cvar_Set("mn_upimage_top", "%s", tech->image);
605 else
606 cgi->Cvar_Set("mn_upimage_top", "");
607
608 cgi->Cvar_Set("mn_upmodel_bottom", "");
609
610 if (tech->type == RS_WEAPON)
612 cgi->Cvar_Set("mn_uprequirement", "");
613 cgi->Cvar_Set("mn_upmetadata", "");
614 }
615
616 cgi->UI_ResetData(TEXT_UFOPEDIA);
617 cgi->UI_ResetData(TEXT_UFOPEDIA_REQUIREMENT);
618
619 if (mail) {
620 /* event mail */
621 cgi->Cvar_SetValue("mn_uppreavailable", 0);
622 cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS);
623 UP_SetMailHeader(nullptr, TECHMAIL_PRE, mail);
624 cgi->UI_RegisterText(TEXT_UFOPEDIA, _(mail->body));
625 /* This allows us to use the index button in the UFOpaedia,
626 * eventMails don't have any chapter to go back to. */
628 } else if (tech) {
630 upCurrentTech = tech;
631
632 /* Reset itemdescription */
633 cgi->UI_ExecuteConfunc("itemdesc_view 0 0;");
634 if (RS_IsResearched_ptr(tech)) {
635 cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s (complete)"), _(tech->name));
636 /* If researched -> display research text */
637 cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->description)));
638 if (tech->preDescription.numDescriptions > 0) {
639 /* Display pre-research text and the buttons if a pre-research text is available. */
640 if (mn_uppretext->integer) {
641 cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription)));
642 UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr);
643 } else {
645 }
646 cgi->Cvar_SetValue("mn_uppreavailable", 1);
647 } else {
648 /* Do not display the pre-research-text button if none is available (no need to even bother clicking there). */
649 cgi->Cvar_SetValue("mn_uppreavailable", 0);
650 cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS);
652 }
653
654 switch (tech->type) {
655 case RS_ARMOUR:
656 case RS_WEAPON:
657 for (int i = 0; i < cgi->csi->numODs; i++) {
658 const objDef_t* od = INVSH_GetItemByIDX(i);
659 if (Q_streq(tech->provides, od->id)) {
660 cgi->INV_ItemDescription(od);
661 UP_DisplayTechTree(tech);
662 cgi->Cvar_Set("mn_upmetadata", "1");
663 break;
664 }
665 }
666 break;
667 case RS_TECH:
668 UP_DisplayTechTree(tech);
669 break;
670 case RS_CRAFT:
672 break;
673 case RS_CRAFTITEM:
675 break;
676 case RS_BUILDING:
678 break;
679 case RS_UGV:
680 UP_UGVDescription(cgi->Com_GetUGVByIDSilent(tech->provides));
681 break;
682 default:
683 break;
684 }
685 /* see also UP_TechGetsDisplayed */
686 } else if (RS_Collected_(tech) || (tech->statusResearchable && tech->preDescription.numDescriptions > 0)) {
687 /* This tech has something collected or has a research proposal. (i.e. pre-research text) */
688 cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name));
689 /* Not researched but some items collected -> display pre-research text if available. */
690 if (tech->preDescription.numDescriptions > 0) {
691 cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription)));
692 UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr);
693 } else {
694 cgi->UI_RegisterText(TEXT_UFOPEDIA, _("No pre-research description available."));
695 }
696 } else {
697 cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name));
698 cgi->UI_ResetData(TEXT_UFOPEDIA);
699 }
700 } else {
701 cgi->Com_Error(ERR_DROP, "UP_Article: No mail or tech given");
702 }
703}
704
708void UP_OpenEventMail (const char* eventMailID)
709{
710 eventMail_t* mail;
711 mail = CL_GetEventMail(eventMailID);
712 if (!mail)
713 return;
714
715 cgi->UI_PushWindow("mail");
716 UP_Article(nullptr, mail);
717}
718
724static void UP_OpenMailWith (const char* techID)
725{
726 if (!techID)
727 return;
728
729 cgi->UI_PushWindow("mail");
730 cgi->Cbuf_AddText("ufopedia %s\n", techID);
731}
732
738void UP_OpenWith (const char* techID)
739{
740 if (!techID)
741 return;
742
743 cgi->UI_PushWindow("ufopedia");
744 cgi->Cbuf_AddText("ufopedia %s\nupdate_ufopedia_layout\n", techID);
745}
746
752void UP_OpenCopyWith (const char* techID)
753{
754 cgi->Cmd_ExecuteString("ui_push ufopedia");
755 cgi->Cbuf_AddText("ufopedia %s\n", techID);
756}
757
758
762static void UP_FindEntry_f (void)
763{
764 const char* id;
765 technology_t* tech;
766
767 if (cgi->Cmd_Argc() < 2) {
768 cgi->Com_Printf("Usage: %s <id>\n", cgi->Cmd_Argv(0));
769 return;
770 }
771
772 /* what are we searching for? */
773 id = cgi->Cmd_Argv(1);
774
775 /* maybe we get a call like 'ufopedia ""' */
776 if (id[0] == '\0') {
777 cgi->Com_Printf("UP_FindEntry_f: No UFOpaedia entry given as parameter\n");
778 return;
779 }
780
781 tech = RS_GetTechByID(id);
782 if (!tech) {
783 cgi->Com_DPrintf(DEBUG_CLIENT, "UP_FindEntry_f: No UFOpaedia entry found for %s\n", id);
784 return;
785 }
786
787 if (tech->redirect)
788 tech = tech->redirect;
789
790 UP_Article(tech, nullptr);
791}
792
799{
800 technology_t* tech = parentChapter->first;
801 uiNode_t* first = nullptr;
802
803 while (tech) {
804 if (UP_TechGetsDisplayed(tech)) {
805 const char* id = va("@%i", tech->idx);
806 cgi->UI_AddOption(&first, id, va("_%s", tech->name), id);
807 }
808 tech = tech->upNext;
809 }
810
811 cgi->UI_SortOptions(&first);
812
813 return first;
814}
815
820static void UP_GenerateSummary (void)
821{
822 uiNode_t* chapters = nullptr;
823 int num = 0;
824
826
827 for (int i = 0; i < ccs.numChapters; i++) {
828 /* hide chapters without name */
829 pediaChapter_t* chapter = &ccs.upChapters[i];
830 if (chapter->name == nullptr)
831 continue;
832
833 /* Check if there are any researched or collected items in this chapter ... */
834 bool researchedEntries = false;
835 upCurrentTech = chapter->first;
836 while (upCurrentTech) {
838 researchedEntries = true;
839 break;
840 }
842 }
843
844 /* .. and if so add them to the displaylist of chapters. */
845 if (researchedEntries) {
846 uiNode_t* chapterOption;
848 cgi->Com_Error(ERR_DROP, "MAX_PEDIACHAPTERS hit");
850
851 /* chapter section*/
852 chapterOption = cgi->UI_AddOption(&chapters, chapter->id, va("_%s", chapter->name), va("%i", num));
854 OPTIONEXTRADATA(chapterOption).icon = cgi->UI_GetSpriteByName(va("icons/ufopedia_%s", chapter->id));
855 chapterOption->firstChild = UP_GenerateArticlesSummary(chapter);
856
857 num++;
858 }
859 }
860
861 cgi->UI_RegisterOption(OPTION_UFOPEDIA, chapters);
862 cgi->Cvar_Set("mn_uptitle", _("UFOpaedia"));
863}
864
868static void UP_Content_f (void)
869{
872}
873
879static void UP_Click_f (void)
880{
881 if (cgi->Cmd_Argc() < 2)
882 return;
883
884 /* article index starts with a @ */
885 if (cgi->Cmd_Argv(1)[0] == '@') {
886 const int techId = atoi(cgi->Cmd_Argv(1) + 1);
887 technology_t* tech;
888 assert(techId >= 0);
889 assert(techId < ccs.numTechnologies);
890 tech = &ccs.technologies[techId];
891 if (tech)
892 UP_Article(tech, nullptr);
893 return;
894 } else {
895 /* Reset itemdescription */
896 cgi->UI_ExecuteConfunc("itemdesc_view 0 0;");
897 }
898
899 /* it clean up the display */
901}
902
906static void UP_TechTreeClick_f (void)
907{
908 if (cgi->Cmd_Argc() < 2)
909 return;
910
911 int num = atoi(cgi->Cmd_Argv(1));
912
913 if (!upCurrentTech)
914 return;
915
916 const requirements_t* required_AND = &upCurrentTech->requireAND;
917 if (num < 0 || num >= required_AND->numLinks)
918 return;
919
920 /* skip every tech which have not been displayed in techtree */
921 for (int i = 0; i <= num; i++) {
922 const requirement_t* r = &required_AND->links[i];
923 if (r->type != RS_LINK_TECH && r->type != RS_LINK_TECH_NOT)
924 num++;
925 }
926
927 const technology_t* techRequired = required_AND->links[num].link.tech;
928 if (!techRequired)
929 cgi->Com_Error(ERR_DROP, "Could not find the tech for '%s'", required_AND->links[num].id);
930
931 /* maybe there is no UFOpaedia chapter assigned - this tech should not be opened at all */
932 if (!techRequired->upChapter)
933 return;
934
935 UP_OpenWith(techRequired->id);
936}
937
941static void UP_Update_f (void)
942{
943 if (upCurrentTech)
944 UP_Article(upCurrentTech, nullptr);
945}
946
951static void UP_MailClientClick_f (void)
952{
953 if (cgi->Cmd_Argc() < 2)
954 return;
955
956 int cnt = -1;
957 const int num = atoi(cgi->Cmd_Argv(1));
958
959 uiMessageListNodeMessage_t* m = cgi->UI_MessageGetStack();
960 while (m) {
961 switch (m->type) {
963 if (!m->pedia->mail[TECHMAIL_PRE].from)
964 break;
965 cnt++;
966 if (cnt == num) {
967 cgi->Cvar_SetValue("mn_uppretext", 1);
968 UP_OpenMailWith(m->pedia->id);
969 return;
970 }
971 break;
973 if (!m->pedia->mail[TECHMAIL_RESEARCHED].from)
974 break;
975 cnt++;
976 if (cnt == num) {
977 cgi->Cvar_SetValue("mn_uppretext", 0);
978 UP_OpenMailWith(m->pedia->id);
979 return;
980 }
981 break;
982 case MSG_NEWS:
983 if (m->pedia->mail[TECHMAIL_PRE].from || m->pedia->mail[TECHMAIL_RESEARCHED].from) {
984 cnt++;
985 if (cnt >= num) {
986 UP_OpenMailWith(m->pedia->id);
987 return;
988 }
989 }
990 break;
991 case MSG_EVENT:
992 cnt++;
993 if (cnt >= num) {
994 UP_OpenEventMail(m->eventMail->id);
995 return;
996 }
997 break;
998 default:
999 break;
1000 }
1001 m = m->next;
1002 }
1003 ccs.numUnreadMails = -1;
1005}
1006
1011{
1012 const objDef_t* od;
1013
1014 if (!upCurrentTech) /* if called from console */
1015 return;
1016
1017 od = INVSH_GetItemByID(upCurrentTech->provides);
1018 assert(od);
1019
1020 if (od->isAmmo()) {
1021 const technology_t* t = RS_GetTechForItem(od->weapons[0]);
1022 if (UP_TechGetsDisplayed(t))
1023 UP_OpenWith(t->id);
1024 } else if (od->weapon && od->isReloadable()) {
1025 const technology_t* t = RS_GetTechForItem(od->ammos[0]);
1026 if (UP_TechGetsDisplayed(t))
1027 UP_OpenWith(t->id);
1028 }
1029}
1030
1038static void UP_OpenMail_f (void)
1039{
1040 cgi->UI_ExecuteConfunc("clear_mails");
1041 int idx = 0;
1042 for (const uiMessageListNodeMessage_t* m = cgi->UI_MessageGetStack(); m; m = m->next) {
1043 dateLong_t date;
1044 char headline[256] = "";
1045 char dateBuf[64] = "";
1046 const char* icon;
1047 bool read;
1048 switch (m->type) {
1049 case MSG_RESEARCH_PROPOSAL: {
1050 const techMail_t& mail = m->pedia->mail[TECHMAIL_PRE];
1051 if (!mail.from)
1052 continue;
1053 CP_DateConvertLong(m->pedia->preResearchedDate, &date);
1054 Com_sprintf(headline, sizeof(headline), _("Proposal: %s"), _(m->pedia->mail[TECHMAIL_PRE].subject));
1055 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day);
1056 icon = mail.icon;
1057 read = mail.read;
1058 break;
1059 }
1060 case MSG_RESEARCH_FINISHED: {
1061 const techMail_t& mail = m->pedia->mail[TECHMAIL_RESEARCHED];
1062 if (!mail.from)
1063 continue;
1064 CP_DateConvertLong(m->pedia->researchedDate, &date);
1065 Com_sprintf(headline, sizeof(headline), _("Re: %s"), _(m->pedia->mail[TECHMAIL_RESEARCHED].subject));
1066 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day);
1067 icon = mail.icon;
1068 read = mail.read;
1069 break;
1070 }
1071 case MSG_NEWS: {
1072 const techMail_t* mail = &m->pedia->mail[TECHMAIL_PRE];
1073 if (mail->from) {
1074 CP_DateConvertLong(m->pedia->preResearchedDate, &date);
1075 } else {
1076 CP_DateConvertLong(m->pedia->researchedDate, &date);
1077 mail = &m->pedia->mail[TECHMAIL_RESEARCHED];
1078 }
1079 if (!mail->from)
1080 continue;
1081 Com_sprintf(headline, sizeof(headline), "%s", _(mail->subject));
1082 Com_sprintf(dateBuf, sizeof(dateBuf), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day);
1083 icon = mail->icon;
1084 read = mail->read;
1085 break;
1086 }
1087 case MSG_EVENT: {
1088 assert(m->eventMail);
1089 const eventMail_t& mail = *m->eventMail;
1090 if (!mail.from)
1091 continue;
1092 Com_sprintf(headline, sizeof(headline), "%s", _(mail.subject));
1093 Com_sprintf(dateBuf, sizeof(dateBuf), "%s", mail.date);
1094 icon = mail.icon;
1095 read = mail.read;
1096 break;
1097 }
1098 default:
1099 continue;
1100 }
1101 cgi->UI_ExecuteConfunc("add_mail %i \"%s\" \"%s\" %i \"%s\"", idx++, headline, icon, read, dateBuf);
1102 }
1103}
1104
1108static void UP_SetAllMailsRead_f (void)
1109{
1110 const uiMessageListNodeMessage_t* m = cgi->UI_MessageGetStack();
1111
1112 while (m) {
1113 switch (m->type) {
1115 assert(m->pedia);
1116 m->pedia->mail[TECHMAIL_PRE].read = true;
1117 break;
1119 assert(m->pedia);
1120 m->pedia->mail[TECHMAIL_RESEARCHED].read = true;
1121 break;
1122 case MSG_NEWS:
1123 assert(m->pedia);
1124 m->pedia->mail[TECHMAIL_PRE].read = true;
1125 m->pedia->mail[TECHMAIL_RESEARCHED].read = true;
1126 break;
1127 case MSG_EVENT:
1128 assert(m->eventMail);
1129 m->eventMail->read = true;
1130 break;
1131 default:
1132 break;
1133 }
1134 m = m->next;
1135 }
1136
1137 ccs.numUnreadMails = 0;
1138 cgi->Cvar_Set("mn_upunreadmail", "%i", ccs.numUnreadMails);
1139 UP_OpenMail_f();
1140}
1141
1142static const cmdList_t ufopediaCmds[] = {
1143 {"mn_upcontent", UP_Content_f, "Shows the UFOpaedia chapters"},
1144 {"mn_upupdate", UP_Update_f, "Redraw the current UFOpaedia article"},
1145 {"ufopedia", UP_FindEntry_f, "Open the UFOpaedia with the given article"},
1146 {"ufopedia_click", UP_Click_f, nullptr},
1147 {"mailclient_click", UP_MailClientClick_f, nullptr},
1148 {"mn_mail_readall", UP_SetAllMailsRead_f, "Mark all mails read"},
1149 {"ufopedia_openmail", UP_OpenMail_f, "Start the mailclient"},
1150 {"techtree_click", UP_TechTreeClick_f, nullptr},
1151 {"mn_upgotoresearchedlink", UP_ResearchedLinkClick_f, nullptr},
1152 {nullptr, nullptr, nullptr}
1153};
1154
1158{
1159 /* add commands and cvars */
1160 cgi->Cmd_TableAddList(ufopediaCmds);
1161
1162 mn_uppretext = cgi->Cvar_Get("mn_uppretext", "0", 0, "Show the pre-research text in the UFOpaedia");
1163 mn_uppreavailable = cgi->Cvar_Get("mn_uppreavailable", "0", 0, "True if there is a pre-research text available");
1164 cgi->Cvar_Set("mn_uprequirement", "");
1165 cgi->Cvar_Set("mn_upmetadata", "");
1166}
1167
1171void UP_Shutdown (void)
1172{
1173 /* add commands and cvars */
1174 cgi->Cmd_TableRemoveList(ufopediaCmds);
1175
1176 cgi->Cvar_Delete("mn_uppretext");
1177 cgi->Cvar_Delete("mn_uppreavailable");
1178 cgi->Cvar_Delete("mn_uprequirement");
1179 cgi->Cvar_Delete("mn_upmetadata");
1180}
1181
1188void UP_ParseChapter (const char* name, const char** text)
1189{
1190 const char* errhead = "UP_ParseChapter: unexpected end of file (names ";
1191 const char* token;
1192
1193 if (ccs.numChapters >= MAX_PEDIACHAPTERS) {
1194 cgi->Com_Error(ERR_DROP, "UP_ParseChapter: chapter def \"%s\": Too many chapter defs.\n", name);
1195 }
1196
1197 pediaChapter_t chapter;
1198 OBJZERO(chapter);
1199 chapter.id = cgi->PoolStrDup(name, cp_campaignPool, 0);
1200 chapter.idx = ccs.numChapters; /* set self-link */
1201
1202 /* get begin block */
1203 token = Com_Parse(text);
1204 if (!*text || *token !='{') {
1205 cgi->Com_Error(ERR_DROP, "UP_ParseChapter: chapter def \"%s\": '{' token expected.\n", name);
1206 }
1207
1208 do {
1209 token = Com_Parse(text);
1210 if (!*text)
1211 cgi->Com_Error(ERR_DROP, "UP_ParseChapter: end of file not expected \"%s\": '{' token expected.\n", name);
1212 if (token[0] == '}')
1213 break;
1214
1215 if (Q_streq(token, "name")) {
1216 /* get the name */
1217 token = cgi->Com_EParse(text, errhead, name);
1218 if (!*text || *token == '}') {
1219 cgi->Com_Error(ERR_DROP, "UP_ParseChapter: chapter def \"%s\": Name token expected.\n", name);
1220 }
1221 if (*token == '_')
1222 token++;
1223 chapter.name = cgi->PoolStrDup(token, cp_campaignPool, 0);
1224 } else {
1225 cgi->Com_Error(ERR_DROP, "UP_ParseChapter: chapter def \"%s\": token \"%s\" not expected.\n", name, token);
1226 }
1227 } while (*text);
1228
1229 /* add chapter to the game */
1230 ccs.upChapters[ccs.numChapters] = chapter;
1231 ccs.numChapters++;
1232}
DateTime class definition.
Header file for inventory handling and Equipment menu.
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define ERR_DROP
Definition common.h:211
int AIR_GetOperationRange(const aircraft_t *aircraft)
Calculates the range an aircraft can fly on the geoscape.
int AIR_AircraftMenuStatsValues(const int value, const int stat)
Some of the aircraft values needs special calculations when they are shown in the menus.
const aircraft_t * AIR_GetAircraft(const char *name)
Searches the global array of aircraft types for a given aircraft.
baseCapacities_t AIR_GetHangarCapacityType(const aircraft_t *aircraft)
Returns capacity type needed for an aircraft.
#define AIR_IsUFO(aircraft)
buildingType_t B_GetBuildingTypeByCapacity(baseCapacities_t cap)
Get building type by base capacity.
Definition cp_base.cpp:447
const building_t * B_GetBuildingTemplateByType(buildingType_t type)
Returns the building template in the global building-types list for a buildingType.
building_t * B_GetBuildingTemplate(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
buildingType_t
All different building types.
Definition cp_building.h:51
memPool_t * cp_campaignPool
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
baseCapacities_t
All possible capacities in base.
Definition cp_capacity.h:27
eventMail_t * CL_GetEventMail(const char *id)
Searches all event mails for a given id.
Definition cp_event.cpp:45
itemWeight_t AII_GetItemWeightBySize(const objDef_t *od)
Returns craftitem weight based on size.
const char * AII_WeightToName(itemWeight_t weight)
Translate a weight int to a translated string.
Header for slot management related stuff.
@ MSG_RESEARCH_FINISHED
Definition cp_messages.h:38
@ MSG_RESEARCH_PROPOSAL
Definition cp_messages.h:36
@ MSG_EVENT
Definition cp_messages.h:51
@ MSG_NEWS
Definition cp_messages.h:47
const char * RS_GetDescription(technologyDescriptions_t *desc)
returns the currently used description for a technology.
technology_t * RS_GetTechForItem(const objDef_t *item)
Returns technology entry for an item.
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
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
#define RS_Collected_(tech)
@ RS_LINK_TECH
Definition cp_research.h:62
@ RS_LINK_TECH_NOT
Definition cp_research.h:63
@ RS_BUILDING
Definition cp_research.h:54
@ RS_CRAFTITEM
Definition cp_research.h:53
@ RS_TECH
Definition cp_research.h:49
@ RS_UGV
Definition cp_research.h:56
@ RS_LOGIC
Definition cp_research.h:58
@ RS_WEAPON
Definition cp_research.h:50
@ RS_CRAFT
Definition cp_research.h:52
@ RS_ARMOUR
Definition cp_research.h:51
techMailType_t
Types for tech mail definitions - see tech->mail[].
Definition cp_research.h:99
@ TECHMAIL_PRE
@ TECHMAIL_MAX
@ TECHMAIL_RESEARCHED
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.
static cvar_t * mn_uppreavailable
void UP_OpenWith(const char *techID)
Opens the UFOpaedia from everywhere with the entry given through name.
static void UP_ChangeDisplay(int newDisplay)
Modify the global display var.
static pediaChapter_t * currentChapter
static void UP_Article(technology_t *tech, eventMail_t *mail)
Display only the TEXT_UFOPEDIA part for a given technology.
static void UP_SetMailHeader(technology_t *tech, techMailType_t type, eventMail_t *mail)
Binds the mail header (if needed) to the mn.menuText array.
static technology_t * upCurrentTech
static void UP_DisplayTechTree(const technology_t *t)
Displays the tech tree dependencies in the UFOpaedia.
static void UP_OpenMailWith(const char *techID)
Opens the mail view from everywhere with the entry given through name.
static void UP_TechTreeClick_f(void)
void UP_OpenCopyWith(const char *techID)
Opens the UFOpaedia with the entry given through name, not deleting copies.
static void UP_BuildingDescription(const technology_t *t)
Prints the UFOpaedia description for buildings.
@ UFOPEDIA_DISPLAYEND
@ UFOPEDIA_INDEX
@ UFOPEDIA_CHAPTERS
@ UFOPEDIA_ARTICLE
static bool UP_TechGetsDisplayed(const technology_t *tech)
Checks If a technology/UFOpaedia-entry will be displayed in the UFOpaedia (-list).
void UP_OpenEventMail(const char *eventMailID)
static void UP_OpenMail_f(void)
Start the mailclient.
void UP_Shutdown(void)
static void UP_Click_f(void)
Callback when we click on the ufopedia summary.
int UP_GetUnreadMails(void)
Sets the amount of unread/new mails.
void UP_UGVDescription(const ugv_t *ugvType)
Prints the description for robots/ugvs.
static uiNode_t * UP_GenerateArticlesSummary(pediaChapter_t *parentChapter)
Generate a list of options for all allowed articles of a chapter.
#define MAX_UPTEXT
static void UP_FindEntry_f(void)
Search and open the UFOpaedia with given id.
static int numChaptersDisplayList
static cvar_t * mn_uppretext
void UP_ParseChapter(const char *name, const char **text)
Parse the UFOpaedia chapters from scripts.
static const cmdList_t ufopediaCmds[]
void UP_AircraftDescription(const technology_t *tech)
Prints the UFOpaedia description for aircraft.
static void UP_ResearchedLinkClick_f(void)
Change UFOpaedia article when clicking on the name of associated ammo or weapon.
static void UP_GenerateSummary(void)
Generate a tree of option for all allowed chapters and articles.
static char upBuffer[MAX_UPTEXT]
static void UP_MailClientClick_f(void)
Mailclient click function callback.
static void UP_Content_f(void)
Displays the chapters in the UFOpaedia.
static int upDisplay
static const char * UP_AircraftStatToName(int stat)
Translate a aircraft statistic integer to a translated string.
static void UP_DrawAssociatedAmmo(const technology_t *tech)
Set the ammo model to display to selected ammo (only for a reloadable weapon).
void UP_AircraftItemDescription(const objDef_t *item)
Prints the (UFOpaedia and other) description for aircraft items.
static void UP_SetAllMailsRead_f(void)
Marks all mails read in mailclient.
static void UP_Update_f(void)
Redraw the UFOpaedia article.
static pediaChapter_t * upChaptersDisplayList[MAX_PEDIACHAPTERS]
void UP_InitStartup(void)
#define MAX_PEDIACHAPTERS
Definition cp_ufopedia.h:28
#define DEBUG_CLIENT
Definition defines.h:59
#define ngettext(x, y, cnt)
Definition g_local.h:40
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
const objDef_t * INVSH_GetItemByIDSilent(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
@ AIR_STATS_MAX
Definition inv_shared.h:237
@ AIR_STATS_ECM
Definition inv_shared.h:229
@ AIR_STATS_ANTIMATTER
Definition inv_shared.h:235
@ AIR_STATS_FUELSIZE
Definition inv_shared.h:232
@ AIR_STATS_WRANGE
Definition inv_shared.h:233
@ AIR_STATS_ACCURACY
Definition inv_shared.h:231
@ AIR_STATS_SPEED
Definition inv_shared.h:226
@ AIR_STATS_DAMAGE
Definition inv_shared.h:230
@ AIR_STATS_SHIELD
Definition inv_shared.h:228
@ AIR_STATS_MAXSPEED
Definition inv_shared.h:227
@ AC_ITEM_WEAPON
Definition inv_shared.h:201
@ AC_ITEM_AMMO
Definition inv_shared.h:211
@ AC_ITEM_BASE_LASER
Definition inv_shared.h:200
@ AC_ITEM_BASE_MISSILE
Definition inv_shared.h:199
static struct mdfour * m
Definition md4.cpp:35
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
QGL_EXTERN GLuint * id
Definition r_gl.h:86
#define Q_streq(a, b)
Definition shared.h:136
#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
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.
int maxElectronics
int stats[AIR_STATS_MAX]
A building with all it's data.
Definition cp_building.h:73
char * name
Definition cp_building.h:79
const struct building_s * dependsBuilding
float stats[AIR_STATS_MAX]
Definition inv_shared.h:248
aircraftItemType_t type
Definition inv_shared.h:247
float weaponDelay
Definition inv_shared.h:251
float weaponDamage
Definition inv_shared.h:249
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
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
char * model
Definition cp_event.h:49
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
bool read
Definition cp_event.h:50
char * body
Definition cp_event.h:47
char * icon
Definition cp_event.h:48
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
bool isAmmo() const
Definition inv_shared.h:343
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition inv_shared.h:307
bool isVirtual
Definition inv_shared.h:284
bool weapon
Definition inv_shared.h:277
int numAmmos
Definition inv_shared.h:308
bool isReloadable() const
Definition inv_shared.h:352
craftItem craftitem
Definition inv_shared.h:331
const char * id
Definition inv_shared.h:268
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition inv_shared.h:311
const char * name
Definition inv_shared.h:267
struct technology_s * first
Definition cp_ufopedia.h:34
union requirement_t::typelink_t link
requirementType_t type
Definition cp_research.h:74
requirement_t links[MAX_TECHLINKS]
Definition cp_research.h:88
available mails for a tech - mail and mail_pre in script files
const char * date
const char * icon
const char * model
char * from
const char * subject
const char * to
This is the technology parsed from research.ufo.
char * provides
technologyDescriptions_t description
technologyDescriptions_t preDescription
bool statusResearchable
requirements_t requireAND
struct technology_s * redirect
class DateTime preResearchedDate
struct technology_s * upNext
struct pediaChapter_s * upChapter
techMail_t mail[TECHMAIL_MAX]
class DateTime researchedDate
researchType_t type
Defines a type of UGV/Robot.
Definition chr_shared.h:245
char weapon[MAX_VAR]
Definition chr_shared.h:248
char * id
Definition chr_shared.h:246
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
uiNode_t * firstChild
Definition ui_nodes.h:89
@ TEXT_UFOPEDIA_MAIL
Definition ui_dataids.h:50
@ TEXT_UFOPEDIA_MAILHEADER
Definition ui_dataids.h:49
@ TEXT_UFOPEDIA_REQUIREMENT
Definition ui_dataids.h:34
@ TEXT_UFOPEDIA
Definition ui_dataids.h:33
@ TEXT_ITEMDESCRIPTION
Definition ui_dataids.h:70
@ OPTION_UFOPEDIA
Definition ui_dataids.h:80
#define OPTIONEXTRADATA(node)
#define EQUAL(a, b)
Definition vector.h:37