UFO: Alien Invasion
Doxygen documentation generating
cp_ufopedia.cpp
Go to the documentation of this file.
1 
8 /*
9 Copyright (C) 2002-2023 UFO: Alien Invasion.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, 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 */
33 #include "../../../shared/parse.h"
34 #include "cp_campaign.h"
35 #include "cp_mapfightequip.h"
36 #include "cp_time.h"
37 
40 
43 
46 
47 #define MAX_UPTEXT 4096
48 static char upBuffer[MAX_UPTEXT];
49 
54 enum {
58 
60 };
62 
70 static bool UP_TechGetsDisplayed (const technology_t* tech)
71 {
72  const objDef_t* item;
73 
74  assert(tech);
75  /* virtual items are hidden */
76  item = INVSH_GetItemByIDSilent(tech->provides);
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)
82  || (tech->statusResearchable && tech->preDescription.numDescriptions > 0))
83  && tech->type != RS_LOGIC && !tech->redirect;
84 }
85 
90 static 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) {
107  case UFOPEDIA_CHAPTERS:
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 
133 static const char* UP_AircraftStatToName (int stat)
134 {
135  switch (stat) {
136  case AIR_STATS_SPEED:
137  return _("Cruising speed");
138  case AIR_STATS_MAXSPEED:
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");
146  case AIR_STATS_ACCURACY:
147  return _("Accuracy");
148  case AIR_STATS_FUELSIZE:
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 
165 static 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 
202 static void UP_BuildingDescription (const technology_t* t)
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;
264  case AC_ITEM_BASE_LASER:
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;
343  case AIR_STATS_MAXSPEED:
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;
348  case AIR_STATS_FUELSIZE:
349  Q_strcat(upBuffer, sizeof(upBuffer), _("Operational range:\t%i km\n"),
350  AIR_GetOperationRange(aircraft));
351  break;
352  case AIR_STATS_ACCURACY:
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 
401 void 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 {
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)
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)
456  break;
457  case MSG_NEWS:
458  assert(m->pedia);
459  if (m->pedia->mail[TECHMAIL_PRE].from && !m->pedia->mail[TECHMAIL_PRE].read)
461  if (m->pedia->mail[TECHMAIL_RESEARCHED].from && !m->pedia->mail[TECHMAIL_RESEARCHED].read)
463  break;
464  case MSG_EVENT:
465  assert(m->eventMail);
466  if (!m->eventMail->read)
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;
527  case TECHMAIL_RESEARCHED:
528  CP_DateConvertLong(tech->researchedDate, &date);
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;
548  case TECHMAIL_RESEARCHED:
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 
577 static 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 
593 static 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)
611  UP_DrawAssociatedAmmo(tech);
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) {
629  currentChapter = tech->upChapter;
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 {
644  UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr);
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);
651  UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr);
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:
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 
708 void 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 
724 static 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 
738 void 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 
752 void UP_OpenCopyWith (const char* techID)
753 {
754  cgi->Cmd_ExecuteString("ui_push ufopedia");
755  cgi->Cbuf_AddText("ufopedia %s\n", techID);
756 }
757 
758 
762 static 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 
820 static 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 
868 static void UP_Content_f (void)
869 {
872 }
873 
879 static 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 
906 static 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 
941 static void UP_Update_f (void)
942 {
943  if (upCurrentTech)
944  UP_Article(upCurrentTech, nullptr);
945 }
946 
951 static 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 
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 
1010 static void UP_ResearchedLinkClick_f (void)
1011 {
1012  const objDef_t* od;
1013 
1014  if (!upCurrentTech) /* if called from console */
1015  return;
1016 
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 
1038 static 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 
1108 static void UP_SetAllMailsRead_f (void)
1109 {
1111 
1112  while (m) {
1113  switch (m->type) {
1114  case MSG_RESEARCH_PROPOSAL:
1115  assert(m->pedia);
1116  m->pedia->mail[TECHMAIL_PRE].read = true;
1117  break;
1118  case MSG_RESEARCH_FINISHED:
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 
1142 static 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 };
1157 void UP_InitStartup (void)
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 
1171 void 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 
1188 void 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 
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 }
static void UP_MailClientClick_f(void)
Mailclient click function callback.
uiSprite_t *IMPORT * UI_GetSpriteByName(const char *name)
const objDef_t * INVSH_GetItemByIDSilent(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn&#39;t found.
Definition: inv_shared.cpp:249
int numChapters
Definition: cp_campaign.h:325
const char * RS_GetDescription(technologyDescriptions_t *desc)
returns the currently used description for a technology.
struct technology_s * redirect
Definition: cp_research.h:147
void UP_OpenWith(const char *techID)
Opens the UFOpaedia from everywhere with the entry given through name.
csi_t * csi
Definition: cgame.h:100
void UP_ParseChapter(const char *name, const char **text)
Parse the UFOpaedia chapters from scripts.
requirement_t links[MAX_TECHLINKS]
Definition: cp_research.h:88
char * subject
Definition: cp_event.h:43
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
const objDef_t * INVSH_GetItemByID(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn&#39;t found.
Definition: inv_shared.cpp:282
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
char * date
Definition: cp_event.h:46
#define MAX_PEDIACHAPTERS
Definition: cp_ufopedia.h:28
struct technology_s * upNext
Definition: cp_research.h:194
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
char * icon
Definition: cp_event.h:48
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don&#39;t need to have varargs versions of all text functi...
Definition: shared.cpp:410
int AIR_AircraftMenuStatsValues(const int value, const int stat)
Some of the aircraft values needs special calculations when they are shown in the menus...
void UP_OpenEventMail(const char *eventMailID)
char * model
Definition: cp_event.h:49
#define _(String)
Definition: cl_shared.h:44
int maxWeapons
Definition: cp_aircraft.h:145
static void UP_OpenMailWith(const char *techID)
Opens the mail view from everywhere with the entry given through name.
requirements_t requireAND
Definition: cp_research.h:150
#define EQUAL(a, b)
Definition: vector.h:37
char * to
Definition: cp_event.h:41
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
const building_t * B_GetBuildingTemplateByType(buildingType_t type)
Returns the building template in the global building-types list for a buildingType.
cvar_t *IMPORT * Cvar_Get(const char *varName, const char *value, int flags, const char *desc)
int varCosts
Definition: cp_building.h:83
int numTechnologies
Definition: cp_campaign.h:278
int integer
Definition: cvar.h:81
techMailType_t
Types for tech mail definitions - see tech->mail[].
Definition: cp_research.h:99
static void UP_DisplayTechTree(const technology_t *t)
Displays the tech tree dependencies in the UFOpaedia.
static const cmdList_t ufopediaCmds[]
static void UP_OpenMail_f(void)
Start the mailclient.
const aircraft_t * AIR_GetAircraft(const char *name)
Searches the global array of aircraft types for a given aircraft.
static void UP_TechTreeClick_f(void)
#define RS_Collected_(tech)
Definition: cp_research.h:203
const char *IMPORT * Cmd_Argv(int n)
byte day
Definition: cp_time.h:39
QGL_EXTERN GLuint * id
Definition: r_gl.h:86
buildingType_t
All different building types.
Definition: cp_building.h:51
char * body
Definition: cp_event.h:47
static void UP_Click_f(void)
Callback when we click on the ufopedia summary.
itemWeight_t AII_GetItemWeightBySize(const objDef_t *od)
Returns craftitem weight based on size.
baseCapacities_t AIR_GetHangarCapacityType(const aircraft_t *aircraft)
Returns capacity type needed for an aircraft.
building_t * B_GetBuildingTemplate(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
#define MAX_UPTEXT
Definition: cp_ufopedia.cpp:47
static void UP_Article(technology_t *tech, eventMail_t *mail)
Display only the TEXT_UFOPEDIA part for a given technology.
memPool_t * cp_campaignPool
Definition: cp_campaign.cpp:62
char * from
Definition: cp_research.h:111
technology_t technologies[MAX_TECHNOLOGIES]
Definition: cp_campaign.h:277
const char * Date_GetMonthName(int month)
Returns the short monthame to the given month index.
Definition: cp_time.cpp:250
int maxElectronics
Definition: cp_aircraft.h:148
char *IMPORT * PoolStrDup(const char *in, memPool_t *pool, const int tagNum)
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
float weaponDelay
Definition: inv_shared.h:251
float stats[AIR_STATS_MAX]
Definition: inv_shared.h:248
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
static void UP_ChangeDisplay(int newDisplay)
Modify the global display var.
Definition: cp_ufopedia.cpp:90
struct uiMessageListNodeMessage_s *IMPORT * UI_MessageGetStack(void)
#define ngettext(x, y, cnt)
Definition: g_local.h:40
int buildTime
Definition: cp_building.h:92
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition: inv_shared.h:307
#define ERR_DROP
Definition: common.h:211
#define OPTIONEXTRADATA(node)
#define DEBUG_CLIENT
Definition: defines.h:59
static void UP_Content_f(void)
Displays the chapters in the UFOpaedia.
int numUnreadMails
Definition: cp_campaign.h:326
#define OBJZERO(obj)
Definition: shared.h:178
int AIR_GetOperationRange(const aircraft_t *aircraft)
Calculates the range an aircraft can fly on the geoscape.
#define MAX_VAR
Definition: shared.h:36
class DateTime researchedDate
Definition: cp_research.h:187
technologyDescriptions_t description
Definition: cp_research.h:143
static void UP_Update_f(void)
Redraw the UFOpaedia article.
char * from
Definition: cp_event.h:40
static pediaChapter_t * currentChapter
Definition: cp_ufopedia.cpp:45
const char * subject
Definition: cp_research.h:113
const cgame_import_t * cgi
struct pediaChapter_s * upChapter
Definition: cp_research.h:192
researchType_t type
Definition: cp_research.h:145
void UP_AircraftItemDescription(const objDef_t *item)
Prints the (UFOpaedia and other) description for aircraft items.
Human readable time information in the game.
Definition: cp_time.h:36
const char uiNode_t *IMPORT * UI_AddOption(uiNode_t **tree, const char *name, const char *label, const char *value)
techMail_t mail[TECHMAIL_MAX]
Definition: cp_research.h:196
char * image
Definition: cp_research.h:172
static uiNode_t * UP_GenerateArticlesSummary(pediaChapter_t *parentChapter)
Generate a list of options for all allowed articles of a chapter.
static void UP_SetAllMailsRead_f(void)
Marks all mails read in mailclient.
ccs_t ccs
Definition: cp_campaign.cpp:63
int fixCosts
Definition: cp_building.h:83
static void UP_FindEntry_f(void)
Search and open the UFOpaedia with given id.
class DateTime preResearchedDate
Definition: cp_research.h:186
void UP_InitStartup(void)
short year
Definition: cp_time.h:37
int numODs
Definition: q_shared.h:518
Campaign geoscape time header.
char weapon[MAX_VAR]
Definition: chr_shared.h:248
technologyDescriptions_t preDescription
Definition: cp_research.h:144
craftItem craftitem
Definition: inv_shared.h:331
const char *IMPORT * CL_Translate(const char *t)
const char * date
Definition: cp_research.h:116
bool weapon
Definition: inv_shared.h:277
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
char * name
Definition: cp_building.h:79
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:311
void UP_OpenCopyWith(const char *techID)
Opens the UFOpaedia with the entry given through name, not deleting copies.
int stats[AIR_STATS_MAX]
Definition: cp_aircraft.h:160
int UP_GetUnreadMails(void)
Sets the amount of unread/new mails.
uiNode_t * firstChild
Definition: ui_nodes.h:89
int ammo
Definition: inv_shared.h:293
char * provides
Definition: cp_research.h:156
baseCapacities_t
All possible capacities in base.
Definition: cp_capacity.h:27
static void UP_DrawAssociatedAmmo(const technology_t *tech)
Set the ammo model to display to selected ammo (only for a reloadable weapon)
An aircraft with all it&#39;s data.
Definition: cp_aircraft.h:115
bool isVirtual
Definition: inv_shared.h:284
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
bool isAmmo() const
Definition: inv_shared.h:343
requirementType_t type
Definition: cp_research.h:74
const char * id
Definition: inv_shared.h:268
bool isReloadable() const
Definition: inv_shared.h:352
QGL_EXTERN GLint i
Definition: r_gl.h:113
void UP_UGVDescription(const ugv_t *ugvType)
Prints the description for robots/ugvs.
static cvar_t * mn_uppretext
Definition: cp_ufopedia.cpp:38
static pediaChapter_t * upChaptersDisplayList[MAX_PEDIACHAPTERS]
Definition: cp_ufopedia.cpp:41
#define AIR_IsUFO(aircraft)
Definition: cp_aircraft.h:206
Header for slot management related stuff.
This is the technology parsed from research.ufo.
Definition: cp_research.h:139
const char * icon
Definition: cp_research.h:117
void UP_AircraftDescription(const technology_t *tech)
Prints the UFOpaedia description for aircraft.
static void UP_SetMailHeader(technology_t *tech, techMailType_t type, eventMail_t *mail)
Binds the mail header (if needed) to the mn.menuText array.
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
void UP_Shutdown(void)
int maxTeamSize
Definition: cp_aircraft.h:139
union requirement_t::typelink_t link
const char * name
Definition: inv_shared.h:267
static int upDisplay
Definition: cp_ufopedia.cpp:61
const char * AII_WeightToName(itemWeight_t weight)
Translate a weight int to a translated string.
const struct building_s * dependsBuilding
Definition: cp_building.h:112
available mails for a tech - mail and mail_pre in script files
Definition: cp_research.h:110
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
static void UP_BuildingDescription(const technology_t *t)
Prints the UFOpaedia description for buildings.
static bool UP_TechGetsDisplayed(const technology_t *tech)
Checks If a technology/UFOpaedia-entry will be displayed in the UFOpaedia (-list).
Definition: cp_ufopedia.cpp:70
static cvar_t * mn_uppreavailable
Definition: cp_ufopedia.cpp:39
const char * to
Definition: cp_research.h:112
Header file for single player campaign control.
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
const ugv_t *IMPORT * Com_GetUGVByIDSilent(const char *ugvID)
aircraftItemType_t type
Definition: inv_shared.h:247
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
bool read
Definition: cp_event.h:50
static const char * UP_AircraftStatToName(int stat)
Translate a aircraft statistic integer to a translated string.
A building with all it&#39;s data.
Definition: cp_building.h:73
static void UP_ResearchedLinkClick_f(void)
Change UFOpaedia article when clicking on the name of associated ammo or weapon.
#define Q_streq(a, b)
Definition: shared.h:136
bool statusResearchable
Definition: cp_research.h:177
char * id
Definition: chr_shared.h:246
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
pediaChapter_t upChapters[MAX_PEDIACHAPTERS]
Definition: cp_campaign.h:323
float weaponDamage
Definition: inv_shared.h:249
eventMail_t * CL_GetEventMail(const char *id)
Searches all event mails for a given id.
Definition: cp_event.cpp:45
technology_t * RS_GetTechForItem(const objDef_t *item)
Returns technology entry for an item.
const char *IMPORT * Com_EParse(const char **text, const char *errhead, const char *errinfo)
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
static struct mdfour * m
Definition: md4.cpp:35
static void UP_GenerateSummary(void)
Generate a tree of option for all allowed chapters and articles.
available mails for a tech - mail and mail_pre in script files
Definition: cp_event.h:38
int numAmmos
Definition: inv_shared.h:308
static char upBuffer[MAX_UPTEXT]
Definition: cp_ufopedia.cpp:48
const char * model
Definition: cp_research.h:118
Defines a type of UGV/Robot.
Definition: chr_shared.h:245
struct technology_s * first
Definition: cp_ufopedia.h:34
byte month
Definition: cp_time.h:38
buildingType_t B_GetBuildingTypeByCapacity(baseCapacities_t cap)
Get building type by base capacity.
Definition: cp_base.cpp:447
static technology_t * upCurrentTech
Definition: cp_ufopedia.cpp:44
static int numChaptersDisplayList
Definition: cp_ufopedia.cpp:42
Definition: cmd.h:86