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