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