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 strlcpy(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"));
101 debug(("engine: free binarybuffer\n"));
102 delete[] binaryBuffer;
104 debug(("Clearing Define List...\n"));
108 void Engine::clearCheatVars()
110 memset(lastKeyEvents, ' ', 25);
111 cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
112 cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
115 bool Engine::compareLastKeyInputs()
117 if (strstr(lastKeyEvents, "lockandload"))
126 void Engine::addKeyEvent()
128 if (strlen(lastKeyPressed) > 1)
135 for (int i = 0 ; i < 25 ; i++)
137 if (lastKeyEvents[i] == ' ')
146 for (int i = 0 ; i < 24 ; i++)
148 lastKeyEvents[i] = lastKeyEvents[i + 1];
154 lastKeyEvents[index] = lastKeyPressed[0];
156 compareLastKeyInputs();
159 void Engine::getInput()
161 SDL_GetMouseState(&mouseX, &mouseY);
163 while (SDL_PollEvent(&event))
174 case SDL_MOUSEBUTTONDOWN:
175 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 1;
176 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 1;
179 case SDL_MOUSEBUTTONUP:
180 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 0;
181 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 0;
188 if (event.key.keysym.sym == SDLK_ESCAPE)
190 lastButtonPressed = -1;
191 *highlightedWidget->value = abs(*highlightedWidget->value) - 1000;
192 highlightedWidget->redraw();
193 waitForButton = false;
197 if (event.key.keysym.sym == SDLK_BACKSPACE)
199 lastButtonPressed = -2;
200 *highlightedWidget->value = -2;
201 highlightedWidget->redraw();
202 waitForButton = false;
211 if (event.key.keysym.sym == SDLK_ESCAPE)
213 *highlightedWidget->value = -*highlightedWidget->value;
217 *highlightedWidget->value = event.key.keysym.sym;
220 lastButtonPressed = -1;
221 highlightedWidget->redraw();
222 waitForButton = false;
229 keyState[event.key.keysym.sym] = 1;
230 strlcpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.sym), sizeof lastKeyPressed);
235 keyState[event.key.keysym.sym] = 0;
238 case SDL_JOYAXISMOTION:
239 if (event.jaxis.axis == 0)
241 joyX = event.jaxis.value;
243 else if (event.jaxis.axis == 1)
245 joyY = event.jaxis.value;
250 case SDL_JOYBUTTONDOWN:
254 lastButtonPressed = event.jbutton.button;
255 *highlightedWidget->value = lastButtonPressed;
256 highlightedWidget->redraw();
257 waitForButton = false;
262 joystickState[event.jbutton.button] = 1;
265 case SDL_JOYBUTTONUP:
266 joystickState[event.jbutton.button] = 0;
275 int Engine::getMouseX() const
280 int Engine::getMouseY() const
285 void Engine::setMouse(int x, int y)
290 bool Engine::userAccepts()
292 if ((keyState[SDLK_SPACE]) || (keyState[SDLK_ESCAPE]) || (keyState[SDLK_LCTRL]) || (keyState[SDLK_RCTRL]) || (keyState[SDLK_RETURN]) || (keyState[SDLK_LCTRL]))
300 void Engine::flushInput()
302 while (SDL_PollEvent(&event)){}
305 void Engine::clearInput()
307 for (int i = 0 ; i < 350 ; i++)
310 mouseLeft = mouseRight = 0;
313 void Engine::setUserHome(const char *path)
315 strlcpy(userHomeDirectory, path, sizeof userHomeDirectory);
316 debug(("User Home = %s\n", path));
319 Pak *Engine::getPak()
325 Searches the pak file for the required data. When
326 it is found, the data is read into a character buffer.
327 In the case of music, the data music be written to a temporary directory
328 since SDL currently provides no means to load music directly from memory
330 bool Engine::unpack(const char *filename, int fileType)
332 if (fileType == PAK_DATA)
339 delete[] binaryBuffer;
343 if (fileType != PAK_DATA)
345 if (!pak.unpack(filename, &binaryBuffer))
352 if (!pak.unpack(filename, &dataBuffer))
358 if ((fileType == PAK_IMG) || (fileType == PAK_SOUND))
360 sdlrw = SDL_RWFromMem(binaryBuffer, pak.getUncompressedSize());
363 printf("Fatal Error: SDL_RWops allocation failed\n");
368 if ((fileType == PAK_MUSIC) || (fileType == PAK_FONT))
370 char tempPath[PATH_MAX];
374 if (fileType == PAK_MUSIC)
376 snprintf(tempPath, sizeof tempPath, "%smusic.mod", userHomeDirectory);
377 fp = fopen(tempPath, "wb");
380 if (fileType == PAK_FONT)
382 snprintf(tempPath, sizeof tempPath, "%sfont.ttf", userHomeDirectory);
383 fp = fopen(tempPath, "wb");
391 fwrite(binaryBuffer, 1, pak.getUncompressedSize(), fp);
395 debug(("unpack() : Loaded %s (%d)\n", filename, pak.getUncompressedSize()));
400 bool Engine::loadData(const char *filename)
406 return unpack(filename, PAK_DATA);
410 fp = fopen(filename, "rb");
414 fseek(fp, 0, SEEK_END);
416 int fSize = ftell(fp);
420 dataBuffer = new unsigned char[fSize + 1];
422 fread(dataBuffer, 1, fSize, fp);
423 dataBuffer[fSize] = 0;
427 debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
432 void Engine::reportFontFailure()
434 printf("\nUnable to load font. The game cannot continue without it.\n");
435 printf("Please confirm that the game and all required SDL libraries are installed\n");
436 printf("The following information may be useful to you,\n\n");
437 printf("Expected location of PAK file: %s\n", PAKFULLPATH);
438 printf("Location of TMP directory: %s\n", userHomeDirectory);
439 printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
443 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
445 playerPosX = x - OFFSETX;
446 playerPosY = y - OFFSETY;
448 Math::limitInt(&playerPosX, limitLeft, limitRight);
449 Math::limitInt(&playerPosY, limitUp, limitDown);
452 int Engine::getFrameLoop() const
457 void Engine::doFrameLoop()
459 Math::wrapChar(&(++frameLoop), 0, 59);
462 void Engine::doTimeDifference()
464 timeDifference = (time2 - time1) / 10.0;
466 time2 = SDL_GetTicks();
469 float Engine::getTimeDifference() const
471 return timeDifference;
474 void Engine::resetTimeDifference()
476 time1 = time2 = SDL_GetTicks();
479 void Engine::setInfoMessage(const char *message, int priority, int type)
481 if (priority >= messagePriority)
483 strlcpy(this->message, message, sizeof this->message);
485 messagePriority = priority;
490 void Engine::deleteWidgets()
494 for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
499 highlightedWidget = NULL;
502 void Engine::addWidget(Widget *widget)
504 widget->previous = (Widget*)widgetList.getTail();
505 widgetList.add(widget);
508 bool Engine::loadWidgets(const char *filename)
512 if (!loadData(filename))
515 char token[50], name[50], groupName[50], label[80], options[100], *line;
522 line = strtok((char*)dataBuffer, "\n");
526 sscanf(line, "%s", token);
528 if (strcmp(token, "END") == 0)
531 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
539 if (strcmp(token, widgetName[i]) == 0)
542 if (strcmp("-1", widgetName[i]) == 0)
548 widget->setProperties(name, groupName, label, options, x, y, min, max);
553 if ((line = strtok(NULL, "\n")) == NULL)
557 highlightedWidget = (Widget*)widgetList.getHead()->next;
562 Widget *Engine::getWidgetByName(const char *name)
564 Widget *widget = (Widget*)widgetList.getHead();
566 while (widget->next != NULL)
568 widget = (Widget*)widget->next;
570 if (strcmp(widget->name, name) == 0)
574 debug(("No such widget '%s'\n", name));
579 void Engine::showWidgetGroup(const char *groupName, bool show)
583 Widget *widget = (Widget*)widgetList.getHead();
585 while (widget->next != NULL)
587 widget = (Widget*)widget->next;
589 if (strcmp(widget->groupName, groupName) == 0)
591 widget->visible = show;
598 debug(("Group '%s' does not exist\n", groupName));
601 void Engine::enableWidgetGroup(const char *groupName, bool show)
605 Widget *widget = (Widget*)widgetList.getHead();
607 while (widget->next != NULL)
609 widget = (Widget*)widget->next;
611 if (strcmp(widget->groupName, groupName) == 0)
613 widget->enabled = show;
620 debug(("Group '%s' does not exist\n", groupName));
623 void Engine::showWidget(const char *name, bool show)
625 Widget *widget = getWidgetByName(name);
628 widget->visible = show;
633 void Engine::enableWidget(const char *name, bool enable)
635 Widget *widget = getWidgetByName(name);
638 widget->enabled = enable;
643 void Engine::setWidgetVariable(const char *name, int *variable)
645 Widget *widget = getWidgetByName(name);
647 widget->value = variable;
650 bool Engine::widgetChanged(const char *name)
652 Widget *widget = getWidgetByName(name);
654 return widget->changed;
659 void Engine::highlightWidget(int dir)
661 highlightedWidget->redraw();
667 if (highlightedWidget->next != NULL)
669 highlightedWidget = (Widget*)highlightedWidget->next;
673 highlightedWidget = (Widget*)widgetList.getHead()->next;
676 if (highlightedWidget->type == 4)
679 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
688 if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
690 highlightedWidget = highlightedWidget->previous;
694 highlightedWidget = (Widget*)widgetList.getTail();
697 if (highlightedWidget->type == WG_LABEL)
700 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
705 highlightedWidget->redraw();
708 void Engine::highlightWidget(const char *name)
710 highlightedWidget = getWidgetByName(name);
713 int Engine::processWidgets()
717 if (keyState[SDLK_UP])
724 if (keyState[SDLK_DOWN])
731 if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
735 if (*highlightedWidget->value > highlightedWidget->min)
737 *highlightedWidget->value = *highlightedWidget->value - 1;
739 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
741 highlightedWidget->changed = true;
744 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
748 if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
752 if (*highlightedWidget->value < highlightedWidget->max)
754 *highlightedWidget->value = *highlightedWidget->value + 1;
756 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
758 highlightedWidget->changed = true;
761 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
765 if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
767 if (highlightedWidget->value == NULL)
769 debug(("%s has not been implemented!\n", highlightedWidget->name));
773 if (highlightedWidget->type == WG_BUTTON)
775 *highlightedWidget->value = 1;
776 highlightedWidget->changed = true;
778 else if (highlightedWidget->type == WG_JOYPAD)
780 waitForButton = true;
784 if (*highlightedWidget->value > -1000)
786 *highlightedWidget->value = (-1000 - *highlightedWidget->value);
789 else if (highlightedWidget->type == WG_KEYBOARD)
792 waitForButton = false;
794 *highlightedWidget->value = -*highlightedWidget->value;
809 char *strtok_r(char *s1, const char *s2, char **lasts)
818 while (*s1 && strchr(s2, *s1))
830 while(*s1 && !strchr(s2, *s1))
847 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
848 game at compile time and run time, so everything is syncronised. This technique has the advantage of
849 allowing the game's data to be human readable and easy to maintain.
851 bool Engine::loadDefines()
853 char string[2][1024];
855 if (!loadData("data/defines.h"))
858 char *token = strtok((char*)dataBuffer, "\n");
864 token = strtok(NULL, "\n");
868 if (!strstr(token, "/*"))
870 sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
872 data->set(string[0], string[1], 1, 1);
873 defineList.add(data);
881 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
882 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
883 1) It makes the game data human readable and 2) It means if I change a #define in
884 the code, I don't have to change all the data entries too. You probably already
885 thought of that though... :)
887 int Engine::getValueOfDefine(const char *word)
891 Data *data = (Data*)defineList.getHead();
893 while (data->next != NULL)
895 data = (Data*)data->next;
897 if (strcmp(data->key, word) == 0)
899 rtn = atoi(data->value);
904 printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
909 Does the opposite of the above(!)
911 char *Engine::getDefineOfValue(const char *prefix, int value)
915 Data *data = (Data*)defineList.getHead();
917 while (data->next != NULL)
919 data = (Data*)data->next;
921 if (strstr(data->key, prefix))
923 rtn = atoi(data->value);
932 printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
937 I like this function. It receives a list of flags declared by their #define name... like
938 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
939 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
940 the values together and then returns them... phew! Makes data files human readable though :)
942 int Engine::getValueOfFlagTokens(const char *realLine)
944 if (strcmp(realLine, "0") == 0)
951 strlcpy(line, realLine, sizeof line);
955 char *word = strtok_r(line, "+", &store);
959 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
967 data = (Data*)defineList.getHead();
970 while (data->next != NULL)
972 data = (Data*)data->next;
974 if (strcmp(data->key, word) == 0)
977 sscanf(data->value, "%d", &value);
981 sscanf(data->value, "%*s %*d %*s %d", &value);
993 printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
994 #if IGNORE_FLAGTOKEN_ERRORS
1001 word = strtok_r(NULL, "+", &store);
1009 void Engine::delay(unsigned int frameLimit) {
1010 unsigned int ticks = SDL_GetTicks();
1012 if(frameLimit < ticks)
1015 if(frameLimit > ticks + 16)
1018 SDL_Delay(frameLimit - ticks);