Xonotic
campaign.qc
Go to the documentation of this file.
1 #include "campaign.qh"
2 
4 #include "inputbox.qh"
5 
7 
8 void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)
9 {
10  int i, j;
11  int n;
12  float l;
13  string r, s;
14  for(i = 0; i < campaign_entries; ++i)
15  {
16  l = l0;
19  r = "";
20  for(j = 0; j < n; ++j)
21  {
22  s = argv(j);
23  if(s == "")
24  {
25  l -= emptyheight;
26  r = strcat(r, "\n");
27  continue;
28  }
29 
32  {
33  s = getWrappedLine(w, theFontSize, draw_TextWidth_WithoutColors);
34  if(--l < 0) goto toolong;
35  r = strcat(r, s, "\n");
36  }
37  }
38  goto nottoolong;
39 LABEL(toolong)
40  while(substring(r, strlen(r) - 1, 1) == "\n")
41  r = substring(r, 0, strlen(r) - 1);
42  r = strcat(r, "...\n");
43 LABEL(nottoolong)
45  }
46 }
47 
49 {
50  entity me;
52  me.configureXonoticCampaignList(me);
53  return me;
54 }
56 {
57  me.configureXonoticListBox(me);
58  me.campaignGlob = search_begin("maps/campaign*.txt", true, true);
59  me.loadCvars(me);
60  me.campaignGo(me, 0); // it makes work buttons too
61 }
62 
64 {
65  if(me.campaignGlob >= 0)
66  search_end(me.campaignGlob);
67 }
68 
70 {
71  // read campaign cvars
72  strcpy(campaign_name, cvar_string("g_campaign_name"));
73  strcpy(me.controlledCvar, strcat("g_campaign", campaign_name, "_index"));
74  registercvar(me.controlledCvar, "", 0); // saved by server QC anyway
77  me.campaignIndex = bound(0, cvar(me.controlledCvar), campaign_entries);
78  cvar_set(me.controlledCvar, ftos(me.campaignIndex));
79  if(me.columnNameSize)
80  rewrapCampaign(me.columnNameSize, me.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
81  me.nItems = min(me.campaignIndex + 2, campaign_entries);
82  me.setSelected(me, min(me.campaignIndex, me.nItems - 1));
83  if(me.nItems - 1 > me.campaignIndex)
84  me.scrollToItem(me, me.nItems - 1);
85  if(me.labelTitle)
86  me.labelTitle.setText(me.labelTitle, campaign_title);
87 }
88 
90 {
91  // write campaign cvars
92  // no reason to do this!
93  // cvar_set("g_campaign_name", campaign_name);
94  // cvar_set(me.controlledCvar, ftos(me.campaignIndex)); // NOTE: only server QC does that!
95 }
96 
98 {
99  string s;
100  float i, j, n;
101 
102  if(me.campaignGlob >= 0)
103  {
104  n = search_getsize(me.campaignGlob);
105  if(n > 0)
106  {
107  j = -1;
108  s = strcat("maps/campaign", campaign_name, ".txt");
109  for(i = 0; i < n; ++i)
110  {
111  if(search_getfilename(me.campaignGlob, i) == s)
112  j = i;
113  }
114  if(j < 0)
115  {
116  s = strcat("maps/campaign", cvar_defstring("g_campaign_name"), ".txt");
117  for(i = 0; i < n; ++i)
118  {
119  if(search_getfilename(me.campaignGlob, i) == s)
120  j = i;
121  }
122  }
123  if(j < 0)
124  {
125  if(step >= 0)
126  j = 0;
127  else
128  j = n - 1;
129  }
130  else
131  j = mod(j + step, n);
132  s = search_getfilename(me.campaignGlob, j);
133  s = substring(s, 13, strlen(s) - 17);
134  cvar_set("g_campaign_name", s);
135  me.loadCvars(me);
136  me.hasNextCampaign = (j != n - 1);
137  me.hasPrevCampaign = (j != 0);
138  }
139  }
140 }
141 
143 {
144  me.campaignGo(me, +1);
145 }
147 {
148  me.campaignGo(me, -1);
149 }
150 
152 {
153  if(me.buttonNext)
154  me.buttonNext.disabled = !me.hasNextCampaign;
155  if(me.buttonPrev)
156  me.buttonPrev.disabled = !me.hasPrevCampaign;
157 
158  if(cvar(me.controlledCvar) != me.campaignIndex || cvar_string("g_campaign_name") != campaign_name)
159  me.loadCvars(me);
160  SUPER(XonoticCampaignList).draw(me);
161 }
162 
163 void XonoticCampaignList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
164 {
165  me.itemAbsSize = '0 0 0';
166  SUPER(XonoticCampaignList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
167 
168  me.itemAbsSize.y = absSize.y * me.itemHeight;
169  me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
170  me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
171  me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
172  me.realUpperMargin1 = 0.5 * me.realFontSize.y;
173  me.realUpperMargin2 = me.realUpperMargin1 + 2 * me.realFontSize.y;
174 
175  me.checkMarkSize = (eX * (me.itemAbsSize.y / me.itemAbsSize.x) + eY) * 0.5;
176 
177  me.columnPreviewOrigin = 0;
178  me.columnPreviewSize = me.itemAbsSize.y / me.itemAbsSize.x * 4 / 3;
179  me.columnCheckMarkSize = me.checkMarkSize.x;
180  me.columnNameSize = 1 - me.columnPreviewSize - me.columnCheckMarkSize - 4 * me.realFontSize.x;
181  me.columnNameOrigin = me.columnPreviewOrigin + me.columnPreviewSize + me.realFontSize.x;
182  me.columnCheckMarkOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize.x * 2;
183 
184  me.checkMarkOrigin = eY + eX * (me.columnCheckMarkOrigin + me.columnCheckMarkSize) - me.checkMarkSize;
185 
186  me.typeIconOrigin = vec3(me.columnPreviewSize - me.checkMarkSize.x, me.checkMarkOrigin.y, 0);
187  me.typeIconSize = me.checkMarkSize;
188 
189  rewrapCampaign(me.columnNameSize, me.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
190 }
192 {
193  CampaignList_LoadMap(me, me);
194 }
195 void XonoticCampaignList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
196 {
197  string s;
198  vector theColor;
199  float theAlpha;
200  float j, n;
201  vector o;
202 
203  if(i < me.campaignIndex)
204  {
205  theAlpha = SKINALPHA_CAMPAIGN_SELECTABLE;
206  theColor = SKINCOLOR_CAMPAIGN_SELECTABLE;
207  }
208  else if(i == me.campaignIndex)
209  {
210  theAlpha = SKINALPHA_CAMPAIGN_CURRENT;
211  theColor = SKINCOLOR_CAMPAIGN_CURRENT;
212  }
213  else
214  {
215  theAlpha = SKINALPHA_CAMPAIGN_FUTURE;
216  theColor = SKINCOLOR_CAMPAIGN_FUTURE;
217  }
218 
219  if(isSelected)
220  draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
221  else if(isFocused)
222  {
223  me.focusedItemAlpha = getFadedAlpha(me.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED);
224  draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
225  }
226 
227  if(draw_PictureSize(strcat("/maps/", campaign_mapname[i])) == '0 0 0')
228  draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
229  else
230  draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", campaign_mapname[i]), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
231 
232  s = strcat("/gfx/menu/", cvar_string("menu_skin"), "/gametype_", campaign_gametype[i]);
233  if(i <= me.campaignIndex && draw_PictureSize(s) != '0 0 0')
234  draw_Picture(me.typeIconOrigin, s, me.typeIconSize, '1 1 1', 1);
235 
236  if(i < me.campaignIndex)
237  draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);
238  if(i <= me.campaignIndex)
239  s = campaign_shortdesc[i]; // fteqcc sucks
240  else
241  s = "???";
242  // NOTE the following string is equal to the one used in the campaign level notification
243  // (CAMPAIGN_MESSAGE) to avoid adding another duplicate string to translate
244  s = draw_TextShortenToWidth(strcat(sprintf(_("Level %s: "), itos(i+1)), s), me.columnNameSize, 0, me.realFontSize);
245  draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, theColor, theAlpha, 0);
246 
247  if(i <= me.campaignIndex)
248  {
250  n = tokenizebyseparator(s, "\n");
251  o = me.realUpperMargin2 * eY + me.columnNameOrigin * eX;
252  for(j = 0; j < n; ++j)
253  if(argv(j) != "")
254  {
255  draw_Text(o, argv(j), me.realFontSize, theColor, theAlpha * SKINALPHA_CAMPAIGN_DESCRIPTION, 0);
256  o.y += me.realFontSize.y;
257  }
258  else
259  o.y += me.realFontSize.y * me.emptyLineHeight;
260  }
261 }
263 {
264  if(me.selectedItem >= me.nItems || me.selectedItem < 0)
265  return;
266  CampaignSetup(me.selectedItem);
267 }
268 
270 {
271  // prevent too late items from being played
272  SUPER(XonoticCampaignList).setSelected(me, min(i, me.campaignIndex));
273 }
274 
275 float XonoticCampaignList_keyDown(entity me, float scan, float ascii, float shift)
276 {
277  if(scan == K_ENTER || scan == K_SPACE || scan == K_KP_ENTER)
278  CampaignList_LoadMap(me, me);
279  else
280  return SUPER(XonoticCampaignList).keyDown(me, scan, ascii, shift);
281  return 1;
282 }
string campaign_name
string campaign_shortdesc[CAMPAIGN_MAX_ENTRIES]
const vector eY
Definition: vector.qh:45
string getWrappedLine_remaining
Definition: util.qh:108
#define NEW(cname,...)
Definition: oo.qh:105
void CampaignSetup(int n)
entity() spawn
#define vec3(_x, _y, _z)
Definition: vector.qh:95
#define itos(i)
Definition: int.qh:6
float K_SPACE
Definition: keycodes.qc:10
float K_KP_ENTER
Definition: keycodes.qc:74
#define strcpy(this, s)
Definition: string.qh:49
#define SUPER(cname)
Definition: oo.qh:219
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string campaign_title
int campaign_entries
#define CAMPAIGN_MAX_ENTRIES
vector(float skel, float bonenum) _skel_get_boneabs_hidden
string campaign_gametype[CAMPAIGN_MAX_ENTRIES]
string campaign_longdesc[CAMPAIGN_MAX_ENTRIES]
const vector eX
Definition: vector.qh:44
#define tokenizebyseparator
Definition: dpextensions.qh:21
#define LABEL(id)
Definition: compiler.qh:36
#define strfree(this)
Definition: string.qh:56
float K_ENTER
Definition: keycodes.qc:8
string campaign_mapname[CAMPAIGN_MAX_ENTRIES]
string getWrappedLine(float w, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition: util.qc:880
float CampaignFile_Load(float offset, float entries)
void CampaignFile_Unload()