]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/CEngine.cpp
Don't link pak tool with SDL.
[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
24 Engine::Engine()
25 {
26         for (int i = 0 ; i < 350 ; i++)
27         {
28                 keyState[i] = 0;
29         }
30         
31         for (int i = 0 ; i < 32 ; i++)
32         {
33                 joystickState[i] = 0;
34         }
35
36         joyX = joyY = 0;
37
38         mouseLeft = mouseRight = 0;
39         waitForButton = false;
40         waitForKey = false;
41         
42         allowJoypad = true;
43
44         lastKeyPressed[0] = 0;
45
46         fullScreen = 0;
47
48         useAudio = 2;
49         
50         practice = false;
51         
52         allowQuit = false;
53
54         saveConfig = false;
55
56         highlightedWidget = NULL;
57
58         message[0] = 0;
59         messageTime = -1;
60
61         // Development Stuff
62         devNoMonsters = false;
63
64         dataBuffer = NULL;
65         binaryBuffer = NULL;
66         #ifdef FRAMEWORK_SDL
67         char pakPath[PATH_MAX];
68         strlcpy(pakPath, PAKFULLPATH, sizeof(pakPath));
69         if (CFBundleGetMainBundle() != NULL) {
70                 CFURLRef pakURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR(PAKNAME), NULL, NULL);
71                 if (pakURL != NULL) {
72                         CFShow(pakURL);
73                         CFURLGetFileSystemRepresentation(pakURL, true, (UInt8*)pakPath, sizeof(pakPath));
74                         CFRelease(pakURL);
75                 }
76         }
77         pak.setPakFile(pakPath);
78         #else
79         pak.setPakFile(PAKFULLPATH);
80         #endif
81
82         // Timer
83         time1 = time2 = 0;
84         timeDifference = 0;
85
86         // Cheats
87         memset(lastKeyEvents, ' ', 25);
88         cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
89         cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
90         
91         extremeAvailable = 0;
92 }
93
94 void Engine::destroy()
95 {
96         debug(("engine: free widgets\n"));
97         deleteWidgets();
98
99         debug(("engine: free databuffer\n"));
100         delete[] dataBuffer;
101
102         debug(("engine: free binarybuffer\n"));
103         delete[] binaryBuffer;
104
105         debug(("Clearing Define List...\n"));
106         defineList.clear();
107 }
108
109 void Engine::clearCheatVars()
110 {
111         memset(lastKeyEvents, ' ', 25);
112         cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
113         cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
114 }
115
116 bool Engine::compareLastKeyInputs()
117 {
118         if (strstr(lastKeyEvents, "lockandload"))
119         {
120                 cheats = true;
121                 return true;
122         }
123
124         return false;
125 }
126
127 void Engine::addKeyEvent()
128 {
129         if (strlen(lastKeyPressed) > 1)
130         {
131                 return;
132         }
133
134         int index = -1;
135
136         for (int i = 0 ; i < 25 ; i++)
137         {
138                 if (lastKeyEvents[i] == ' ')
139                 {
140                         index = i;
141                         break;
142                 }
143         }
144
145         if (index == -1)
146         {
147                 for (int i = 0 ; i < 24 ; i++)
148                 {
149                         lastKeyEvents[i] = lastKeyEvents[i + 1];
150                 }
151
152                 index = 24;
153         }
154
155         lastKeyEvents[index] = lastKeyPressed[0];
156
157         compareLastKeyInputs();
158 }
159
160 void Engine::getInput()
161 {
162         SDL_GetMouseState(&mouseX, &mouseY);
163
164         while (SDL_PollEvent(&event))
165         {
166                 switch (event.type)
167                 {
168                         case SDL_QUIT:
169                                 if (allowQuit)
170                                 {
171                                         exit(0);
172                                 }
173                                 break;
174
175                         case SDL_MOUSEBUTTONDOWN:
176                                 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 1;
177                                 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 1;
178                                 break;
179
180                         case SDL_MOUSEBUTTONUP:
181                                 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 0;
182                                 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 0;
183                                 break;
184
185                         case SDL_KEYDOWN:
186                                 
187                                 if (waitForButton)
188                                 {
189                                         if (event.key.keysym.sym == SDLK_ESCAPE)
190                                         {
191                                                 lastButtonPressed = -1;
192                                                 *highlightedWidget->value = abs(*highlightedWidget->value) - 1000;
193                                                 highlightedWidget->redraw();
194                                                 waitForButton = false;
195                                                 allowJoypad = false;
196                                         }
197                                         
198                                         if (event.key.keysym.sym == SDLK_BACKSPACE)
199                                         {
200                                                 lastButtonPressed = -2;
201                                                 *highlightedWidget->value = -2;
202                                                 highlightedWidget->redraw();
203                                                 waitForButton = false;
204                                                 allowJoypad = false;
205                                         }
206                                         
207                                         return;
208                                 }
209                                 
210                                 if (waitForKey)
211                                 {
212                                         if (event.key.keysym.sym == SDLK_ESCAPE)
213                                         {
214                                                 *highlightedWidget->value = -*highlightedWidget->value;
215                                         }
216                                         else
217                                         {
218                                                 *highlightedWidget->value = event.key.keysym.sym;
219                                         }
220                                         
221                                         lastButtonPressed = -1;
222                                         highlightedWidget->redraw();
223                                         waitForButton = false;
224                                         waitForKey = false;
225                                         allowJoypad = false;
226                                         
227                                         return;
228                                 }
229
230                                 keyState[event.key.keysym.sym] = 1;
231                                 strlcpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.sym), sizeof lastKeyPressed);
232                                 addKeyEvent();
233                                 break;
234
235                         case SDL_KEYUP:
236                                 keyState[event.key.keysym.sym] = 0;
237                                 break;
238
239                         case SDL_JOYAXISMOTION:
240                                 if (event.jaxis.axis == 0)
241                                 {
242                                   joyX = event.jaxis.value;
243                                 }
244                                 else if (event.jaxis.axis == 1)
245                                 {
246                                   joyY = event.jaxis.value;
247                                 }
248                                 
249                                 break;
250
251                         case SDL_JOYBUTTONDOWN:
252                         
253                                 if (waitForButton)
254                                 {
255                                         lastButtonPressed = event.jbutton.button;
256                                         *highlightedWidget->value = lastButtonPressed;
257                                         highlightedWidget->redraw();
258                                         waitForButton = false;
259                                         allowJoypad = false;
260                                         return;
261                                 }
262                                 
263                                 joystickState[event.jbutton.button] = 1;
264                                 break;
265
266                         case SDL_JOYBUTTONUP:
267                                 joystickState[event.jbutton.button] = 0;
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_WarpMouse(x, y);
289 }
290
291 bool Engine::userAccepts()
292 {
293         if ((keyState[SDLK_SPACE]) || (keyState[SDLK_ESCAPE]) || (keyState[SDLK_LCTRL]) || (keyState[SDLK_RCTRL]) || (keyState[SDLK_RETURN]) || (keyState[SDLK_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         for (int i = 0 ; i < 350 ; i++)
309                 keyState[i] = 0;
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[SDLK_UP])
736         {
737                 highlightWidget(-1);
738                 update = 1;
739                 clearInput();
740         }
741
742         if (keyState[SDLK_DOWN])
743         {
744                 highlightWidget(1);
745                 update = 1;
746                 clearInput();
747         }
748
749         if (keyState[SDLK_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[SDLK_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[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_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 }