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 + 1];
431 fread(dataBuffer, 1, fSize, fp);
432 dataBuffer[fSize] = 0;
436 debug(("loadData() : Loaded %s (%d)\n", filename, fSize));
441 void Engine::reportFontFailure()
443 printf("\nUnable to load font. The game cannot continue without it.\n");
444 printf("Please confirm that the game and all required SDL libraries are installed\n");
445 printf("The following information may be useful to you,\n\n");
446 printf("Expected location of PAK file: %s\n", PAKFULLPATH);
447 printf("Location of TMP directory: %s\n", userHomeDirectory);
448 printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
452 void Engine::setPlayerPosition(int x, int y, int limitLeft, int limitRight, int limitUp, int limitDown)
454 playerPosX = x - OFFSETX;
455 playerPosY = y - OFFSETY;
457 Math::limitInt(&playerPosX, limitLeft, limitRight);
458 Math::limitInt(&playerPosY, limitUp, limitDown);
461 int Engine::getFrameLoop()
466 void Engine::doFrameLoop()
468 Math::wrapChar(&(++frameLoop), 0, 59);
471 void Engine::doTimeDifference()
473 timeDifference = (time2 - time1) / 10.0;
475 time2 = SDL_GetTicks();
478 float Engine::getTimeDifference()
480 return timeDifference;
483 void Engine::resetTimeDifference()
485 time1 = time2 = SDL_GetTicks();
488 void Engine::setInfoMessage(const char *message, int priority, int type)
490 if (priority >= messagePriority)
492 strncpy(this->message, message, sizeof this->message);
494 messagePriority = priority;
499 void Engine::deleteWidgets()
503 for (widget = (Widget*)widgetList.getHead()->next ; widget != NULL ; widget = (Widget*)widget->next)
508 highlightedWidget = NULL;
511 void Engine::addWidget(Widget *widget)
513 widget->previous = (Widget*)widgetList.getTail();
514 widgetList.add(widget);
517 bool Engine::loadWidgets(const char *filename)
521 if (!loadData(filename))
524 char token[50], name[50], groupName[50], label[80], options[100], *line;
531 line = strtok((char*)dataBuffer, "\n");
535 sscanf(line, "%s", token);
537 if (strcmp(token, "END") == 0)
540 sscanf(line, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name, groupName, label, options, &x, &y, &min, &max);
548 if (strcmp(token, widgetName[i]) == 0)
551 if (strcmp("-1", widgetName[i]) == 0)
557 widget->setProperties(name, groupName, label, options, x, y, min, max);
562 if ((line = strtok(NULL, "\n")) == NULL)
566 highlightedWidget = (Widget*)widgetList.getHead()->next;
571 Widget *Engine::getWidgetByName(const char *name)
573 Widget *widget = (Widget*)widgetList.getHead();
575 while (widget->next != NULL)
577 widget = (Widget*)widget->next;
579 if (strcmp(widget->name, name) == 0)
583 debug(("No such widget '%s'\n", name));
588 void Engine::showWidgetGroup(const char *groupName, bool show)
592 Widget *widget = (Widget*)widgetList.getHead();
594 while (widget->next != NULL)
596 widget = (Widget*)widget->next;
598 if (strcmp(widget->groupName, groupName) == 0)
600 widget->visible = show;
607 debug(("Group '%s' does not exist\n", groupName));
610 void Engine::enableWidgetGroup(const char *groupName, bool show)
614 Widget *widget = (Widget*)widgetList.getHead();
616 while (widget->next != NULL)
618 widget = (Widget*)widget->next;
620 if (strcmp(widget->groupName, groupName) == 0)
622 widget->enabled = show;
629 debug(("Group '%s' does not exist\n", groupName));
632 void Engine::showWidget(const char *name, bool show)
634 Widget *widget = getWidgetByName(name);
637 widget->visible = show;
642 void Engine::enableWidget(const char *name, bool enable)
644 Widget *widget = getWidgetByName(name);
647 widget->enabled = enable;
652 void Engine::setWidgetVariable(const char *name, int *variable)
654 Widget *widget = getWidgetByName(name);
656 widget->value = variable;
659 bool Engine::widgetChanged(const char *name)
661 Widget *widget = getWidgetByName(name);
663 return widget->changed;
668 void Engine::highlightWidget(int dir)
670 highlightedWidget->redraw();
676 if (highlightedWidget->next != NULL)
678 highlightedWidget = (Widget*)highlightedWidget->next;
682 highlightedWidget = (Widget*)widgetList.getHead()->next;
685 if (highlightedWidget->type == 4)
688 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
697 if ((highlightedWidget->previous != NULL) && (highlightedWidget->previous != (Widget*)widgetList.getHead()))
699 highlightedWidget = highlightedWidget->previous;
703 highlightedWidget = (Widget*)widgetList.getTail();
706 if (highlightedWidget->type == WG_LABEL)
709 if ((highlightedWidget->enabled) && (highlightedWidget->visible))
714 highlightedWidget->redraw();
717 void Engine::highlightWidget(const char *name)
719 highlightedWidget = getWidgetByName(name);
722 int Engine::processWidgets()
726 if (keyState[SDLK_UP])
733 if (keyState[SDLK_DOWN])
740 if (keyState[SDLK_LEFT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
744 if (*highlightedWidget->value > highlightedWidget->min)
746 *highlightedWidget->value = *highlightedWidget->value - 1;
748 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
750 highlightedWidget->changed = true;
753 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
757 if (keyState[SDLK_RIGHT] && (highlightedWidget->type != WG_BUTTON && highlightedWidget->type != WG_JOYPAD))
761 if (*highlightedWidget->value < highlightedWidget->max)
763 *highlightedWidget->value = *highlightedWidget->value + 1;
765 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
767 highlightedWidget->changed = true;
770 if ((highlightedWidget->type == WG_RADIO) || (highlightedWidget->type == WG_SLIDER))
774 if ((keyState[SDLK_RETURN]) || (keyState[SDLK_SPACE]) || (keyState[SDLK_LCTRL]))
776 if (highlightedWidget->value == NULL)
778 debug(("%s has not been implemented!\n", highlightedWidget->name));
782 if (highlightedWidget->type == WG_BUTTON)
784 *highlightedWidget->value = 1;
785 highlightedWidget->changed = true;
787 else if (highlightedWidget->type == WG_JOYPAD)
789 waitForButton = true;
793 if (*highlightedWidget->value > -1000)
795 *highlightedWidget->value = (-1000 - *highlightedWidget->value);
798 else if (highlightedWidget->type == WG_KEYBOARD)
801 waitForButton = false;
803 *highlightedWidget->value = -*highlightedWidget->value;
818 char *strtok_r(char *s1, const char *s2, char **lasts)
827 while (*s1 && strchr(s2, *s1))
839 while(*s1 && !strchr(s2, *s1))
856 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
857 game at compile time and run time, so everything is syncronised. This technique has the advantage of
858 allowing the game's data to be human readable and easy to maintain.
860 bool Engine::loadDefines()
862 char string[2][1024];
864 if (!loadData("data/defines.h"))
867 char *token = strtok((char*)dataBuffer, "\n");
873 token = strtok(NULL, "\n");
877 if (!strstr(token, "/*"))
879 sscanf(token, "%*s %s %[^\n\r]", string[0], string[1]);
881 data->set(string[0], string[1], 1, 1);
882 defineList.add(data);
890 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
891 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
892 1) It makes the game data human readable and 2) It means if I change a #define in
893 the code, I don't have to change all the data entries too. You probably already
894 thought of that though... :)
896 int Engine::getValueOfDefine(const char *word)
900 Data *data = (Data*)defineList.getHead();
902 while (data->next != NULL)
904 data = (Data*)data->next;
906 if (strcmp(data->key, word) == 0)
908 rtn = atoi(data->value);
913 printf("ERROR: getValueOfDefine() : %s is not defined!\n", word);
918 Does the opposite of the above(!)
920 char *Engine::getDefineOfValue(const char *prefix, int value)
924 Data *data = (Data*)defineList.getHead();
926 while (data->next != NULL)
928 data = (Data*)data->next;
930 if (strstr(data->key, prefix))
932 rtn = atoi(data->value);
941 printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix, value);
946 I like this function. It receives a list of flags declared by their #define name... like
947 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
948 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
949 the values together and then returns them... phew! Makes data files human readable though :)
951 int Engine::getValueOfFlagTokens(const char *realLine)
953 if (strcmp(realLine, "0") == 0)
960 strncpy(line, realLine, sizeof line);
964 char *word = strtok_r(line, "+", &store);
968 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
976 data = (Data*)defineList.getHead();
979 while (data->next != NULL)
981 data = (Data*)data->next;
983 if (strcmp(data->key, word) == 0)
986 sscanf(data->value, "%d", &value);
990 sscanf(data->value, "%*s %*d %*s %d", &value);
1002 printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word);
1003 #if IGNORE_FLAGTOKEN_ERRORS
1010 word = strtok_r(NULL, "+", &store);
1018 void Engine::delay(unsigned int frameLimit) {
1019 unsigned int ticks = SDL_GetTicks();
1021 if(frameLimit < ticks)
1024 if(frameLimit > ticks + 16)
1027 SDL_Delay(frameLimit - ticks);