]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/CEngine.cpp
45f30eff7d65632ea499b839addaa083a480a5d2
[quix0rs-blobwars.git] / src / CEngine.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 */
21
22 #include "headers.h"
23 #include <errno.h>
24 extern Graphics graphics;
25
26 Engine::Engine()
27 {
28         memset(keyState, 0, sizeof keyState);
29
30         memset(joystickState, 0, sizeof joystickState);
31
32         joyX = joyY = 0;
33
34         mouseLeft = mouseRight = 0;
35         waitForButton = false;
36         waitForKey = false;
37         
38         allowJoypad = true;
39
40         lastKeyPressed[0] = 0;
41
42         fullScreen = 0;
43
44         useAudio = 2;
45         
46         practice = false;
47         
48         allowQuit = false;
49
50         saveConfig = false;
51
52         highlightedWidget = NULL;
53
54         message[0] = 0;
55         messageTime = -1;
56
57         // Development Stuff
58         devNoMonsters = false;
59
60         dataBuffer = NULL;
61         binaryBuffer = NULL;
62         #ifdef FRAMEWORK_SDL
63         char pakPath[PATH_MAX];
64         strlcpy(pakPath, PAKFULLPATH, sizeof(pakPath));
65         if (CFBundleGetMainBundle() != NULL) {
66                 CFURLRef pakURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR(PAKNAME), NULL, NULL);
67                 if (pakURL != NULL) {
68                         CFShow(pakURL);
69                         CFURLGetFileSystemRepresentation(pakURL, true, (UInt8*)pakPath, sizeof(pakPath));
70                         CFRelease(pakURL);
71                 }
72         }
73         pak.setPakFile(pakPath);
74         #else
75         pak.setPakFile(PAKFULLPATH);
76         #endif
77
78         // Timer
79         time1 = time2 = 0;
80         timeDifference = 0;
81
82         // Cheats
83         memset(lastKeyEvents, ' ', 25);
84         cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
85         cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
86         
87         extremeAvailable = 0;
88 }
89
90 void Engine::destroy()
91 {
92         debug(("engine: free widgets\n"));
93         deleteWidgets();
94
95         debug(("engine: free databuffer\n"));
96         delete[] dataBuffer;
97
98         debug(("engine: free binarybuffer\n"));
99         delete[] binaryBuffer;
100
101         debug(("Clearing Define List...\n"));
102         defineList.clear();
103 }
104
105 void Engine::clearCheatVars()
106 {
107         memset(lastKeyEvents, ' ', 25);
108         cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
109         cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
110 }
111
112 bool Engine::compareLastKeyInputs()
113 {
114         if (strstr(lastKeyEvents, "lockandload"))
115         {
116                 cheats = true;
117                 return true;
118         }
119
120         return false;
121 }
122
123 void Engine::addKeyEvent()
124 {
125         if (strlen(lastKeyPressed) > 1)
126         {
127                 return;
128         }
129
130         int index = -1;
131
132         for (int i = 0 ; i < 25 ; i++)
133         {
134                 if (lastKeyEvents[i] == ' ')
135                 {
136                         index = i;
137                         break;
138                 }
139         }
140
141         if (index == -1)
142         {
143                 for (int i = 0 ; i < 24 ; i++)
144                 {
145                         lastKeyEvents[i] = lastKeyEvents[i + 1];
146                 }
147
148                 index = 24;
149         }
150
151         lastKeyEvents[index] = lastKeyPressed[0];
152
153         compareLastKeyInputs();
154 }
155
156 void Engine::getInput()
157 {
158         SDL_GetMouseState(&mouseX, &mouseY);
159
160         // Scale from window coordinates to graphics coordinates
161         int w, h;
162         SDL_GetWindowSize(graphics.window, &w, &h);
163         mouseX = mouseX * 640 / w;
164         mouseY = mouseY * 480 / h;
165
166         while (SDL_PollEvent(&event))
167         {
168                 switch (event.type)
169                 {
170                         case SDL_QUIT:
171                                 if (allowQuit)
172                                 {
173                                         exit(0);
174                                 }
175                                 break;
176
177                         case SDL_MOUSEBUTTONDOWN:
178                                 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 1;
179                                 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 1;
180                                 break;
181
182                         case SDL_MOUSEBUTTONUP:
183                                 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 0;
184                                 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 0;
185                                 break;
186
187                         case SDL_KEYDOWN:
188                                 
189                                 if (waitForButton)
190                                 {
191                                         if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
192                                         {
193                                                 lastButtonPressed = -1;
194                                                 *highlightedWidget->value = abs(*highlightedWidget->value) - 1000;
195                                                 highlightedWidget->redraw();
196                                                 waitForButton = false;
197                                                 allowJoypad = false;
198                                         }
199                                         
200                                         if (event.key.keysym.scancode == SDL_SCANCODE_BACKSPACE)
201                                         {
202                                                 lastButtonPressed = -2;
203                                                 *highlightedWidget->value = -2;
204                                                 highlightedWidget->redraw();
205                                                 waitForButton = false;
206                                                 allowJoypad = false;
207                                         }
208                                         
209                                         return;
210                                 }
211                                 
212                                 if (waitForKey)
213                                 {
214                                         if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
215                                         {
216                                                 *highlightedWidget->value = -*highlightedWidget->value;
217                                         }
218                                         else
219                                         {
220                                                 *highlightedWidget->value = event.key.keysym.scancode;
221                                         }
222                                         
223                                         lastButtonPressed = -1;
224                                         highlightedWidget->redraw();
225                                         waitForButton = false;
226                                         waitForKey = false;
227                                         allowJoypad = false;
228                                         
229                                         return;
230                                 }
231
232                                 keyState[event.key.keysym.scancode] = 1;
233                                 strlcpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.scancode), sizeof lastKeyPressed);
234                                 addKeyEvent();
235                                 break;
236
237                         case SDL_KEYUP:
238                                 keyState[event.key.keysym.scancode] = 0;
239                                 break;
240
241                         case SDL_JOYAXISMOTION:
242                                 if (event.jaxis.axis == 0)
243                                 {
244                                   joyX = event.jaxis.value;
245                                 }
246                                 else if (event.jaxis.axis == 1)
247                                 {
248                                   joyY = event.jaxis.value;
249                                 }
250                                 
251                                 break;
252
253                         case SDL_JOYBUTTONDOWN:
254                         
255                                 if (waitForButton)
256                                 {
257                                         lastButtonPressed = event.jbutton.button;
258                                         *highlightedWidget->value = lastButtonPressed;
259                                         highlightedWidget->redraw();
260                                         waitForButton = false;
261                                         allowJoypad = false;
262                                         return;
263                                 }
264                                 
265                                 joystickState[event.jbutton.button] = 1;
266                                 break;
267
268                         case SDL_JOYBUTTONUP:
269                                 joystickState[event.jbutton.button] = 0;
270                                 break;
271
272                         case SDL_WINDOWEVENT:
273                                 if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
274                                         paused = true;
275                                 break;
276
277                         default:
278                                 break;
279                 }
280         }
281 }
282
283 int Engine::getMouseX() const
284 {
285         return mouseX;
286 }
287
288 int Engine::getMouseY() const
289 {
290         return mouseY;
291 }
292
293 void Engine::setMouse(int x, int y)
294 {
295         SDL_WarpMouseInWindow(graphics.window, x, y);
296 }
297
298 bool Engine::userAccepts()
299 {
300         if ((keyState[SDL_SCANCODE_SPACE]) || (keyState[SDL_SCANCODE_ESCAPE]) || (keyState[SDL_SCANCODE_LCTRL]) || (keyState[SDL_SCANCODE_RCTRL]) || (keyState[SDL_SCANCODE_RETURN]) || (keyState[SDL_SCANCODE_LCTRL]))
301         {
302                 return true;
303         }
304
305         return false;
306 }
307
308 void Engine::flushInput()
309 {
310         while (SDL_PollEvent(&event)){}
311 }
312
313 void Engine::clearInput()
314 {
315         memset(keyState, 0, sizeof keyState);
316
317         mouseLeft = mouseRight = 0;
318 }
319
320 void Engine::setUserHome(const char *path)
321 {
322         strlcpy(userHomeDirectory, path, sizeof userHomeDirectory);
323         debug(("User Home = %s\n", path));
324 }
325
326 Pak *Engine::getPak()
327 {
328         return &pak;
329 }
330
331 /*
332 Searches the pak file for the required data. When
333 it is found, the data is read into a character buffer.
334 In the case of music, the data music be written to a temporary directory
335 since SDL currently provides no means to load music directly from memory
336 */
337 bool Engine::unpack(const char *filename, int fileType)
338 {
339         bool ret = true;
340
341         if (fileType == PAK_DATA)
342         {
343                 delete[] dataBuffer;
344                 dataBuffer = NULL;
345         }
346         else
347         {
348                 delete[] binaryBuffer;
349                 binaryBuffer = NULL;
350         }
351
352         if (fileType != PAK_DATA)
353         {
354                 if (!pak.unpack(filename, &binaryBuffer))
355                 {
356                         return false;
357                 }
358         }
359         else
360         {
361                 if (!pak.unpack(filename, &dataBuffer))
362                 {
363                         return false;
364                 }
365         }
366
367         if ((fileType == PAK_IMG) || (fileType == PAK_SOUND))
368         {
369                 sdlrw = SDL_RWFromMem(binaryBuffer, pak.getUncompressedSize());
370                 if (!sdlrw)
371                 {
372                         printf("Fatal Error: SDL_RWops allocation failed\n");
373                         exit(1);
374                 }
375         }
376
377         if ((fileType == PAK_MUSIC) || (fileType == PAK_FONT) || (fileType == PAK_TAGS))
378         {
379                 char tempPath[PATH_MAX];
380                 
381                 FILE *fp = NULL;
382
383                 if (fileType == PAK_MUSIC)
384                 {
385                         snprintf(tempPath, sizeof tempPath, "%smusic.mod", userHomeDirectory);
386                         fp = fopen(tempPath, "wb");
387                 }
388
389                 if (fileType == PAK_TAGS)
390                 {
391                         snprintf(tempPath, sizeof tempPath, "%smusic.tags", userHomeDirectory);
392                         fp = fopen(tempPath, "wb");
393                 }
394
395                 if (fileType == PAK_FONT)
396                 {
397                         snprintf(tempPath, sizeof tempPath, "%sfont.ttf", userHomeDirectory);
398                         fp = fopen(tempPath, "wb");
399                 }
400
401                 if (!fp)
402                 {
403                         printf("Fatal Error: could not open %s for writing: %s", tempPath, strerror(errno));
404                         return false;
405                 }
406
407                 if (fwrite(binaryBuffer, 1, pak.getUncompressedSize(), fp) != pak.getUncompressedSize())
408                 {
409                         printf("Fatal Error: could not write to %s: %s", tempPath, strerror(errno));
410                         ret = false;
411                 }
412                 fclose(fp);
413         }
414
415         debug(("unpack() : Loaded %s (%d), ret: %d\n", filename, pak.getUncompressedSize(), (int)ret));
416
417         return ret;
418 }
419
420 bool Engine::loadData(const char *filename)
421 {
422         bool ret = true;
423
424         delete[] dataBuffer;
425         dataBuffer = NULL;
426         
427         #if USEPAK
428                 return unpack(filename, PAK_DATA);
429         #endif
430
431         FILE *fp;
432         fp = fopen(filename, "rb");
433         if (fp == NULL)
434                 return false;
435
436         fseek(fp, 0, SEEK_END);
437
438         int fSize = ftell(fp);
439
440         rewind(fp);
441
442         dataBuffer = new unsigned char[fSize + 1];
443
444         if (fread(dataBuffer, 1, fSize, fp) != (size_t)fSize)
445                 ret = false;
446
447         dataBuffer[fSize] = 0;
448
449         fclose(fp);
450
451         debug(("loadData() : Loaded %s (%d), ret: %d\n", filename, fSize, (int)ret));
452
453         return ret;
454 }
455
456 void Engine::reportFontFailure()
457 {
458         printf("\nUnable to load font. The game cannot continue without it.\n");
459         printf("Please confirm that the game and all required SDL libraries are installed\n");
460         printf("The following information may be useful to you,\n\n");
461         printf("Expected location of PAK file: %s\n", PAKFULLPATH);
462         printf("Location of TMP directory: %s\n", userHomeDirectory);
463         printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
464         exit(1);
465 }
466
467 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
468 {
469         playerPosX = x - OFFSETX;
470         playerPosY = y - OFFSETY;
471
472         Math::limitInt(&playerPosX, limitLeft, limitRight);
473         Math::limitInt(&playerPosY, limitUp, limitDown);
474 }
475
476 int Engine::getFrameLoop() const
477 {
478         return frameLoop;
479 }
480
481 void Engine::doFrameLoop()
482 {
483         Math::wrapChar(&(++frameLoop), 0, 59);
484 }
485
486 void Engine::doTimeDifference()
487 {
488         timeDifference = (time2 - time1) / 10.0;
489         time1 = time2;
490         time2 = SDL_GetTicks();
491 }
492
493 float Engine::getTimeDifference() const
494 {
495         return timeDifference;
496 }
497
498 void Engine::resetTimeDifference()
499 {
500         time1 = time2 = SDL_GetTicks();
501 }
502
503 void Engine::setInfoMessage(const char *message, int priority, int type)
504 {
505         if (priority >= messagePriority)
506         {
507                 strlcpy(this->message, message, sizeof this->message);
508                 messageTime = 180;
509                 messagePriority = priority;
510                 messageType = type;
511         }
512 }
513
514 void Engine::deleteWidgets()
515 {
516         Widget *widget;
517
518         for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
519                 widget->redraw();
520
521         widgetList.clear();
522
523         highlightedWidget = NULL;
524 }
525
526 void Engine::addWidget(Widget *widget)
527 {
528         widget->previous = (Widget*)widgetList.getTail();
529         widgetList.add(widget);
530 }
531
532 bool Engine::loadWidgets(const char *filename)
533 {
534         deleteWidgets();
535
536         if (!loadData(filename))
537                 return false;
538
539         char token[50], name[50], groupName[50], label[80], options[100], *line;
540         int x, y, min, max;
541
542         int i;
543
544         Widget *widget;
545
546         line = strtok((char*)dataBuffer, "\n");
547
548         while (true)
549         {
550                 sscanf(line, "%s", token);
551
552                 if (strcmp(token, "END") == 0)
553                         break;
554
555                 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
556
557                 widget = new Widget;
558
559                 i = 0;
560
561                 while (true)
562                 {
563                         if (strcmp(token, widgetName[i]) == 0)
564                                 widget->type = i;
565
566                         if (strcmp("-1", widgetName[i]) == 0)
567                                 break;
568
569                         i++;
570                 }
571
572                 widget->setProperties(name, groupName, label, options, x, y, min, max);
573
574                 addWidget(widget);
575
576
577                 if ((line = strtok(NULL, "\n")) == NULL)
578                         break;
579         }
580
581         highlightedWidget = (Widget*)widgetList.getHead()->next;
582
583         return true;
584 }
585
586 Widget *Engine::getWidgetByName(const char *name)
587 {
588         Widget *widget = (Widget*)widgetList.getHead();
589
590         while (widget->next != NULL)
591         {
592                 widget = (Widget*)widget->next;
593
594                 if (strcmp(widget->name, name) == 0)
595                         return widget;
596         }
597
598         debug(("No such widget '%s'\n", name));
599
600         return NULL;
601 }
602
603 void Engine::showWidgetGroup(const char *groupName, bool show)
604 {
605         bool found = false;
606
607         Widget *widget = (Widget*)widgetList.getHead();
608
609         while (widget->next != NULL)
610         {
611                 widget = (Widget*)widget->next;
612
613                 if (strcmp(widget->groupName, groupName) == 0)
614                 {
615                         widget->visible = show;
616                         widget->redraw();
617                         found = true;
618                 }
619         }
620
621         if (!found)
622                 debug(("Group '%s' does not exist\n", groupName));
623 }
624
625 void Engine::enableWidgetGroup(const char *groupName, bool show)
626 {
627         bool found = false;
628
629         Widget *widget = (Widget*)widgetList.getHead();
630
631         while (widget->next != NULL)
632         {
633                 widget = (Widget*)widget->next;
634
635                 if (strcmp(widget->groupName, groupName) == 0)
636                 {
637                         widget->enabled = show;
638                         widget->redraw();
639                         found = true;
640                 }
641         }
642
643         if (!found)
644                 debug(("Group '%s' does not exist\n", groupName));
645 }
646
647 void Engine::showWidget(const char *name, bool show)
648 {
649         Widget *widget = getWidgetByName(name);
650         if (widget != NULL)
651         {
652                 widget->visible = show;
653                 widget->redraw();
654         }
655 }
656
657 void Engine::enableWidget(const char *name, bool enable)
658 {
659         Widget *widget = getWidgetByName(name);
660         if (widget != NULL)
661         {
662                 widget->enabled = enable;
663                 widget->redraw();
664         }
665 }
666
667 void Engine::setWidgetVariable(const char *name, int *variable)
668 {
669         Widget *widget = getWidgetByName(name);
670         if (widget != NULL)
671                 widget->value = variable;
672 }
673
674 bool Engine::widgetChanged(const char *name)
675 {
676         Widget *widget = getWidgetByName(name);
677         if (widget != NULL)
678                 return widget->changed;
679
680         return false;
681 }
682
683 void Engine::highlightWidget(int dir)
684 {
685         highlightedWidget->redraw();
686
687         if (dir == 1)
688         {
689                 while (true)
690                 {
691                         if (highlightedWidget->next != NULL)
692                         {
693                                 highlightedWidget = (Widget*)highlightedWidget->next;
694                         }
695                         else
696                         {
697                                 highlightedWidget = (Widget*)widgetList.getHead()->next;
698                         }
699
700                         if (highlightedWidget->type == 4)
701                                 continue;
702
703                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
704                                 break;
705                 }
706         }
707
708         if (dir == -1)
709         {
710                 while (true)
711                 {
712                         if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
713                         {
714                                 highlightedWidget = highlightedWidget->previous;
715                         }
716                         else
717                         {
718                                 highlightedWidget = (Widget*)widgetList.getTail();
719                         }
720
721                         if (highlightedWidget->type == WG_LABEL)
722                                 continue;
723
724                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
725                                 break;
726                 }
727         }
728
729         highlightedWidget->redraw();
730 }
731
732 void Engine::highlightWidget(const char *name)
733 {
734         highlightedWidget = getWidgetByName(name);
735 }
736
737 int Engine::processWidgets()
738 {
739         int update = 0;
740
741         if (keyState[SDL_SCANCODE_UP])
742         {
743                 highlightWidget(-1);
744                 update = 1;
745                 clearInput();
746         }
747
748         if (keyState[SDL_SCANCODE_DOWN])
749         {
750                 highlightWidget(1);
751                 update = 1;
752                 clearInput();
753         }
754
755         if (keyState[SDL_SCANCODE_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
756         {
757                 SDL_Delay(1);
758
759                 if (*highlightedWidget->value > highlightedWidget->min)
760                 {
761                         *highlightedWidget->value = *highlightedWidget->value - 1;
762                         update = 3;
763                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
764                                 update = 1;
765                         highlightedWidget->changed = true;
766                 }
767
768                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
769                         clearInput();
770         }
771
772         if (keyState[SDL_SCANCODE_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
773         {
774                 SDL_Delay(1);
775
776                 if (*highlightedWidget->value < highlightedWidget->max)
777                 {
778                         *highlightedWidget->value = *highlightedWidget->value + 1;
779                         update = 3;
780                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
781                                 update = 1;
782                         highlightedWidget->changed = true;
783                 }
784
785                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
786                         clearInput();
787         }
788
789         if ((keyState[SDL_SCANCODE_RETURN]) || (keyState[SDL_SCANCODE_SPACE]) || (keyState[SDL_SCANCODE_LCTRL]))
790         {
791                 if (highlightedWidget->value == NULL)
792                 {
793                         debug(("%s has not been implemented!\n", highlightedWidget->name));
794                 }
795                 else
796                 {
797                         if (highlightedWidget->type == WG_BUTTON)
798                         {
799                                 *highlightedWidget->value = 1;
800                                 highlightedWidget->changed = true;
801                         }
802                         else if (highlightedWidget->type == WG_JOYPAD)
803                         {
804                                 waitForButton = true;
805                                 waitForKey = false;
806                                 allowJoypad = true;
807                                 
808                                 if (*highlightedWidget->value > -1000)
809                                 {
810                                         *highlightedWidget->value = (-1000 - *highlightedWidget->value);
811                                 }
812                         }
813                         else if (highlightedWidget->type == WG_KEYBOARD)
814                         {
815                                 waitForKey = true;
816                                 waitForButton = false;
817                                 allowJoypad = false;
818                                 *highlightedWidget->value = -*highlightedWidget->value;
819                         }
820                         
821                         update = 2;
822                 }
823                 
824
825                 flushInput();
826                 clearInput();
827         }
828
829         return update;
830 }
831
832 #if !UNIX
833 char *strtok_r(char *s1, const char *s2, char **lasts)
834 {
835         char *ret;
836         
837         if (s1 == NULL)
838         {
839                 s1 = *lasts;
840         }
841         
842         while (*s1 && strchr(s2, *s1))
843         {
844                 ++s1;
845         }
846         
847         if (*s1 == '\0')
848         {
849                 return NULL;
850         }
851         
852         ret = s1;
853         
854         while(*s1 && !strchr(s2, *s1))
855         {
856                 ++s1;
857         }
858         
859         if(*s1)
860         {
861                 *s1++ = '\0';
862         }
863         
864         *lasts = s1;
865         
866         return ret;
867 }
868 #endif
869
870 /*
871 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
872 game at compile time and run time, so everything is syncronised. This technique has the advantage of
873 allowing the game's data to be human readable and easy to maintain.
874 */
875 bool Engine::loadDefines()
876 {
877         char string[2][1024];
878
879         if (!loadData("data/defines.h"))
880                 return false;
881
882         char *token = strtok((char*)dataBuffer, "\n");
883
884         Data *data;
885
886         while (true)
887         {
888                 token = strtok(NULL, "\n");
889                 if (!token)
890                         break;
891
892                 if (!strstr(token, "/*"))
893                 {
894                         sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
895                         data = new Data();
896                         data->set(string[0], string[1], 1, 1);
897                         defineList.add(data);
898                 }
899         }
900
901         return true;
902 }
903
904 /*
905 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
906 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
907 1) It makes the game data human readable and 2) It means if I change a #define in
908 the code, I don't have to change all the data entries too. You probably already
909 thought of that though... :)
910 */
911 int Engine::getValueOfDefine(const char *word)
912 {
913         int rtn = 0;
914
915         Data *data = (Data*)defineList.getHead();
916
917         while (data->next != NULL)
918         {
919                 data = (Data*)data->next;
920
921                 if (strcmp(data->key, word) == 0)
922                 {
923                         rtn = atoi(data->value);
924                         return rtn;
925                 }
926         }
927
928         printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
929         exit(1);
930 }
931
932 /*
933 Does the opposite of the above(!)
934 */
935 char *Engine::getDefineOfValue(const char *prefix, int value)
936 {
937         int rtn = 0;
938
939         Data *data = (Data*)defineList.getHead();
940
941         while (data->next != NULL)
942         {
943                 data = (Data*)data->next;
944
945                 if (strstr(data->key, prefix))
946                 {
947                         rtn = atoi(data->value);
948                         
949                         if (rtn == value)
950                         {
951                                 return data->key;
952                         }
953                 }
954         }
955
956         printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
957         exit(1);
958 }
959
960 /*
961 I like this function. It receives a list of flags declared by their #define name... like
962 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
963 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
964 the values together and then returns them... phew! Makes data files human readable though :)
965 */
966 int Engine::getValueOfFlagTokens(const char *realLine)
967 {
968         if (strcmp(realLine, "0") == 0)
969                 return 0;
970
971         char *store;
972         char line[1024];
973         bool found;
974         int value;
975         strlcpy(line, realLine, sizeof line);
976
977         int flags = 0;
978
979         char *word = strtok_r(line, "+", &store);
980
981         if (!word)
982         {
983                 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
984                 exit(1);
985         }
986
987         Data *data;
988
989         while (true)
990         {
991                 data = (Data*)defineList.getHead();
992                 found = false;
993
994                 while (data->next != NULL)
995                 {
996                         data = (Data*)data->next;
997
998                         if (strcmp(data->key, word) == 0)
999                         {
1000                                 value = -1;
1001                                 sscanf(data->value, "%d", &value);
1002
1003                                 if (value == -1)
1004                                 {
1005                                         sscanf(data->value, "%*s %*d %*s %d", &value);
1006                                         value = 2 << value;
1007                                 }
1008
1009                                 flags += value;
1010                                 found = true;
1011                                 break;
1012                         }
1013                 }
1014
1015                 if (!found)
1016                 {
1017                         printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1018                         #if IGNORE_FLAGTOKEN_ERRORS
1019                                 break;
1020                         #else
1021                                 exit(1);
1022                         #endif
1023                 }
1024
1025                 word = strtok_r(NULL, "+", &store);
1026                 if (!word)
1027                         break;
1028         }
1029
1030         return flags;
1031 }
1032
1033 void Engine::delay(unsigned int frameLimit) {
1034         unsigned int ticks = SDL_GetTicks();
1035
1036         if(frameLimit < ticks)
1037                 return;
1038         
1039         if(frameLimit > ticks + 16)
1040                 SDL_Delay(16);
1041         else
1042                 SDL_Delay(frameLimit - ticks);
1043 }