]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/menu/voret/campaign.c
Fix that last arrangement
[voretournament/voretournament.git] / data / qcsrc / menu / voret / campaign.c
1 #ifdef INTERFACE\r
2 CLASS(VoretCampaignList) EXTENDS(VoretListBox)\r
3         METHOD(VoretCampaignList, configureVoretCampaignList, void(entity))\r
4         ATTRIB(VoretCampaignList, rowsPerItem, float, 10)\r
5         METHOD(VoretCampaignList, draw, void(entity))\r
6         METHOD(VoretCampaignList, drawListBoxItem, void(entity, float, vector, float))\r
7         METHOD(VoretCampaignList, clickListBoxItem, void(entity, float, vector))\r
8         METHOD(VoretCampaignList, resizeNotify, void(entity, vector, vector, vector, vector))\r
9         METHOD(VoretCampaignList, setSelected, void(entity, float))\r
10         METHOD(VoretCampaignList, keyDown, float(entity, float, float, float))\r
11         METHOD(VoretCampaignList, campaignGo, void(entity, float))\r
12         METHOD(VoretCampaignList, destroy, void(entity))\r
13 \r
14         ATTRIB(VoretCampaignList, campaignGlob, float, 0)\r
15         ATTRIB(VoretCampaignList, realFontSize, vector, '0 0 0')\r
16         ATTRIB(VoretCampaignList, columnPreviewOrigin, float, 0)\r
17         ATTRIB(VoretCampaignList, columnPreviewSize, float, 0)\r
18         ATTRIB(VoretCampaignList, columnNameOrigin, float, 0)\r
19         ATTRIB(VoretCampaignList, columnNameSize, float, 0)\r
20         ATTRIB(VoretCampaignList, columnCheckMarkOrigin, float, 0)\r
21         ATTRIB(VoretCampaignList, columnCheckMarkSize, float, 0)\r
22         ATTRIB(VoretCampaignList, checkMarkOrigin, vector, '0 0 0')\r
23         ATTRIB(VoretCampaignList, checkMarkSize, vector, '0 0 0')\r
24         ATTRIB(VoretCampaignList, realUpperMargin1, float, 0)\r
25         ATTRIB(VoretCampaignList, realUpperMargin2, float, 0)\r
26 \r
27         ATTRIB(VoretCampaignList, lastClickedMap, float, -1)\r
28         ATTRIB(VoretCampaignList, lastClickedTime, float, 0)\r
29 \r
30         ATTRIB(VoretCampaignList, origin, vector, '0 0 0')\r
31         ATTRIB(VoretCampaignList, itemAbsSize, vector, '0 0 0')\r
32         ATTRIB(VoretCampaignList, emptyLineHeight, float, 0.5)\r
33 \r
34         ATTRIB(VoretCampaignList, campaignIndex, float, 0)\r
35         ATTRIB(VoretCampaignList, cvarName, string, string_null)\r
36         METHOD(VoretCampaignList, loadCvars, void(entity))\r
37         METHOD(VoretCampaignList, saveCvars, void(entity))\r
38 \r
39         ATTRIB(VoretCampaignList, buttonNext, entity, NULL)\r
40         ATTRIB(VoretCampaignList, buttonPrev, entity, NULL)\r
41         ATTRIB(VoretCampaignList, labelTitle, entity, NULL)\r
42 ENDCLASS(VoretCampaignList)\r
43 entity makeVoretCampaignList();\r
44 void CampaignList_LoadMap(entity btn, entity me);\r
45 void MultiCampaign_Next(entity btn, entity me);\r
46 void MultiCampaign_Prev(entity btn, entity me);\r
47 #endif\r
48 \r
49 #ifdef IMPLEMENTATION\r
50 string campaign_longdesc_wrapped[CAMPAIGN_MAX_ENTRIES];\r
51 \r
52 void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)\r
53 {\r
54         float i, j;\r
55         float n, l;\r
56         string r, s;\r
57         for(i = 0; i < campaign_entries; ++i)\r
58         {\r
59                 l = l0;\r
60                 if(campaign_longdesc_wrapped[i])\r
61                         strunzone(campaign_longdesc_wrapped[i]);\r
62                 n = tokenizebyseparator(campaign_longdesc[i], "\n");\r
63                 r = "";\r
64                 for(j = 0; j < n; ++j)\r
65                 {\r
66                         s = argv(j);\r
67                         if(s == "")\r
68                         {\r
69                                 l -= emptyheight;\r
70                                 r = strcat(r, "\n");\r
71                                 continue;\r
72                         }\r
73 \r
74                         getWrappedLine_remaining = s;\r
75                         while(getWrappedLine_remaining)\r
76                         {\r
77                                 s = getWrappedLine(w, theFontSize, draw_TextWidth_WithoutColors);\r
78                                 if(--l < 0) goto toolong;\r
79                                 r = strcat(r, s, "\n");\r
80                         }\r
81                 }\r
82                 goto nottoolong;\r
83 :toolong\r
84                 while(substring(r, strlen(r) - 1, 1) == "\n")\r
85                         r = substring(r, 0, strlen(r) - 1);\r
86                 r = strcat(r, "...\n");\r
87 :nottoolong\r
88                 campaign_longdesc_wrapped[i] = strzone(substring(r, 0, strlen(r) - 1));\r
89         }\r
90 }\r
91 \r
92 entity makeVoretCampaignList()\r
93 {\r
94         entity me;\r
95         me = spawnVoretCampaignList();\r
96         me.configureVoretCampaignList(me);\r
97         return me;\r
98 }\r
99 void configureVoretCampaignListVoretCampaignList(entity me)\r
100 {\r
101         me.configureVoretListBox(me);\r
102         me.campaignGlob = search_begin("maps/campaign*.txt", TRUE, TRUE);\r
103         me.loadCvars(me);\r
104         me.campaignGo(me, 0); // takes care of enabling/disabling buttons too\r
105 }\r
106 \r
107 void destroyVoretCampaignList(entity me)\r
108 {\r
109         if(me.campaignGlob >= 0)\r
110                 search_end(me.campaignGlob);\r
111 }\r
112 \r
113 void loadCvarsVoretCampaignList(entity me)\r
114 {\r
115         // read campaign cvars\r
116         if(campaign_name)\r
117                 strunzone(campaign_name);\r
118         if(me.cvarName)\r
119                 strunzone(me.cvarName);\r
120         campaign_name = strzone(cvar_string("g_campaign_name"));\r
121         me.cvarName = strzone(strcat("g_campaign", campaign_name, "_index"));\r
122         registercvar(me.cvarName, "", 0); // saved by server QC anyway\r
123         CampaignFile_Unload();\r
124         CampaignFile_Load(0, CAMPAIGN_MAX_ENTRIES);\r
125         me.campaignIndex = bound(0, cvar(me.cvarName), campaign_entries);\r
126         cvar_set(me.cvarName, ftos(me.campaignIndex));\r
127         if(me.columnNameSize)\r
128                 rewrapCampaign(me.columnNameSize, me.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);\r
129         me.nItems = min(me.campaignIndex + 2, campaign_entries);\r
130         me.selectedItem = min(me.campaignIndex, me.nItems - 1);\r
131         me.scrollPos = me.nItems * me.itemHeight - 1;\r
132         if(me.labelTitle)\r
133                 me.labelTitle.setText(me.labelTitle, campaign_title);\r
134 }\r
135 \r
136 void saveCvarsVoretCampaignList(entity me)\r
137 {\r
138         // write campaign cvars\r
139         // no reason to do this!\r
140         // cvar_set("g_campaign_name", campaign_name);\r
141         // cvar_set(me.cvarName, ftos(me.campaignIndex)); // NOTE: only server QC does that!\r
142 }\r
143 \r
144 void campaignGoVoretCampaignList(entity me, float step)\r
145 {\r
146         float canNext, canPrev;\r
147         string s;\r
148         float i, j, n;\r
149 \r
150         canNext = canPrev = 0;\r
151 \r
152         if(me.campaignGlob >= 0)\r
153         {\r
154                 n = search_getsize(me.campaignGlob);\r
155                 if(n > 0)\r
156                 {\r
157                         j = -1;\r
158                         s = strcat("maps/campaign", campaign_name, ".txt");\r
159                         for(i = 0; i < n; ++i)\r
160                         {\r
161                                 if(search_getfilename(me.campaignGlob, i) == s)\r
162                                         j = i;\r
163                         }\r
164                         if(j < 0)\r
165                         {\r
166                                 s = strcat("maps/campaign", cvar_defstring("g_campaign_name"), ".txt");\r
167                                 for(i = 0; i < n; ++i)\r
168                                 {\r
169                                         if(search_getfilename(me.campaignGlob, i) == s)\r
170                                                 j = i;\r
171                                 }\r
172                         }\r
173                         if(j < 0)\r
174                         {\r
175                                 if(step >= 0)\r
176                                         j = 0;\r
177                                 else\r
178                                         j = n - 1;\r
179                         }\r
180                         else\r
181                                 j = mod(j + step, n);\r
182                         s = search_getfilename(me.campaignGlob, j);\r
183                         s = substring(s, 13, strlen(s) - 17);\r
184                         cvar_set("g_campaign_name", s);\r
185                         me.loadCvars(me);\r
186                         canNext = (j != n - 1);\r
187                         canPrev = (j != 0);\r
188                 }\r
189         }\r
190 \r
191         if(me.buttonNext)\r
192                 me.buttonNext.disabled = !canNext;\r
193         if(me.buttonPrev)\r
194                 me.buttonPrev.disabled = !canPrev;\r
195 }\r
196 \r
197 void MultiCampaign_Next(entity btn, entity me)\r
198 {\r
199         me.campaignGo(me, +1);\r
200 }\r
201 void MultiCampaign_Prev(entity btn, entity me)\r
202 {\r
203         me.campaignGo(me, -1);\r
204 }\r
205 \r
206 void drawVoretCampaignList(entity me)\r
207 {\r
208         if(cvar(me.cvarName) != me.campaignIndex || cvar_string("g_campaign_name") != campaign_name)\r
209                 me.loadCvars(me);\r
210         drawListBox(me);\r
211 }\r
212 \r
213 void resizeNotifyVoretCampaignList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)\r
214 {\r
215         me.itemAbsSize = '0 0 0';\r
216         resizeNotifyVoretListBox(me, relOrigin, relSize, absOrigin, absSize);\r
217 \r
218         me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));\r
219         me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));\r
220         me.realUpperMargin1 = 0 * me.realFontSize_y;\r
221         me.realUpperMargin2 = me.realUpperMargin1 + 2 * me.realFontSize_y;\r
222 \r
223         me.checkMarkSize = (eX * (me.itemAbsSize_y / me.itemAbsSize_x) + eY) * 0.5;\r
224 \r
225         me.columnPreviewOrigin = 0;\r
226         me.columnPreviewSize = me.itemAbsSize_y / me.itemAbsSize_x * 4 / 3;\r
227         me.columnCheckMarkSize = me.checkMarkSize_x;\r
228         me.columnNameSize = 1 - me.columnPreviewSize - me.columnCheckMarkSize - 4 * me.realFontSize_x;\r
229         me.columnNameOrigin = me.columnPreviewOrigin + me.columnPreviewSize + me.realFontSize_x;\r
230         me.columnCheckMarkOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x * 2;\r
231 \r
232         me.checkMarkOrigin = eY + eX * (me.columnCheckMarkOrigin + me.columnCheckMarkSize) - me.checkMarkSize;\r
233 \r
234         rewrapCampaign(me.columnNameSize, me.rowsPerItem - 2, me.emptyLineHeight, me.realFontSize);\r
235 }\r
236 void clickListBoxItemVoretCampaignList(entity me, float i, vector where)\r
237 {\r
238         if(i == me.lastClickedMap)\r
239                 if(time < me.lastClickedTime + 0.3)\r
240                 {\r
241                         // DOUBLE CLICK!\r
242                         // start game\r
243                         CampaignList_LoadMap(me, me);\r
244                         return;\r
245                 }\r
246         me.lastClickedMap = i;\r
247         me.lastClickedTime = time;\r
248 }\r
249 void drawListBoxItemVoretCampaignList(entity me, float i, vector absSize, float isSelected)\r
250 {\r
251         string s;\r
252         float p;\r
253         vector theColor;\r
254         float theAlpha;\r
255         float j, n;\r
256         vector o;\r
257 \r
258         if(i < me.campaignIndex)\r
259         {\r
260                 theAlpha = SKINALPHA_CAMPAIGN_SELECTABLE;\r
261                 theColor = SKINCOLOR_CAMPAIGN_SELECTABLE;\r
262         }\r
263         else if(i == me.campaignIndex)\r
264         {\r
265                 theAlpha = SKINALPHA_CAMPAIGN_CURRENT;\r
266                 theColor = SKINCOLOR_CAMPAIGN_CURRENT;\r
267         }\r
268         else\r
269         {\r
270                 theAlpha = SKINALPHA_CAMPAIGN_FUTURE;\r
271                 theColor = SKINCOLOR_CAMPAIGN_FUTURE;\r
272         }\r
273 \r
274         if(isSelected)\r
275                 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);\r
276 \r
277         s = ftos(p);\r
278         draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", campaign_mapname[i]), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);\r
279         if(i < me.campaignIndex)\r
280                 draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);\r
281         if(i <= me.campaignIndex)\r
282                 s = campaign_shortdesc[i]; // fteqcc sucks\r
283         else\r
284                 s = "???";\r
285         s = draw_TextShortenToWidth(strcat("Level ", ftos(i + 1), ": ", s), me.columnNameSize, 0, me.realFontSize);\r
286         draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
287 \r
288         if(i <= me.campaignIndex)\r
289         {\r
290                 s = campaign_longdesc_wrapped[i];\r
291                 n = tokenizebyseparator(s, "\n");\r
292                 o = me.realUpperMargin2 * eY + me.columnNameOrigin * eX;\r
293                 for(j = 0; j < n; ++j)\r
294                         if(argv(j) != "")\r
295                         {\r
296                                 draw_Text(o, argv(j), me.realFontSize, theColor, theAlpha * SKINALPHA_CAMPAIGN_DESCRIPTION, 0);\r
297                                 o_y += me.realFontSize_y;\r
298                         }\r
299                         else\r
300                                 o_y += me.realFontSize_y * me.emptyLineHeight;\r
301         }\r
302 }\r
303 void CampaignList_LoadMap(entity btn, entity me)\r
304 {\r
305         if(me.selectedItem >= me.nItems || me.selectedItem < 0)\r
306                 return;\r
307         CampaignSetup(me.selectedItem);\r
308 }\r
309 \r
310 void setSelectedVoretCampaignList(entity me, float i)\r
311 {\r
312         // prevent too late items from being played\r
313         setSelectedListBox(me, min(i, me.campaignIndex));\r
314 }\r
315 \r
316 float keyDownVoretCampaignList(entity me, float scan, float ascii, float shift)\r
317 {\r
318         if(scan == K_ENTER || scan == K_SPACE)\r
319                 CampaignList_LoadMap(me, me);\r
320         else\r
321                 return keyDownListBox(me, scan, ascii, shift);\r
322         return 1;\r
323 }\r
324 #endif\r