Also allow to open help file with F1
[meritous_recharged.git] / src / help.c
blob4c47c5454328b1766d941d6cfc7231f98b0e66d7
1 //
2 // help.c
3 //
4 // Copyright 2007, 2008 Lancer-X/ASCEAI
5 //
6 // This file is part of Meritous Recharged.
7 //
8 // Meritous Recharged is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
13 // Meritous Recharged is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with Meritous Recharged. If not, see <http://www.gnu.org/licenses/>.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <math.h>
25 #include <SDL.h>
26 #include <SDL_image.h>
27 #include <string.h>
29 #include "levelblit.h"
31 struct help_line {
32 char *t;
35 struct help_section {
36 int lines;
37 char *identifier;
38 struct help_line *l[256];
41 struct help_file {
42 int sections;
43 struct help_section *s[256];
46 struct help_file *hlp = NULL;
47 struct help_section *itemlist = NULL;
48 int my_line;
49 int my_sec;
50 int itemlistid;
51 int my_cursor;
52 int my_link;
53 int my_return;
55 void InitHelp()
57 FILE *fp;
58 struct help_section *current_sec = NULL;
59 struct help_line *current_line = NULL;
60 char linebuf[80];
61 hlp = malloc(sizeof(struct help_file));
62 hlp->sections = 0;
64 fp = fopen("dat/d/helpfile.txt", "r");
65 while (!feof(fp)) {
66 if (fgets(linebuf, 79, fp) == NULL) {
67 break;
69 if (linebuf[strlen(linebuf)-1] == 0x0A)
70 linebuf[strlen(linebuf)-1] = 0;
72 if (linebuf[0] == '\'') {
73 // comment
74 continue;
76 if (linebuf[0] == ':') {
77 // section
78 hlp->s[hlp->sections] = malloc(sizeof(struct help_section));
79 current_sec = hlp->s[hlp->sections];
80 hlp->sections++;
81 current_sec->identifier = malloc(strlen(linebuf));
82 current_sec->lines = 0;
83 strcpy(current_sec->identifier, linebuf+1);
84 continue;
87 // different line
88 if (current_sec != NULL) {
89 current_sec->l[current_sec->lines] = malloc(sizeof(struct help_line));
90 current_line = current_sec->l[current_sec->lines];
91 current_sec->lines++;
92 current_line->t = malloc(strlen(linebuf)+1);
93 strcpy(current_line->t, linebuf);
96 fclose(fp);
100 int CheckItemlistSection(char* id)
102 if (strcmp(id, "itemlist_header")==0) {
103 return 1;
105 if (strcmp(id, "artifact_map")==0) {
106 if (artifacts[0]) {
107 return 1;
108 } else {
109 return 0;
112 if (strcmp(id, "artifact_shieldbooster")==0) {
113 if (artifacts[1]) {
114 return 1;
115 } else {
116 return 0;
119 if (strcmp(id, "artifact_extracrystalefficiency")==0) {
120 if (artifacts[2]) {
121 return 1;
122 } else {
123 return 0;
126 if (strcmp(id, "artifact_circuitbooster")==0) {
127 if (artifacts[3]) {
128 return 1;
129 } else {
130 return 0;
133 if (strcmp(id, "artifact_metabolismenhancer")==0) {
134 if (artifacts[4]) {
135 return 1;
136 } else {
137 return 0;
140 if (strcmp(id, "artifact_dodgeenhancer")==0) {
141 if (artifacts[5]) {
142 return 1;
143 } else {
144 return 0;
147 if (strcmp(id, "artifact_etherealmonocle")==0) {
148 if (artifacts[6]) {
149 return 1;
150 } else {
151 return 0;
154 if (strcmp(id, "artifact_crystalgatherer")==0) {
155 if (artifacts[7]) {
156 return 1;
157 } else {
158 return 0;
161 if (strcmp(id, "artifact_sword")==0) {
162 if (artifacts[8]) {
163 return 1;
164 } else {
165 return 0;
168 if (strcmp(id, "artifact_halberd")==0) {
169 if (artifacts[9]) {
170 return 1;
171 } else {
172 return 0;
175 if (strcmp(id, "artifact_bow")==0) {
176 if (artifacts[10]) {
177 return 1;
178 } else {
179 return 0;
182 if (strcmp(id, "artifact_seal")==0) {
183 if (artifacts[11]) {
184 return 1;
185 } else {
186 return 0;
189 if (strcmp(id, "artifact_agateknife")==0) {
190 if (player_shield == 30) {
191 return 1;
192 } else {
193 return 0;
196 return 0;
199 void InitItemlistSection()
201 itemlist = malloc(sizeof(struct help_section));
202 itemlist->identifier = malloc(strlen("itemlist"));
203 itemlist->lines = 0;
204 strcpy(itemlist->identifier, "itemlist");
205 hlp->s[hlp->sections] = itemlist;
206 itemlistid = hlp->sections;
207 hlp->sections++;
210 void CreateItemlistSection()
212 itemlist->lines = 0;
213 int currentline = itemlist->lines;
214 struct help_section *sec;
215 struct help_section *no_artifacts = NULL;
216 struct help_section *footer = NULL;
218 int s, l;
219 int sections = 0;
221 if (on_title) {
222 /* In main menu; just print an “excuse” message */
223 for (s=0; s<hlp->sections; s++) {
224 sec = hlp->s[s];
225 if (strcmp(sec->identifier, "itemlist_mainmenu")==0) {
226 for (l=0; l<sec->lines; l++) {
227 itemlist->l[currentline] = sec->l[l];
228 currentline++;
230 itemlist->lines = itemlist->lines + sec->lines;
233 } else {
234 /* In game */
235 for (s=0; s<hlp->sections; s++) {
236 sec = hlp->s[s];
237 if (CheckItemlistSection(sec->identifier)) {
238 for (l=0; l<sec->lines; l++) {
239 itemlist->l[currentline] = sec->l[l];
240 currentline++;
242 itemlist->lines = itemlist->lines + sec->lines;
243 sections++;
245 if (strcmp(sec->identifier, "no_artifacts") == 0) {
246 no_artifacts = sec;
248 if (strcmp(sec->identifier, "itemlist_footer") == 0) {
249 footer = sec;
252 /* If there’s only 1 section, then we only have the intro section
253 and can conclude that there are no artifact sections */
254 if(sections <= 1) {
255 /* Print out special section for when no artifacts have
256 been collected */
257 for (l=0; l<no_artifacts->lines; l++) {
258 itemlist->l[currentline] = no_artifacts->l[l];
259 currentline++;
261 itemlist->lines = itemlist->lines + no_artifacts->lines;
264 /* Print footer */
265 for (l=0; l<footer->lines; l++) {
266 itemlist->l[currentline] = footer->l[l];
267 currentline++;
269 itemlist->lines = itemlist->lines + footer->lines;
273 void BlitArtifact(char* textptr, int i) {
274 int a;
275 SDL_Rect from, to;
276 SDL_Surface* sprite;
278 a = atoi(textptr+1);
279 if(a != 12) {
280 // Not Agate Knife
281 from.x = a * 32;
282 sprite = artifact_spr;
283 } else {
284 // Agate Knife
285 from.x = 0;
286 sprite = agate_knife_spr;
287 if (agate_knife_spr == NULL) {
288 agate_knife_spr = IMG_Load("dat/i/agate.png");
289 SDL_SetColorKey(agate_knife_spr, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
292 from.w = 32;
294 to.x = 40;
295 to.y = 40+i*10+10;
297 if(to.y < 35) {
298 from.h = 32 - (35 - to.y);
299 from.y = 32 - from.h;
300 to.y = to.y + from.y;
301 } else {
302 from.y = 0;
303 from.h = 32;
306 if(to.y > 413) {
307 from.h = 32 - (to.y - 413);
308 } else {
309 from.h = 32;
312 if(from.h > 0 || from.h <= 32) {
313 SDL_BlitSurface(sprite, &from, screen, &to);
317 void DisplayHelp()
319 static int tick = 0;
320 int i;
321 struct help_section *current_sec = NULL;
322 char *ltext;
323 char c_ident[20];
324 int line_num;
325 int follow_link = 0;
326 char linkfollow[20] = "";
328 DrawRect(23, 23, 594, 434, 0);
329 DrawRect(24, 24, 592, 432, 200);
330 DrawRect(25, 25, 590, 430, 255);
331 DrawRect(26, 26, 588, 428, 200);
332 DrawRect(27, 27, 586, 426, 100);
333 DrawRect(30, 30, 580, 420, 20);
334 DrawRect(35, 35, 570, 410, 60);
336 // 70x40 display
337 current_sec = hlp->s[my_sec];
339 if (current_sec->lines > 40) {
340 my_line = my_cursor - 19;
341 } else {
342 my_line = my_cursor - 39;
344 if (my_line < 0) my_line = 0;
345 if (my_line >= (current_sec->lines)) my_line = current_sec->lines - 1;
346 for (i = 0; i < 2; i++) {
347 draw_text(23+i, 40+(my_cursor - my_line)*10, "->", 255);
348 draw_text(599+i, 40+(my_cursor - my_line)*10, "<-", 255);
351 for (i = -5; i < 40; i++) {
352 line_num = my_line + i;
353 if (line_num >= 0) {
354 if (line_num < current_sec->lines) {
355 ltext = current_sec->l[line_num]->t;
356 if (i >= 0) {
357 switch (ltext[0]) {
358 case '!':
360 draw_text(40 + (560-strlen(ltext+1)*8)/2, 40+i*10, ltext+1, 255);
361 break;
362 case '?':
363 strncpy(c_ident, ltext+1, strchr(ltext+1, '?')-ltext-1);
364 c_ident[strchr(ltext+1, '?')-ltext-1] = 0;
366 draw_text(40, 40+i*10, strchr(ltext+1, '?')+1, my_cursor == line_num ? 200+(tick%16)*3 : 150);
367 if ((my_link == 1)&&(my_cursor == line_num)) {
368 follow_link = 1;
369 strcpy(linkfollow, c_ident);
371 break;
372 case ';':
373 draw_text(80, 40+i*10, ltext+1, 200);
374 break;
375 case ',':
376 BlitArtifact(ltext, i);
377 break;
378 default:
379 draw_text(40, 40+i*10, ltext, 200);
380 break;
382 } else {
383 if (ltext[0] == ',') {
384 BlitArtifact(ltext, i);
390 tick++;
391 SDL_UpdateRect(screen, 0, 0, 0, 0);
393 if (my_return) {
394 my_sec = 0;
395 my_cursor = 0;
396 my_return = 0;
399 if (follow_link) {
400 for (i = 0; i < hlp->sections; i++) {
401 if (strcmp(linkfollow, hlp->s[i]->identifier) == 0) {
402 my_sec = i;
403 my_cursor = 0;
404 break;
407 my_link = 0;
411 int MoveCursor()
413 SDL_Event ev;
414 static int key_delay = 0;
415 static int key_up = 0, key_down = 0;
416 static int joy_up = 0, joy_down = 0;
417 int lastline = hlp->s[my_sec]->lines-1;
419 if (key_delay > 0) key_delay--;
421 my_link = 0;
422 while (SDL_PollEvent(&ev)) {
423 if (ev.type == SDL_KEYDOWN) {
424 if (ev.key.keysym.sym == SDLK_DOWN) {
425 key_down = 1;
426 key_delay = 10;
427 if (my_cursor < lastline) my_cursor++;
429 if (ev.key.keysym.sym == SDLK_UP) {
430 key_up = 1;
431 key_delay = 10;
432 if (my_cursor > 0) my_cursor--;
434 if (ev.key.keysym.sym == SDLK_PAGEDOWN) {
435 my_cursor = my_cursor + 40;
436 if (my_cursor > lastline) {
437 my_cursor = lastline;
440 if (ev.key.keysym.sym == SDLK_PAGEUP) {
441 my_cursor = my_cursor - 40;
442 if (my_cursor < 0) {
443 my_cursor = 0;
446 if (ev.key.keysym.sym == SDLK_HOME) {
447 my_cursor = 0;
449 if (ev.key.keysym.sym == SDLK_END) {
450 my_cursor = lastline;
452 if (ev.key.keysym.sym == SDLK_BACKSPACE) {
453 my_return = 1;
455 if (ev.key.keysym.sym == SDLK_ESCAPE) {
456 return 0;
458 if (ev.key.keysym.sym == SDLK_h || ev.key.keysym.sym == SDLK_F1) {
459 return 0;
461 if (ev.key.keysym.sym == SDLK_i) {
462 return 0;
464 if ((ev.key.keysym.sym == SDLK_SPACE) || (ev.key.keysym.sym == SDLK_RETURN))
465 my_link = 1;
468 if (ev.type == SDL_KEYUP) {
469 if (ev.key.keysym.sym == SDLK_DOWN) {
470 key_down = 0;
472 if (ev.key.keysym.sym == SDLK_UP) {
473 key_up = 0;
476 if (ev.type == SDL_JOYHATMOTION) {
477 if (ev.jhat.value & SDL_HAT_DOWN) {
478 joy_down = 1;
479 key_delay = 10;
480 if (my_cursor < lastline) my_cursor++;
481 } else {
482 joy_down = 0;
484 if (ev.jhat.value & SDL_HAT_UP) {
485 joy_up = 1;
486 key_delay = 10;
487 if (my_cursor > 0) my_cursor--;
488 } else {
489 joy_up = 0;
492 if (ev.type == SDL_JOYBUTTONDOWN) {
493 if (ev.jbutton.button == 1) {
494 my_link = 1;
496 if (ev.jbutton.button == 3 || ev.jbutton.button == 4 || ev.jbutton.button == 6) {
497 return 0;
500 if (ev.type == SDL_QUIT) {
501 return 0;
505 if (key_delay == 0) {
506 if (key_up == 1 || joy_up == 1) {
507 if (my_cursor > 0) my_cursor--;
509 if (key_down == 1 || joy_down == 1) {
510 if (my_cursor < hlp->s[my_sec]->lines-1) my_cursor++;
514 return 1;
518 void ShowHelpWindow(int start_section)
520 int in_help = 1;
521 if (hlp == NULL) {
522 InitHelp();
524 if (itemlist == NULL) {
525 InitItemlistSection();
527 CreateItemlistSection();
528 my_sec = start_section;
529 my_line = 0;
530 my_cursor = 0;
531 my_link = 0;
532 my_return = 0;
534 while (in_help)
536 DisplayHelp();
537 in_help = MoveCursor();
538 SDL_Delay(30);
543 void ShowHelp()
545 ShowHelpWindow(0);
548 void ShowItemlist()
549 { if (hlp == NULL) {
550 InitHelp();
552 if (itemlist == NULL) {
553 InitItemlistSection();
555 ShowHelpWindow(itemlistid);