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