]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/CEngine.cpp
Use DEBUG instead of USEPAK to enable debugging code.
[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         strcpy(lastKeyPressed, "");
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         strcpy(message, "");
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                                 strcpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.sym));
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         strcpy(userHomeDirectory, path);
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                         sprintf(tempPath, "%smusic.mod", userHomeDirectory);
383                         fp = fopen(tempPath, "wb");
384                 }
385
386                 if (fileType == PAK_FONT)
387                 {
388                         sprintf(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];
430
431         fread(dataBuffer, 1, fSize, fp);
432
433         fclose(fp);
434
435         debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
436
437         return true;
438 }
439
440 void Engine::reportFontFailure()
441 {
442         printf("\nUnable to load font. The game cannot continue without it.\n");
443         printf("Please confirm that the game and all required SDL libraries are installed\n");
444         printf("The following information may be useful to you,\n\n");
445         printf("Expected location of PAK file: %s\n", PAKFULLPATH);
446         printf("Location of TMP directory: %s\n", userHomeDirectory);
447         printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
448         exit(1);
449 }
450
451 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
452 {
453         playerPosX = x - OFFSETX;
454         playerPosY = y - OFFSETY;
455
456         Math::limitInt(&playerPosX, limitLeft, limitRight);
457         Math::limitInt(&playerPosY, limitUp, limitDown);
458 }
459
460 int Engine::getFrameLoop()
461 {
462         return frameLoop;
463 }
464
465 void Engine::doFrameLoop()
466 {
467         Math::wrapChar(&(++frameLoop), 0, 59);
468 }
469
470 void Engine::doTimeDifference()
471 {
472         timeDifference = (time2 - time1) / 10.0;
473         time1 = time2;
474         time2 = SDL_GetTicks();
475 }
476
477 float Engine::getTimeDifference()
478 {
479         return timeDifference;
480 }
481
482 void Engine::resetTimeDifference()
483 {
484         time1 = time2 = SDL_GetTicks();
485 }
486
487 void Engine::setInfoMessage(const char *message, int priority, int type)
488 {
489         if (priority >= messagePriority)
490         {
491                 strcpy(this->message, message);
492                 messageTime = 180;
493                 messagePriority = priority;
494                 messageType = type;
495         }
496 }
497
498 void Engine::deleteWidgets()
499 {
500         Widget *widget;
501
502         for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
503                 widget->redraw();
504
505         widgetList.clear();
506
507         highlightedWidget = NULL;
508 }
509
510 void Engine::addWidget(Widget *widget)
511 {
512         widget->previous = (Widget*)widgetList.getTail();
513         widgetList.add(widget);
514 }
515
516 bool Engine::loadWidgets(const char *filename)
517 {
518         deleteWidgets();
519
520         if (!loadData(filename))
521                 return false;
522
523         char token[50], name[50], groupName[50], label[80], options[100], *line;
524         int x, y, min, max;
525
526         int i;
527
528         Widget *widget;
529
530         line = strtok((char*)dataBuffer, "\n");
531
532         while (true)
533         {
534                 sscanf(line, "%s", token);
535
536                 if (strcmp(token, "END") == 0)
537                         break;
538
539                 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
540
541                 widget = new Widget;
542
543                 i = 0;
544
545                 while (true)
546                 {
547                         if (strcmp(token, widgetName[i]) == 0)
548                                 widget->type = i;
549
550                         if (strcmp("-1", widgetName[i]) == 0)
551                                 break;
552
553                         i++;
554                 }
555
556                 widget->setProperties(name, groupName, label, options, x, y, min, max);
557
558                 addWidget(widget);
559
560
561                 if ((line = strtok(NULL, "\n")) == NULL)
562                         break;
563         }
564
565         highlightedWidget = (Widget*)widgetList.getHead()->next;
566
567         return true;
568 }
569
570 Widget *Engine::getWidgetByName(const char *name)
571 {
572         Widget *widget = (Widget*)widgetList.getHead();
573
574         while (widget->next != NULL)
575         {
576                 widget = (Widget*)widget->next;
577
578                 if (strcmp(widget->name, name) == 0)
579                         return widget;
580         }
581
582         debug(("No such widget '%s'\n", name));
583
584         return NULL;
585 }
586
587 void Engine::showWidgetGroup(const char *groupName, bool show)
588 {
589         bool found = false;
590
591         Widget *widget = (Widget*)widgetList.getHead();
592
593         while (widget->next != NULL)
594         {
595                 widget = (Widget*)widget->next;
596
597                 if (strcmp(widget->groupName, groupName) == 0)
598                 {
599                         widget->visible = show;
600                         widget->redraw();
601                         found = true;
602                 }
603         }
604
605         if (!found)
606                 debug(("Group '%s' does not exist\n", groupName));
607 }
608
609 void Engine::enableWidgetGroup(const char *groupName, bool show)
610 {
611         bool found = false;
612
613         Widget *widget = (Widget*)widgetList.getHead();
614
615         while (widget->next != NULL)
616         {
617                 widget = (Widget*)widget->next;
618
619                 if (strcmp(widget->groupName, groupName) == 0)
620                 {
621                         widget->enabled = show;
622                         widget->redraw();
623                         found = true;
624                 }
625         }
626
627         if (!found)
628                 debug(("Group '%s' does not exist\n", groupName));
629 }
630
631 void Engine::showWidget(const char *name, bool show)
632 {
633         Widget *widget = getWidgetByName(name);
634         if (widget != NULL)
635         {
636                 widget->visible = show;
637                 widget->redraw();
638         }
639 }
640
641 void Engine::enableWidget(const char *name, bool enable)
642 {
643         Widget *widget = getWidgetByName(name);
644         if (widget != NULL)
645         {
646                 widget->enabled = enable;
647                 widget->redraw();
648         }
649 }
650
651 void Engine::setWidgetVariable(const char *name, int *variable)
652 {
653         Widget *widget = getWidgetByName(name);
654         if (widget != NULL)
655                 widget->value = variable;
656 }
657
658 bool Engine::widgetChanged(const char *name)
659 {
660         Widget *widget = getWidgetByName(name);
661         if (widget != NULL)
662                 return widget->changed;
663
664         return false;
665 }
666
667 void Engine::highlightWidget(int dir)
668 {
669         highlightedWidget->redraw();
670
671         if (dir == 1)
672         {
673                 while (true)
674                 {
675                         if (highlightedWidget->next != NULL)
676                         {
677                                 highlightedWidget = (Widget*)highlightedWidget->next;
678                         }
679                         else
680                         {
681                                 highlightedWidget = (Widget*)widgetList.getHead()->next;
682                         }
683
684                         if (highlightedWidget->type == 4)
685                                 continue;
686
687                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
688                                 break;
689                 }
690         }
691
692         if (dir == -1)
693         {
694                 while (true)
695                 {
696                         if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
697                         {
698                                 highlightedWidget = highlightedWidget->previous;
699                         }
700                         else
701                         {
702                                 highlightedWidget = (Widget*)widgetList.getTail();
703                         }
704
705                         if (highlightedWidget->type == WG_LABEL)
706                                 continue;
707
708                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
709                                 break;
710                 }
711         }
712
713         highlightedWidget->redraw();
714 }
715
716 void Engine::highlightWidget(const char *name)
717 {
718         highlightedWidget = getWidgetByName(name);
719 }
720
721 int Engine::processWidgets()
722 {
723         int update = 0;
724
725         if (keyState[SDLK_UP])
726         {
727                 highlightWidget(-1);
728                 update = 1;
729                 clearInput();
730         }
731
732         if (keyState[SDLK_DOWN])
733         {
734                 highlightWidget(1);
735                 update = 1;
736                 clearInput();
737         }
738
739         if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
740         {
741                 SDL_Delay(1);
742
743                 if (*highlightedWidget->value > highlightedWidget->min)
744                 {
745                         *highlightedWidget->value = *highlightedWidget->value - 1;
746                         update = 3;
747                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
748                                 update = 1;
749                         highlightedWidget->changed = true;
750                 }
751
752                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
753                         clearInput();
754         }
755
756         if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
757         {
758                 SDL_Delay(1);
759
760                 if (*highlightedWidget->value < highlightedWidget->max)
761                 {
762                         *highlightedWidget->value = *highlightedWidget->value + 1;
763                         update = 3;
764                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
765                                 update = 1;
766                         highlightedWidget->changed = true;
767                 }
768
769                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
770                         clearInput();
771         }
772
773         if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
774         {
775                 if (highlightedWidget->value == NULL)
776                 {
777                         debug(("%s has not been implemented!\n", highlightedWidget->name));
778                 }
779                 else
780                 {
781                         if (highlightedWidget->type == WG_BUTTON)
782                         {
783                                 *highlightedWidget->value = 1;
784                                 highlightedWidget->changed = true;
785                         }
786                         else if (highlightedWidget->type == WG_JOYPAD)
787                         {
788                                 waitForButton = true;
789                                 waitForKey = false;
790                                 allowJoypad = true;
791                                 
792                                 if (*highlightedWidget->value > -1000)
793                                 {
794                                         *highlightedWidget->value = (-1000 - *highlightedWidget->value);
795                                 }
796                         }
797                         else if (highlightedWidget->type == WG_KEYBOARD)
798                         {
799                                 waitForKey = true;
800                                 waitForButton = false;
801                                 allowJoypad = false;
802                                 *highlightedWidget->value = -*highlightedWidget->value;
803                         }
804                         
805                         update = 2;
806                 }
807                 
808
809                 flushInput();
810                 clearInput();
811         }
812
813         return update;
814 }
815
816 #if !UNIX
817 char *strtok_r(char *s1, const char *s2, char **lasts)
818 {
819         char *ret;
820         
821         if (s1 == NULL)
822         {
823                 s1 = *lasts;
824         }
825         
826         while (*s1 && strchr(s2, *s1))
827         {
828                 ++s1;
829         }
830         
831         if (*s1 == '\0')
832         {
833                 return NULL;
834         }
835         
836         ret = s1;
837         
838         while(*s1 && !strchr(s2, *s1))
839         {
840                 ++s1;
841         }
842         
843         if(*s1)
844         {
845                 *s1++ = '\0';
846         }
847         
848         *lasts = s1;
849         
850         return ret;
851 }
852 #endif
853
854 /*
855 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
856 game at compile time and run time, so everything is syncronised. This technique has the advantage of
857 allowing the game's data to be human readable and easy to maintain.
858 */
859 bool Engine::loadDefines()
860 {
861         char string[2][1024];
862
863         if (!loadData("data/defines.h"))
864                 return false;
865
866         char *token = strtok((char*)dataBuffer, "\n");
867
868         Data *data;
869
870         while (true)
871         {
872                 token = strtok(NULL, "\n");
873                 if (!token)
874                         break;
875
876                 if (!strstr(token, "/*"))
877                 {
878                         sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
879                         data = new Data();
880                         data->set(string[0], string[1], 1, 1);
881                         defineList.add(data);
882                 }
883         }
884
885         return true;
886 }
887
888 /*
889 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
890 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
891 1) It makes the game data human readable and 2) It means if I change a #define in
892 the code, I don't have to change all the data entries too. You probably already
893 thought of that though... :)
894 */
895 int Engine::getValueOfDefine(const char *word)
896 {
897         int rtn = 0;
898
899         Data *data = (Data*)defineList.getHead();
900
901         while (data->next != NULL)
902         {
903                 data = (Data*)data->next;
904
905                 if (strcmp(data->key, word) == 0)
906                 {
907                         rtn = atoi(data->value);
908                         return rtn;
909                 }
910         }
911
912         printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
913         exit(1);
914 }
915
916 /*
917 Does the opposite of the above(!)
918 */
919 char *Engine::getDefineOfValue(const char *prefix, int value)
920 {
921         int rtn = 0;
922
923         Data *data = (Data*)defineList.getHead();
924
925         while (data->next != NULL)
926         {
927                 data = (Data*)data->next;
928
929                 if (strstr(data->key, prefix))
930                 {
931                         rtn = atoi(data->value);
932                         
933                         if (rtn == value)
934                         {
935                                 return data->key;
936                         }
937                 }
938         }
939
940         printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
941         exit(1);
942 }
943
944 /*
945 I like this function. It receives a list of flags declared by their #define name... like
946 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
947 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
948 the values together and then returns them... phew! Makes data files human readable though :)
949 */
950 int Engine::getValueOfFlagTokens(const char *realLine)
951 {
952         if (strcmp(realLine, "0") == 0)
953                 return 0;
954
955         char *store;
956         char line[1024];
957         bool found;
958         int value;
959         strcpy(line, realLine);
960
961         int flags = 0;
962
963         char *word = strtok_r(line, "+", &store);
964
965         if (!word)
966         {
967                 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
968                 exit(1);
969         }
970
971         Data *data;
972
973         while (true)
974         {
975                 data = (Data*)defineList.getHead();
976                 found = false;
977
978                 while (data->next != NULL)
979                 {
980                         data = (Data*)data->next;
981
982                         if (strcmp(data->key, word) == 0)
983                         {
984                                 value = -1;
985                                 sscanf(data->value, "%d", &value);
986
987                                 if (value == -1)
988                                 {
989                                         sscanf(data->value, "%*s %*d %*s %d", &value);
990                                         value = 2 << value;
991                                 }
992
993                                 flags += value;
994                                 found = true;
995                                 break;
996                         }
997                 }
998
999                 if (!found)
1000                 {
1001                         printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1002                         #if IGNORE_FLAGTOKEN_ERRORS
1003                                 break;
1004                         #else
1005                                 exit(1);
1006                         #endif
1007                 }
1008
1009                 word = strtok_r(NULL, "+", &store);
1010                 if (!word)
1011                         break;
1012         }
1013
1014         return flags;
1015 }
1016
1017 void Engine::delay(unsigned int frameLimit) {
1018         unsigned int ticks = SDL_GetTicks();
1019
1020         if(frameLimit < ticks)
1021                 return;
1022         
1023         if(frameLimit > ticks + 16)
1024                 SDL_Delay(16);
1025         else
1026                 SDL_Delay(frameLimit - ticks);
1027 }