]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/CEngine.cpp
7017039722123c54f5df2ad448a3a2297b5b4282
[quix0rs-blobwars.git] / src / CEngine.cpp
1 /*
2 Copyright (C) 2004-2010 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         if (fileType == PAK_DATA)
334         {
335                 delete[] dataBuffer;
336                 dataBuffer = NULL;
337         }
338         else
339         {
340                 delete[] binaryBuffer;
341                 binaryBuffer = NULL;
342         }
343
344         if (fileType != PAK_DATA)
345         {
346                 if (!pak.unpack(filename, &binaryBuffer))
347                 {
348                         return false;
349                 }
350         }
351         else
352         {
353                 if (!pak.unpack(filename, &dataBuffer))
354                 {
355                         return false;
356                 }
357         }
358
359         if ((fileType == PAK_IMG) || (fileType == PAK_SOUND))
360         {
361                 sdlrw = SDL_RWFromMem(binaryBuffer, pak.getUncompressedSize());
362                 if (!sdlrw)
363                 {
364                         printf("Fatal Error: SDL_RWops allocation failed\n");
365                         exit(1);
366                 }
367         }
368
369         if ((fileType == PAK_MUSIC) || (fileType == PAK_FONT) || (fileType == PAK_TAGS))
370         {
371                 char tempPath[PATH_MAX];
372                 
373                 FILE *fp = NULL;
374
375                 if (fileType == PAK_MUSIC)
376                 {
377                         snprintf(tempPath, sizeof tempPath, "%smusic.mod", userHomeDirectory);
378                         fp = fopen(tempPath, "wb");
379                 }
380
381                 if (fileType == PAK_TAGS)
382                 {
383                         snprintf(tempPath, sizeof tempPath, "%smusic.tags", userHomeDirectory);
384                         fp = fopen(tempPath, "wb");
385                 }
386
387                 if (fileType == PAK_FONT)
388                 {
389                         snprintf(tempPath, sizeof tempPath, "%sfont.ttf", userHomeDirectory);
390                         fp = fopen(tempPath, "wb");
391                 }
392
393                 if (!fp)
394                 {
395                         printf("Fatal Error: could not open %s for writing: %s", tempPath, strerror(errno));
396                         return false;
397                 }
398
399                 fwrite(binaryBuffer, 1, pak.getUncompressedSize(), fp);
400                 fclose(fp);
401         }
402
403         debug(("unpack() : Loaded %s (%d)\n", filename, pak.getUncompressedSize()));
404
405         return true;
406 }
407
408 bool Engine::loadData(const char *filename)
409 {
410         delete[] dataBuffer;
411         dataBuffer = NULL;
412         
413         #if USEPAK
414                 return unpack(filename, PAK_DATA);
415         #endif
416
417         FILE *fp;
418         fp = fopen(filename, "rb");
419         if (fp == NULL)
420                 return false;
421
422         fseek(fp, 0, SEEK_END);
423
424         int fSize = ftell(fp);
425
426         rewind(fp);
427
428         dataBuffer = new unsigned char[fSize + 1];
429
430         fread(dataBuffer, 1, fSize, fp);
431         dataBuffer[fSize] = 0;
432
433         fclose(fp);
434
435         debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
436
437         return true;
438 }
439
440 void Engine::reportFontFailure()
441 {
442         printf("\nUnable to load font. The game cannot continue without it.\n");
443         printf("Please confirm that the game and all required SDL libraries are installed\n");
444         printf("The following information may be useful to you,\n\n");
445         printf("Expected location of PAK file: %s\n", PAKFULLPATH);
446         printf("Location of TMP directory: %s\n", userHomeDirectory);
447         printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
448         exit(1);
449 }
450
451 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
452 {
453         playerPosX = x - OFFSETX;
454         playerPosY = y - OFFSETY;
455
456         Math::limitInt(&playerPosX, limitLeft, limitRight);
457         Math::limitInt(&playerPosY, limitUp, limitDown);
458 }
459
460 int Engine::getFrameLoop() const
461 {
462         return frameLoop;
463 }
464
465 void Engine::doFrameLoop()
466 {
467         Math::wrapChar(&(++frameLoop), 0, 59);
468 }
469
470 void Engine::doTimeDifference()
471 {
472         timeDifference = (time2 - time1) / 10.0;
473         time1 = time2;
474         time2 = SDL_GetTicks();
475 }
476
477 float Engine::getTimeDifference() const
478 {
479         return timeDifference;
480 }
481
482 void Engine::resetTimeDifference()
483 {
484         time1 = time2 = SDL_GetTicks();
485 }
486
487 void Engine::setInfoMessage(const char *message, int priority, int type)
488 {
489         if (priority >= messagePriority)
490         {
491                 strlcpy(this->message, message, sizeof this->message);
492                 messageTime = 180;
493                 messagePriority = priority;
494                 messageType = type;
495         }
496 }
497
498 void Engine::deleteWidgets()
499 {
500         Widget *widget;
501
502         for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
503                 widget->redraw();
504
505         widgetList.clear();
506
507         highlightedWidget = NULL;
508 }
509
510 void Engine::addWidget(Widget *widget)
511 {
512         widget->previous = (Widget*)widgetList.getTail();
513         widgetList.add(widget);
514 }
515
516 bool Engine::loadWidgets(const char *filename)
517 {
518         deleteWidgets();
519
520         if (!loadData(filename))
521                 return false;
522
523         char token[50], name[50], groupName[50], label[80], options[100], *line;
524         int x, y, min, max;
525
526         int i;
527
528         Widget *widget;
529
530         line = strtok((char*)dataBuffer, "\n");
531
532         while (true)
533         {
534                 sscanf(line, "%s", token);
535
536                 if (strcmp(token, "END") == 0)
537                         break;
538
539                 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
540
541                 widget = new Widget;
542
543                 i = 0;
544
545                 while (true)
546                 {
547                         if (strcmp(token, widgetName[i]) == 0)
548                                 widget->type = i;
549
550                         if (strcmp("-1", widgetName[i]) == 0)
551                                 break;
552
553                         i++;
554                 }
555
556                 widget->setProperties(name, groupName, label, options, x, y, min, max);
557
558                 addWidget(widget);
559
560
561                 if ((line = strtok(NULL, "\n")) == NULL)
562                         break;
563         }
564
565         highlightedWidget = (Widget*)widgetList.getHead()->next;
566
567         return true;
568 }
569
570 Widget *Engine::getWidgetByName(const char *name)
571 {
572         Widget *widget = (Widget*)widgetList.getHead();
573
574         while (widget->next != NULL)
575         {
576                 widget = (Widget*)widget->next;
577
578                 if (strcmp(widget->name, name) == 0)
579                         return widget;
580         }
581
582         debug(("No such widget '%s'\n", name));
583
584         return NULL;
585 }
586
587 void Engine::showWidgetGroup(const char *groupName, bool show)
588 {
589         bool found = false;
590
591         Widget *widget = (Widget*)widgetList.getHead();
592
593         while (widget->next != NULL)
594         {
595                 widget = (Widget*)widget->next;
596
597                 if (strcmp(widget->groupName, groupName) == 0)
598                 {
599                         widget->visible = show;
600                         widget->redraw();
601                         found = true;
602                 }
603         }
604
605         if (!found)
606                 debug(("Group '%s' does not exist\n", groupName));
607 }
608
609 void Engine::enableWidgetGroup(const char *groupName, bool show)
610 {
611         bool found = false;
612
613         Widget *widget = (Widget*)widgetList.getHead();
614
615         while (widget->next != NULL)
616         {
617                 widget = (Widget*)widget->next;
618
619                 if (strcmp(widget->groupName, groupName) == 0)
620                 {
621                         widget->enabled = show;
622                         widget->redraw();
623                         found = true;
624                 }
625         }
626
627         if (!found)
628                 debug(("Group '%s' does not exist\n", groupName));
629 }
630
631 void Engine::showWidget(const char *name, bool show)
632 {
633         Widget *widget = getWidgetByName(name);
634         if (widget != NULL)
635         {
636                 widget->visible = show;
637                 widget->redraw();
638         }
639 }
640
641 void Engine::enableWidget(const char *name, bool enable)
642 {
643         Widget *widget = getWidgetByName(name);
644         if (widget != NULL)
645         {
646                 widget->enabled = enable;
647                 widget->redraw();
648         }
649 }
650
651 void Engine::setWidgetVariable(const char *name, int *variable)
652 {
653         Widget *widget = getWidgetByName(name);
654         if (widget != NULL)
655                 widget->value = variable;
656 }
657
658 bool Engine::widgetChanged(const char *name)
659 {
660         Widget *widget = getWidgetByName(name);
661         if (widget != NULL)
662                 return widget->changed;
663
664         return false;
665 }
666
667 void Engine::highlightWidget(int dir)
668 {
669         highlightedWidget->redraw();
670
671         if (dir == 1)
672         {
673                 while (true)
674                 {
675                         if (highlightedWidget->next != NULL)
676                         {
677                                 highlightedWidget = (Widget*)highlightedWidget->next;
678                         }
679                         else
680                         {
681                                 highlightedWidget = (Widget*)widgetList.getHead()->next;
682                         }
683
684                         if (highlightedWidget->type == 4)
685                                 continue;
686
687                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
688                                 break;
689                 }
690         }
691
692         if (dir == -1)
693         {
694                 while (true)
695                 {
696                         if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
697                         {
698                                 highlightedWidget = highlightedWidget->previous;
699                         }
700                         else
701                         {
702                                 highlightedWidget = (Widget*)widgetList.getTail();
703                         }
704
705                         if (highlightedWidget->type == WG_LABEL)
706                                 continue;
707
708                         if ((highlightedWidget->enabled) && (highlightedWidget->visible))
709                                 break;
710                 }
711         }
712
713         highlightedWidget->redraw();
714 }
715
716 void Engine::highlightWidget(const char *name)
717 {
718         highlightedWidget = getWidgetByName(name);
719 }
720
721 int Engine::processWidgets()
722 {
723         int update = 0;
724
725         if (keyState[SDLK_UP])
726         {
727                 highlightWidget(-1);
728                 update = 1;
729                 clearInput();
730         }
731
732         if (keyState[SDLK_DOWN])
733         {
734                 highlightWidget(1);
735                 update = 1;
736                 clearInput();
737         }
738
739         if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
740         {
741                 SDL_Delay(1);
742
743                 if (*highlightedWidget->value > highlightedWidget->min)
744                 {
745                         *highlightedWidget->value = *highlightedWidget->value - 1;
746                         update = 3;
747                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
748                                 update = 1;
749                         highlightedWidget->changed = true;
750                 }
751
752                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
753                         clearInput();
754         }
755
756         if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
757         {
758                 SDL_Delay(1);
759
760                 if (*highlightedWidget->value < highlightedWidget->max)
761                 {
762                         *highlightedWidget->value = *highlightedWidget->value + 1;
763                         update = 3;
764                         if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
765                                 update = 1;
766                         highlightedWidget->changed = true;
767                 }
768
769                 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
770                         clearInput();
771         }
772
773         if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
774         {
775                 if (highlightedWidget->value == NULL)
776                 {
777                         debug(("%s has not been implemented!\n", highlightedWidget->name));
778                 }
779                 else
780                 {
781                         if (highlightedWidget->type == WG_BUTTON)
782                         {
783                                 *highlightedWidget->value = 1;
784                                 highlightedWidget->changed = true;
785                         }
786                         else if (highlightedWidget->type == WG_JOYPAD)
787                         {
788                                 waitForButton = true;
789                                 waitForKey = false;
790                                 allowJoypad = true;
791                                 
792                                 if (*highlightedWidget->value > -1000)
793                                 {
794                                         *highlightedWidget->value = (-1000 - *highlightedWidget->value);
795                                 }
796                         }
797                         else if (highlightedWidget->type == WG_KEYBOARD)
798                         {
799                                 waitForKey = true;
800                                 waitForButton = false;
801                                 allowJoypad = false;
802                                 *highlightedWidget->value = -*highlightedWidget->value;
803                         }
804                         
805                         update = 2;
806                 }
807                 
808
809                 flushInput();
810                 clearInput();
811         }
812
813         return update;
814 }
815
816 #if !UNIX
817 char *strtok_r(char *s1, const char *s2, char **lasts)
818 {
819         char *ret;
820         
821         if (s1 == NULL)
822         {
823                 s1 = *lasts;
824         }
825         
826         while (*s1 && strchr(s2, *s1))
827         {
828                 ++s1;
829         }
830         
831         if (*s1 == '\0')
832         {
833                 return NULL;
834         }
835         
836         ret = s1;
837         
838         while(*s1 && !strchr(s2, *s1))
839         {
840                 ++s1;
841         }
842         
843         if(*s1)
844         {
845                 *s1++ = '\0';
846         }
847         
848         *lasts = s1;
849         
850         return ret;
851 }
852 #endif
853
854 /*
855 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
856 game at compile time and run time, so everything is syncronised. This technique has the advantage of
857 allowing the game's data to be human readable and easy to maintain.
858 */
859 bool Engine::loadDefines()
860 {
861         char string[2][1024];
862
863         if (!loadData("data/defines.h"))
864                 return false;
865
866         char *token = strtok((char*)dataBuffer, "\n");
867
868         Data *data;
869
870         while (true)
871         {
872                 token = strtok(NULL, "\n");
873                 if (!token)
874                         break;
875
876                 if (!strstr(token, "/*"))
877                 {
878                         sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
879                         data = new Data();
880                         data->set(string[0], string[1], 1, 1);
881                         defineList.add(data);
882                 }
883         }
884
885         return true;
886 }
887
888 /*
889 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
890 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
891 1) It makes the game data human readable and 2) It means if I change a #define in
892 the code, I don't have to change all the data entries too. You probably already
893 thought of that though... :)
894 */
895 int Engine::getValueOfDefine(const char *word)
896 {
897         int rtn = 0;
898
899         Data *data = (Data*)defineList.getHead();
900
901         while (data->next != NULL)
902         {
903                 data = (Data*)data->next;
904
905                 if (strcmp(data->key, word) == 0)
906                 {
907                         rtn = atoi(data->value);
908                         return rtn;
909                 }
910         }
911
912         printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
913         exit(1);
914 }
915
916 /*
917 Does the opposite of the above(!)
918 */
919 char *Engine::getDefineOfValue(const char *prefix, int value)
920 {
921         int rtn = 0;
922
923         Data *data = (Data*)defineList.getHead();
924
925         while (data->next != NULL)
926         {
927                 data = (Data*)data->next;
928
929                 if (strstr(data->key, prefix))
930                 {
931                         rtn = atoi(data->value);
932                         
933                         if (rtn == value)
934                         {
935                                 return data->key;
936                         }
937                 }
938         }
939
940         printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
941         exit(1);
942 }
943
944 /*
945 I like this function. It receives a list of flags declared by their #define name... like
946 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
947 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
948 the values together and then returns them... phew! Makes data files human readable though :)
949 */
950 int Engine::getValueOfFlagTokens(const char *realLine)
951 {
952         if (strcmp(realLine, "0") == 0)
953                 return 0;
954
955         char *store;
956         char line[1024];
957         bool found;
958         int value;
959         strlcpy(line, realLine, sizeof line);
960
961         int flags = 0;
962
963         char *word = strtok_r(line, "+", &store);
964
965         if (!word)
966         {
967                 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
968                 exit(1);
969         }
970
971         Data *data;
972
973         while (true)
974         {
975                 data = (Data*)defineList.getHead();
976                 found = false;
977
978                 while (data->next != NULL)
979                 {
980                         data = (Data*)data->next;
981
982                         if (strcmp(data->key, word) == 0)
983                         {
984                                 value = -1;
985                                 sscanf(data->value, "%d", &value);
986
987                                 if (value == -1)
988                                 {
989                                         sscanf(data->value, "%*s %*d %*s %d", &value);
990                                         value = 2 << value;
991                                 }
992
993                                 flags += value;
994                                 found = true;
995                                 break;
996                         }
997                 }
998
999                 if (!found)
1000                 {
1001                         printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1002                         #if IGNORE_FLAGTOKEN_ERRORS
1003                                 break;
1004                         #else
1005                                 exit(1);
1006                         #endif
1007                 }
1008
1009                 word = strtok_r(NULL, "+", &store);
1010                 if (!word)
1011                         break;
1012         }
1013
1014         return flags;
1015 }
1016
1017 void Engine::delay(unsigned int frameLimit) {
1018         unsigned int ticks = SDL_GetTicks();
1019
1020         if(frameLimit < ticks)
1021                 return;
1022         
1023         if(frameLimit > ticks + 16)
1024                 SDL_Delay(16);
1025         else
1026                 SDL_Delay(frameLimit - ticks);
1027 }