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