2 Copyright (C) 2004 Parallel Realities
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.
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.
13 See the GNU General Public License for more details.
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.
25 for (int i = 0 ; i < 350 ; i++)
30 for (int i = 0 ; i < 32 ; i++)
37 mouseLeft = mouseRight = 0;
38 waitForButton = false;
43 lastKeyPressed[0] = 0;
55 highlightedWidget = NULL;
61 devNoMonsters = false;
66 char pakPath[PATH_MAX];
67 strncpy(pakPath, PAKFULLPATH, sizeof(pakPath));
68 if (CFBundleGetMainBundle() != NULL) {
69 CFURLRef pakURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR(PAKNAME), NULL, NULL);
72 CFURLGetFileSystemRepresentation(pakURL, true, (UInt8*)pakPath, sizeof(pakPath));
76 pak.setPakFile(pakPath);
78 pak.setPakFile(PAKFULLPATH);
86 memset(lastKeyEvents, ' ', 25);
87 cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
88 cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
93 void Engine::destroy()
95 debug(("engine: free widgets\n"));
98 debug(("engine: free databuffer\n"));
99 if (dataBuffer != NULL)
102 debug(("engine: free binarybuffer\n"));
103 if (binaryBuffer != NULL)
104 delete[] binaryBuffer;
106 debug(("Clearing Define List...\n"));
110 void Engine::clearCheatVars()
112 memset(lastKeyEvents, ' ', 25);
113 cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
114 cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
117 bool Engine::compareLastKeyInputs()
119 if (strstr(lastKeyEvents, "lockandload"))
128 void Engine::addKeyEvent()
130 if (strlen(lastKeyPressed) > 1)
137 for (int i = 0 ; i < 25 ; i++)
139 if (lastKeyEvents[i] == ' ')
148 for (int i = 0 ; i < 25 ; i++)
150 lastKeyEvents[i] = lastKeyEvents[i + 1];
156 lastKeyEvents[index] = lastKeyPressed[0];
158 compareLastKeyInputs();
161 void Engine::getInput()
163 SDL_GetMouseState(&mouseX, &mouseY);
165 while (SDL_PollEvent(&event))
176 case SDL_MOUSEBUTTONDOWN:
177 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 1;
178 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 1;
181 case SDL_MOUSEBUTTONUP:
182 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 0;
183 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 0;
190 if (event.key.keysym.sym == SDLK_ESCAPE)
192 lastButtonPressed = -1;
193 *highlightedWidget->value = abs(*highlightedWidget->value) - 1000;
194 highlightedWidget->redraw();
195 waitForButton = false;
199 if (event.key.keysym.sym == SDLK_BACKSPACE)
201 lastButtonPressed = -2;
202 *highlightedWidget->value = -2;
203 highlightedWidget->redraw();
204 waitForButton = false;
213 if (event.key.keysym.sym == SDLK_ESCAPE)
215 *highlightedWidget->value = -*highlightedWidget->value;
219 *highlightedWidget->value = event.key.keysym.sym;
222 lastButtonPressed = -1;
223 highlightedWidget->redraw();
224 waitForButton = false;
231 keyState[event.key.keysym.sym] = 1;
232 strncpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.sym), sizeof lastKeyPressed);
237 keyState[event.key.keysym.sym] = 0;
240 case SDL_JOYAXISMOTION:
241 if (event.jaxis.axis == 0)
243 joyX = event.jaxis.value;
245 else if (event.jaxis.axis == 1)
247 joyY = event.jaxis.value;
252 case SDL_JOYBUTTONDOWN:
256 lastButtonPressed = event.jbutton.button;
257 *highlightedWidget->value = lastButtonPressed;
258 highlightedWidget->redraw();
259 waitForButton = false;
264 joystickState[event.jbutton.button] = 1;
267 case SDL_JOYBUTTONUP:
268 joystickState[event.jbutton.button] = 0;
277 int Engine::getMouseX()
282 int Engine::getMouseY()
287 void Engine::setMouse(int x, int y)
292 bool Engine::userAccepts()
294 if ((keyState[SDLK_SPACE]) || (keyState[SDLK_ESCAPE]) || (keyState[SDLK_LCTRL]) || (keyState[SDLK_RCTRL]) || (keyState[SDLK_RETURN]) || (keyState[SDLK_LCTRL]))
302 void Engine::flushInput()
304 while (SDL_PollEvent(&event)){}
307 void Engine::clearInput()
309 for (int i = 0 ; i < 350 ; i++)
312 mouseLeft = mouseRight = 0;
315 void Engine::setUserHome(const char *path)
317 strncpy(userHomeDirectory, path, sizeof userHomeDirectory);
318 debug(("User Home = %s\n", path));
321 Pak *Engine::getPak()
327 Searches the pak file for the required data. When
328 it is found, the data is read into a character buffer.
329 In the case of music, the data music be written to a temporary directory
330 since SDL currently provides no means to load music directly from memory
332 bool Engine::unpack(const char *filename, int fileType)
334 if (fileType == PAK_DATA)
336 if (dataBuffer != NULL)
343 if (binaryBuffer != NULL)
344 delete[] binaryBuffer;
349 if (fileType != PAK_DATA)
351 if (!pak.unpack(filename, &binaryBuffer))
358 if (!pak.unpack(filename, &dataBuffer))
364 if ((fileType == PAK_IMG) || (fileType == PAK_SOUND))
366 sdlrw = SDL_RWFromMem(binaryBuffer, pak.getUncompressedSize());
369 printf("Fatal Error: SDL_RWops allocation failed\n");
374 if ((fileType == PAK_MUSIC) || (fileType == PAK_FONT))
376 char tempPath[PATH_MAX];
380 if (fileType == PAK_MUSIC)
382 snprintf(tempPath, sizeof tempPath, "%smusic.mod", userHomeDirectory);
383 fp = fopen(tempPath, "wb");
386 if (fileType == PAK_FONT)
388 snprintf(tempPath, sizeof tempPath, "%sfont.ttf", userHomeDirectory);
389 fp = fopen(tempPath, "wb");
397 fwrite(binaryBuffer, 1, pak.getUncompressedSize(), fp);
401 debug(("unpack() : Loaded %s (%d)\n", filename, pak.getUncompressedSize()));
406 bool Engine::loadData(const char *filename)
408 if (dataBuffer != NULL)
415 return unpack(filename, PAK_DATA);
419 fp = fopen(filename, "rb");
423 fseek(fp, 0, SEEK_END);
425 int fSize = ftell(fp);
429 dataBuffer = new unsigned char[fSize];
431 fread(dataBuffer, 1, fSize, fp);
435 debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
440 void Engine::reportFontFailure()
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");
451 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
453 playerPosX = x - OFFSETX;
454 playerPosY = y - OFFSETY;
456 Math::limitInt(&playerPosX, limitLeft, limitRight);
457 Math::limitInt(&playerPosY, limitUp, limitDown);
460 int Engine::getFrameLoop()
465 void Engine::doFrameLoop()
467 Math::wrapChar(&(++frameLoop), 0, 59);
470 void Engine::doTimeDifference()
472 timeDifference = (time2 - time1) / 10.0;
474 time2 = SDL_GetTicks();
477 float Engine::getTimeDifference()
479 return timeDifference;
482 void Engine::resetTimeDifference()
484 time1 = time2 = SDL_GetTicks();
487 void Engine::setInfoMessage(const char *message, int priority, int type)
489 if (priority >= messagePriority)
491 strncpy(this->message, message, sizeof this->message);
493 messagePriority = priority;
498 void Engine::deleteWidgets()
502 for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
507 highlightedWidget = NULL;
510 void Engine::addWidget(Widget *widget)
512 widget->previous = (Widget*)widgetList.getTail();
513 widgetList.add(widget);
516 bool Engine::loadWidgets(const char *filename)
520 if (!loadData(filename))
523 char token[50], name[50], groupName[50], label[80], options[100], *line;
530 line = strtok((char*)dataBuffer, "\n");
534 sscanf(line, "%s", token);
536 if (strcmp(token, "END") == 0)
539 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
547 if (strcmp(token, widgetName[i]) == 0)
550 if (strcmp("-1", widgetName[i]) == 0)
556 widget->setProperties(name, groupName, label, options, x, y, min, max);
561 if ((line = strtok(NULL, "\n")) == NULL)
565 highlightedWidget = (Widget*)widgetList.getHead()->next;
570 Widget *Engine::getWidgetByName(const char *name)
572 Widget *widget = (Widget*)widgetList.getHead();
574 while (widget->next != NULL)
576 widget = (Widget*)widget->next;
578 if (strcmp(widget->name, name) == 0)
582 debug(("No such widget '%s'\n", name));
587 void Engine::showWidgetGroup(const char *groupName, bool show)
591 Widget *widget = (Widget*)widgetList.getHead();
593 while (widget->next != NULL)
595 widget = (Widget*)widget->next;
597 if (strcmp(widget->groupName, groupName) == 0)
599 widget->visible = show;
606 debug(("Group '%s' does not exist\n", groupName));
609 void Engine::enableWidgetGroup(const char *groupName, bool show)
613 Widget *widget = (Widget*)widgetList.getHead();
615 while (widget->next != NULL)
617 widget = (Widget*)widget->next;
619 if (strcmp(widget->groupName, groupName) == 0)
621 widget->enabled = show;
628 debug(("Group '%s' does not exist\n", groupName));
631 void Engine::showWidget(const char *name, bool show)
633 Widget *widget = getWidgetByName(name);
636 widget->visible = show;
641 void Engine::enableWidget(const char *name, bool enable)
643 Widget *widget = getWidgetByName(name);
646 widget->enabled = enable;
651 void Engine::setWidgetVariable(const char *name, int *variable)
653 Widget *widget = getWidgetByName(name);
655 widget->value = variable;
658 bool Engine::widgetChanged(const char *name)
660 Widget *widget = getWidgetByName(name);
662 return widget->changed;
667 void Engine::highlightWidget(int dir)
669 highlightedWidget->redraw();
675 if (highlightedWidget->next != NULL)
677 highlightedWidget = (Widget*)highlightedWidget->next;
681 highlightedWidget = (Widget*)widgetList.getHead()->next;
684 if (highlightedWidget->type == 4)
687 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
696 if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
698 highlightedWidget = highlightedWidget->previous;
702 highlightedWidget = (Widget*)widgetList.getTail();
705 if (highlightedWidget->type == WG_LABEL)
708 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
713 highlightedWidget->redraw();
716 void Engine::highlightWidget(const char *name)
718 highlightedWidget = getWidgetByName(name);
721 int Engine::processWidgets()
725 if (keyState[SDLK_UP])
732 if (keyState[SDLK_DOWN])
739 if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
743 if (*highlightedWidget->value > highlightedWidget->min)
745 *highlightedWidget->value = *highlightedWidget->value - 1;
747 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
749 highlightedWidget->changed = true;
752 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
756 if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
760 if (*highlightedWidget->value < highlightedWidget->max)
762 *highlightedWidget->value = *highlightedWidget->value + 1;
764 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
766 highlightedWidget->changed = true;
769 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
773 if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
775 if (highlightedWidget->value == NULL)
777 debug(("%s has not been implemented!\n", highlightedWidget->name));
781 if (highlightedWidget->type == WG_BUTTON)
783 *highlightedWidget->value = 1;
784 highlightedWidget->changed = true;
786 else if (highlightedWidget->type == WG_JOYPAD)
788 waitForButton = true;
792 if (*highlightedWidget->value > -1000)
794 *highlightedWidget->value = (-1000 - *highlightedWidget->value);
797 else if (highlightedWidget->type == WG_KEYBOARD)
800 waitForButton = false;
802 *highlightedWidget->value = -*highlightedWidget->value;
817 char *strtok_r(char *s1, const char *s2, char **lasts)
826 while (*s1 && strchr(s2, *s1))
838 while(*s1 && !strchr(s2, *s1))
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.
859 bool Engine::loadDefines()
861 char string[2][1024];
863 if (!loadData("data/defines.h"))
866 char *token = strtok((char*)dataBuffer, "\n");
872 token = strtok(NULL, "\n");
876 if (!strstr(token, "/*"))
878 sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
880 data->set(string[0], string[1], 1, 1);
881 defineList.add(data);
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... :)
895 int Engine::getValueOfDefine(const char *word)
899 Data *data = (Data*)defineList.getHead();
901 while (data->next != NULL)
903 data = (Data*)data->next;
905 if (strcmp(data->key, word) == 0)
907 rtn = atoi(data->value);
912 printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
917 Does the opposite of the above(!)
919 char *Engine::getDefineOfValue(const char *prefix, int value)
923 Data *data = (Data*)defineList.getHead();
925 while (data->next != NULL)
927 data = (Data*)data->next;
929 if (strstr(data->key, prefix))
931 rtn = atoi(data->value);
940 printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
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 :)
950 int Engine::getValueOfFlagTokens(const char *realLine)
952 if (strcmp(realLine, "0") == 0)
959 strncpy(line, realLine, sizeof line);
963 char *word = strtok_r(line, "+", &store);
967 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
975 data = (Data*)defineList.getHead();
978 while (data->next != NULL)
980 data = (Data*)data->next;
982 if (strcmp(data->key, word) == 0)
985 sscanf(data->value, "%d", &value);
989 sscanf(data->value, "%*s %*d %*s %d", &value);
1001 printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1002 #if IGNORE_FLAGTOKEN_ERRORS
1009 word = strtok_r(NULL, "+", &store);
1017 void Engine::delay(unsigned int frameLimit) {
1018 unsigned int ticks = SDL_GetTicks();
1020 if(frameLimit < ticks)
1023 if(frameLimit > ticks + 16)
1026 SDL_Delay(frameLimit - ticks);