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