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);
92 cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
93 cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
98 void Engine::destroy()
100 debug(("engine: free widgets\n"));
103 debug(("engine: free databuffer\n"));
104 if (dataBuffer != NULL)
107 debug(("engine: free binarybuffer\n"));
108 if (binaryBuffer != NULL)
109 delete[] binaryBuffer;
111 debug(("Clearing Define List...\n"));
115 void Engine::clearCheatVars()
117 memset(lastKeyEvents, ' ', 25);
118 cheatHealth = cheatExtras = cheatFuel = cheatLevels = false;
119 cheatBlood = cheatInvulnerable = cheatReload = cheatSpeed = cheatSkipLevel = false;
122 bool Engine::compareLastKeyInputs()
124 if (strstr(lastKeyEvents, "lockandload"))
133 void Engine::addKeyEvent()
135 if (strlen(lastKeyPressed) > 1)
142 for (int i = 0 ; i < 25 ; i++)
144 if (lastKeyEvents[i] == ' ')
153 for (int i = 0 ; i < 25 ; i++)
155 lastKeyEvents[i] = lastKeyEvents[i + 1];
161 lastKeyEvents[index] = lastKeyPressed[0];
163 compareLastKeyInputs();
166 void Engine::getInput()
168 SDL_GetMouseState(&mouseX, &mouseY);
170 while (SDL_PollEvent(&event))
181 case SDL_MOUSEBUTTONDOWN:
182 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 1;
183 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 1;
186 case SDL_MOUSEBUTTONUP:
187 if (event.button.button == SDL_BUTTON_LEFT) mouseLeft = 0;
188 if (event.button.button == SDL_BUTTON_RIGHT) mouseRight = 0;
195 if (event.key.keysym.sym == SDLK_ESCAPE)
197 lastButtonPressed = -1;
198 *highlightedWidget->value = abs(*highlightedWidget->value) - 1000;
199 highlightedWidget->redraw();
200 waitForButton = false;
204 if (event.key.keysym.sym == SDLK_BACKSPACE)
206 lastButtonPressed = -2;
207 *highlightedWidget->value = -2;
208 highlightedWidget->redraw();
209 waitForButton = false;
218 if (event.key.keysym.sym == SDLK_ESCAPE)
220 *highlightedWidget->value = -*highlightedWidget->value;
224 *highlightedWidget->value = event.key.keysym.sym;
227 lastButtonPressed = -1;
228 highlightedWidget->redraw();
229 waitForButton = false;
236 keyState[event.key.keysym.sym] = 1;
237 strncpy(lastKeyPressed, SDL_GetKeyName(event.key.keysym.sym), sizeof lastKeyPressed);
242 keyState[event.key.keysym.sym] = 0;
245 case SDL_JOYAXISMOTION:
246 if (event.jaxis.axis == 0)
248 joyX = event.jaxis.value;
250 else if (event.jaxis.axis == 1)
252 joyY = event.jaxis.value;
257 case SDL_JOYBUTTONDOWN:
261 lastButtonPressed = event.jbutton.button;
262 *highlightedWidget->value = lastButtonPressed;
263 highlightedWidget->redraw();
264 waitForButton = false;
269 joystickState[event.jbutton.button] = 1;
272 case SDL_JOYBUTTONUP:
273 joystickState[event.jbutton.button] = 0;
282 int Engine::getMouseX()
287 int Engine::getMouseY()
292 void Engine::setMouse(int x, int y)
297 bool Engine::userAccepts()
299 if ((keyState[SDLK_SPACE]) || (keyState[SDLK_ESCAPE]) || (keyState[SDLK_LCTRL]) || (keyState[SDLK_RCTRL]) || (keyState[SDLK_RETURN]) || (keyState[SDLK_LCTRL]))
307 void Engine::flushInput()
309 while (SDL_PollEvent(&event)){}
312 void Engine::clearInput()
314 for (int i = 0 ; i < 350 ; i++)
317 mouseLeft = mouseRight = 0;
320 void Engine::setUserHome(const char *path)
322 strncpy(userHomeDirectory, path, sizeof userHomeDirectory);
323 debug(("User Home = %s\n", path));
326 Pak *Engine::getPak()
332 Searches the pak file for the required data. When
333 it is found, the data is read into a character buffer.
334 In the case of music, the data music be written to a temporary directory
335 since SDL currently provides no means to load music directly from memory
337 bool Engine::unpack(const char *filename, int fileType)
339 if (fileType == PAK_DATA)
341 if (dataBuffer != NULL)
348 if (binaryBuffer != NULL)
349 delete[] binaryBuffer;
354 if (fileType != PAK_DATA)
356 if (!pak.unpack(filename, &binaryBuffer))
363 if (!pak.unpack(filename, &dataBuffer))
369 if ((fileType == PAK_IMG) || (fileType == PAK_SOUND))
371 sdlrw = SDL_RWFromMem(binaryBuffer, pak.getUncompressedSize());
374 printf("Fatal Error: SDL_RWops allocation failed\n");
379 if ((fileType == PAK_MUSIC) || (fileType == PAK_FONT))
381 char tempPath[PATH_MAX];
385 if (fileType == PAK_MUSIC)
387 snprintf(tempPath, sizeof tempPath, "%smusic.mod", userHomeDirectory);
388 fp = fopen(tempPath, "wb");
391 if (fileType == PAK_FONT)
393 snprintf(tempPath, sizeof tempPath, "%sfont.ttf", userHomeDirectory);
394 fp = fopen(tempPath, "wb");
402 fwrite(binaryBuffer, 1, pak.getUncompressedSize(), fp);
406 debug(("unpack() : Loaded %s (%d)\n", filename, pak.getUncompressedSize()));
411 bool Engine::loadData(const char *filename)
413 if (dataBuffer != NULL)
420 return unpack(filename, PAK_DATA);
424 fp = fopen(filename, "rb");
428 fseek(fp, 0, SEEK_END);
430 int fSize = ftell(fp);
434 dataBuffer = new unsigned char[fSize];
436 fread(dataBuffer, 1, fSize, fp);
440 debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
445 void Engine::reportFontFailure()
447 printf("\nUnable to load font. The game cannot continue without it.\n");
448 printf("Please confirm that the game and all required SDL libraries are installed\n");
449 printf("The following information may be useful to you,\n\n");
450 printf("Expected location of PAK file: %s\n", PAKFULLPATH);
451 printf("Location of TMP directory: %s\n", userHomeDirectory);
452 printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
456 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
458 playerPosX = x - OFFSETX;
459 playerPosY = y - OFFSETY;
461 Math::limitInt(&playerPosX, limitLeft, limitRight);
462 Math::limitInt(&playerPosY, limitUp, limitDown);
465 int Engine::getFrameLoop()
470 void Engine::doFrameLoop()
472 Math::wrapChar(&(++frameLoop), 0, 59);
475 void Engine::doTimeDifference()
477 timeDifference = (time2 - time1) / 10.0;
479 time2 = SDL_GetTicks();
482 float Engine::getTimeDifference()
484 return timeDifference;
487 void Engine::resetTimeDifference()
489 time1 = time2 = SDL_GetTicks();
492 void Engine::setInfoMessage(const char *message, int priority, int type)
494 if (priority >= messagePriority)
496 strncpy(this->message, message, sizeof this->message);
498 messagePriority = priority;
503 void Engine::deleteWidgets()
507 for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
512 highlightedWidget = NULL;
515 void Engine::addWidget(Widget *widget)
517 widget->previous = (Widget*)widgetList.getTail();
518 widgetList.add(widget);
521 bool Engine::loadWidgets(const char *filename)
525 if (!loadData(filename))
528 char token[50], name[50], groupName[50], label[80], options[100], *line;
535 line = strtok((char*)dataBuffer, "\n");
539 sscanf(line, "%s", token);
541 if (strcmp(token, "END") == 0)
544 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
552 if (strcmp(token, widgetName[i]) == 0)
555 if (strcmp("-1", widgetName[i]) == 0)
561 widget->setProperties(name, groupName, label, options, x, y, min, max);
566 if ((line = strtok(NULL, "\n")) == NULL)
570 highlightedWidget = (Widget*)widgetList.getHead()->next;
575 Widget *Engine::getWidgetByName(const char *name)
577 Widget *widget = (Widget*)widgetList.getHead();
579 while (widget->next != NULL)
581 widget = (Widget*)widget->next;
583 if (strcmp(widget->name, name) == 0)
587 debug(("No such widget '%s'\n", name));
592 void Engine::showWidgetGroup(const char *groupName, bool show)
596 Widget *widget = (Widget*)widgetList.getHead();
598 while (widget->next != NULL)
600 widget = (Widget*)widget->next;
602 if (strcmp(widget->groupName, groupName) == 0)
604 widget->visible = show;
611 debug(("Group '%s' does not exist\n", groupName));
614 void Engine::enableWidgetGroup(const char *groupName, bool show)
618 Widget *widget = (Widget*)widgetList.getHead();
620 while (widget->next != NULL)
622 widget = (Widget*)widget->next;
624 if (strcmp(widget->groupName, groupName) == 0)
626 widget->enabled = show;
633 debug(("Group '%s' does not exist\n", groupName));
636 void Engine::showWidget(const char *name, bool show)
638 Widget *widget = getWidgetByName(name);
641 widget->visible = show;
646 void Engine::enableWidget(const char *name, bool enable)
648 Widget *widget = getWidgetByName(name);
651 widget->enabled = enable;
656 void Engine::setWidgetVariable(const char *name, int *variable)
658 Widget *widget = getWidgetByName(name);
660 widget->value = variable;
663 bool Engine::widgetChanged(const char *name)
665 Widget *widget = getWidgetByName(name);
667 return widget->changed;
672 void Engine::highlightWidget(int dir)
674 highlightedWidget->redraw();
680 if (highlightedWidget->next != NULL)
682 highlightedWidget = (Widget*)highlightedWidget->next;
686 highlightedWidget = (Widget*)widgetList.getHead()->next;
689 if (highlightedWidget->type == 4)
692 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
701 if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
703 highlightedWidget = highlightedWidget->previous;
707 highlightedWidget = (Widget*)widgetList.getTail();
710 if (highlightedWidget->type == WG_LABEL)
713 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
718 highlightedWidget->redraw();
721 void Engine::highlightWidget(const char *name)
723 highlightedWidget = getWidgetByName(name);
726 int Engine::processWidgets()
730 if (keyState[SDLK_UP])
737 if (keyState[SDLK_DOWN])
744 if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
748 if (*highlightedWidget->value > highlightedWidget->min)
750 *highlightedWidget->value = *highlightedWidget->value - 1;
752 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
754 highlightedWidget->changed = true;
757 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
761 if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
765 if (*highlightedWidget->value < highlightedWidget->max)
767 *highlightedWidget->value = *highlightedWidget->value + 1;
769 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
771 highlightedWidget->changed = true;
774 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
778 if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
780 if (highlightedWidget->value == NULL)
782 debug(("%s has not been implemented!\n", highlightedWidget->name));
786 if (highlightedWidget->type == WG_BUTTON)
788 *highlightedWidget->value = 1;
789 highlightedWidget->changed = true;
791 else if (highlightedWidget->type == WG_JOYPAD)
793 waitForButton = true;
797 if (*highlightedWidget->value > -1000)
799 *highlightedWidget->value = (-1000 - *highlightedWidget->value);
802 else if (highlightedWidget->type == WG_KEYBOARD)
805 waitForButton = false;
807 *highlightedWidget->value = -*highlightedWidget->value;
822 char *strtok_r(char *s1, const char *s2, char **lasts)
831 while (*s1 && strchr(s2, *s1))
843 while(*s1 && !strchr(s2, *s1))
860 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
861 game at compile time and run time, so everything is syncronised. This technique has the advantage of
862 allowing the game's data to be human readable and easy to maintain.
864 bool Engine::loadDefines()
866 char string[2][1024];
868 if (!loadData("data/defines.h"))
871 char *token = strtok((char*)dataBuffer, "\n");
877 token = strtok(NULL, "\n");
881 if (!strstr(token, "/*"))
883 sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
885 data->set(string[0], string[1], 1, 1);
886 defineList.add(data);
894 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
895 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
896 1) It makes the game data human readable and 2) It means if I change a #define in
897 the code, I don't have to change all the data entries too. You probably already
898 thought of that though... :)
900 int Engine::getValueOfDefine(const char *word)
904 Data *data = (Data*)defineList.getHead();
906 while (data->next != NULL)
908 data = (Data*)data->next;
910 if (strcmp(data->key, word) == 0)
912 rtn = atoi(data->value);
917 printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
922 Does the opposite of the above(!)
924 char *Engine::getDefineOfValue(const char *prefix, int value)
928 Data *data = (Data*)defineList.getHead();
930 while (data->next != NULL)
932 data = (Data*)data->next;
934 if (strstr(data->key, prefix))
936 rtn = atoi(data->value);
945 printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
950 I like this function. It receives a list of flags declared by their #define name... like
951 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
952 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
953 the values together and then returns them... phew! Makes data files human readable though :)
955 int Engine::getValueOfFlagTokens(const char *realLine)
957 if (strcmp(realLine, "0") == 0)
964 strncpy(line, realLine, sizeof line);
968 char *word = strtok_r(line, "+", &store);
972 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
980 data = (Data*)defineList.getHead();
983 while (data->next != NULL)
985 data = (Data*)data->next;
987 if (strcmp(data->key, word) == 0)
990 sscanf(data->value, "%d", &value);
994 sscanf(data->value, "%*s %*d %*s %d", &value);
1006 printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1007 #if IGNORE_FLAGTOKEN_ERRORS
1014 word = strtok_r(NULL, "+", &store);
1022 void Engine::delay(unsigned int frameLimit) {
1023 unsigned int ticks = SDL_GetTicks();
1025 if(frameLimit < ticks)
1028 if(frameLimit > ticks + 16)
1031 SDL_Delay(frameLimit - ticks);