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