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 strcpy(lastKeyPressed
, "");
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);
93 cheatHealth
= cheatExtras
= cheatFuel
= cheatLevels
= false;
94 cheatBlood
= cheatInvulnerable
= cheatReload
= cheatSpeed
= cheatSkipLevel
= false;
99 void Engine::destroy()
101 debug(("engine: free widgets\n"));
104 debug(("engine: free databuffer\n"));
105 if (dataBuffer
!= NULL
)
108 debug(("engine: free binarybuffer\n"));
109 if (binaryBuffer
!= NULL
)
110 delete[] binaryBuffer
;
112 debug(("Clearing Define List...\n"));
116 void Engine::clearCheatVars()
118 memset(lastKeyEvents
, ' ', 25);
119 cheatHealth
= cheatExtras
= cheatFuel
= cheatLevels
= false;
120 cheatBlood
= cheatInvulnerable
= cheatReload
= cheatSpeed
= cheatSkipLevel
= false;
123 bool Engine::compareLastKeyInputs()
125 if (strstr(lastKeyEvents
, "lockandload"))
134 void Engine::addKeyEvent()
136 if (strlen(lastKeyPressed
) > 1)
143 for (int i
= 0 ; i
< 25 ; i
++)
145 if (lastKeyEvents
[i
] == ' ')
154 for (int i
= 0 ; i
< 25 ; i
++)
156 lastKeyEvents
[i
] = lastKeyEvents
[i
+ 1];
162 lastKeyEvents
[index
] = lastKeyPressed
[0];
164 compareLastKeyInputs();
167 void Engine::getInput()
169 SDL_GetMouseState(&mouseX
, &mouseY
);
171 while (SDL_PollEvent(&event
))
182 case SDL_MOUSEBUTTONDOWN
:
183 if (event
.button
.button
== SDL_BUTTON_LEFT
) mouseLeft
= 1;
184 if (event
.button
.button
== SDL_BUTTON_RIGHT
) mouseRight
= 1;
187 case SDL_MOUSEBUTTONUP
:
188 if (event
.button
.button
== SDL_BUTTON_LEFT
) mouseLeft
= 0;
189 if (event
.button
.button
== SDL_BUTTON_RIGHT
) mouseRight
= 0;
196 if (event
.key
.keysym
.sym
== SDLK_ESCAPE
)
198 lastButtonPressed
= -1;
199 *highlightedWidget
->value
= abs(*highlightedWidget
->value
) - 1000;
200 highlightedWidget
->redraw();
201 waitForButton
= false;
205 if (event
.key
.keysym
.sym
== SDLK_BACKSPACE
)
207 lastButtonPressed
= -2;
208 *highlightedWidget
->value
= -2;
209 highlightedWidget
->redraw();
210 waitForButton
= false;
219 if (event
.key
.keysym
.sym
== SDLK_ESCAPE
)
221 *highlightedWidget
->value
= -*highlightedWidget
->value
;
225 *highlightedWidget
->value
= event
.key
.keysym
.sym
;
228 lastButtonPressed
= -1;
229 highlightedWidget
->redraw();
230 waitForButton
= false;
237 keyState
[event
.key
.keysym
.sym
] = 1;
238 strcpy(lastKeyPressed
, SDL_GetKeyName(event
.key
.keysym
.sym
));
243 keyState
[event
.key
.keysym
.sym
] = 0;
246 case SDL_JOYAXISMOTION
:
247 if (event
.jaxis
.axis
== 0)
249 joyX
= event
.jaxis
.value
;
251 else if (event
.jaxis
.axis
== 1)
253 joyY
= event
.jaxis
.value
;
258 case SDL_JOYBUTTONDOWN
:
262 lastButtonPressed
= event
.jbutton
.button
;
263 *highlightedWidget
->value
= lastButtonPressed
;
264 highlightedWidget
->redraw();
265 waitForButton
= false;
270 joystickState
[event
.jbutton
.button
] = 1;
273 case SDL_JOYBUTTONUP
:
274 joystickState
[event
.jbutton
.button
] = 0;
283 int Engine::getMouseX()
288 int Engine::getMouseY()
293 void Engine::setMouse(int x
, int y
)
298 bool Engine::userAccepts()
300 if ((keyState
[SDLK_SPACE
]) || (keyState
[SDLK_ESCAPE
]) || (keyState
[SDLK_LCTRL
]) || (keyState
[SDLK_RCTRL
]) || (keyState
[SDLK_RETURN
]) || (keyState
[SDLK_LCTRL
]))
308 void Engine::flushInput()
310 while (SDL_PollEvent(&event
)){}
313 void Engine::clearInput()
315 for (int i
= 0 ; i
< 350 ; i
++)
318 mouseLeft
= mouseRight
= 0;
321 void Engine::setUserHome(char *path
)
323 strcpy(userHomeDirectory
, path
);
324 debug(("User Home = %s\n", path
));
327 Pak
*Engine::getPak()
333 Searches the pak file for the required data. When
334 it is found, the data is read into a character buffer.
335 In the case of music, the data music be written to a temporary directory
336 since SDL currently provides no means to load music directly from memory
338 bool Engine::unpack(char *filename
, int fileType
)
340 if (fileType
== PAK_DATA
)
342 if (dataBuffer
!= NULL
)
349 if (binaryBuffer
!= NULL
)
350 delete[] binaryBuffer
;
355 if (fileType
!= PAK_DATA
)
357 if (!pak
.unpack(filename
, &binaryBuffer
))
364 if (!pak
.unpack(filename
, &dataBuffer
))
370 if ((fileType
== PAK_IMG
) || (fileType
== PAK_SOUND
))
372 sdlrw
= SDL_RWFromMem(binaryBuffer
, pak
.getUncompressedSize());
375 printf("Fatal Error: SDL_RWops allocation failed\n");
380 if ((fileType
== PAK_MUSIC
) || (fileType
== PAK_FONT
))
382 char tempPath
[PATH_MAX
];
386 if (fileType
== PAK_MUSIC
)
388 sprintf(tempPath
, "%smusic.mod", userHomeDirectory
);
389 fp
= fopen(tempPath
, "wb");
392 if (fileType
== PAK_FONT
)
394 sprintf(tempPath
, "%sfont.ttf", userHomeDirectory
);
395 fp
= fopen(tempPath
, "wb");
403 fwrite(binaryBuffer
, 1, pak
.getUncompressedSize(), fp
);
407 debug(("unpack() : Loaded %s (%d)\n", filename
, pak
.getUncompressedSize()));
412 bool Engine::loadData(char *filename
)
414 if (dataBuffer
!= NULL
)
421 return unpack(filename
, PAK_DATA
);
425 fp
= fopen(filename
, "rb");
429 fseek(fp
, 0, SEEK_END
);
431 int fSize
= ftell(fp
);
435 dataBuffer
= new unsigned char[fSize
];
437 fread(dataBuffer
, 1, fSize
, fp
);
441 debug(("loadData() : Loaded %s (%d)\n", filename
, fSize
));
446 void Engine::reportFontFailure()
448 printf("\nUnable to load font. The game cannot continue without it.\n");
449 printf("Please confirm that the game and all required SDL libraries are installed\n");
450 printf("The following information may be useful to you,\n\n");
451 printf("Expected location of PAK file: %s\n", PAKFULLPATH
);
452 printf("Location of TMP directory: %s\n", userHomeDirectory
);
453 printf("\nAlso try checking http://www.parallelrealities.co.uk/blobWars.php for updates\n\n");
457 void Engine::setPlayerPosition(int x
, int y
, int limitLeft
, int limitRight
, int limitUp
, int limitDown
)
459 playerPosX
= x
- OFFSETX
;
460 playerPosY
= y
- OFFSETY
;
462 Math::limitInt(&playerPosX
, limitLeft
, limitRight
);
463 Math::limitInt(&playerPosY
, limitUp
, limitDown
);
466 int Engine::getFrameLoop()
471 void Engine::doFrameLoop()
473 Math::wrapChar(&(++frameLoop
), 0, 59);
476 void Engine::doTimeDifference()
478 timeDifference
= (time2
- time1
) / 10.0;
480 time2
= SDL_GetTicks();
483 float Engine::getTimeDifference()
485 return timeDifference
;
488 void Engine::resetTimeDifference()
490 time1
= time2
= SDL_GetTicks();
493 void Engine::setInfoMessage(char *message
, int priority
, int type
)
495 if (priority
>= messagePriority
)
497 strcpy(this->message
, message
);
499 messagePriority
= priority
;
504 void Engine::deleteWidgets()
508 for (widget
= (Widget
*)widgetList
.getHead()->next
; widget
!= NULL
; widget
= (Widget
*)widget
->next
)
513 highlightedWidget
= NULL
;
516 void Engine::addWidget(Widget
*widget
)
518 widget
->previous
= (Widget
*)widgetList
.getTail();
519 widgetList
.add(widget
);
522 bool Engine::loadWidgets(char *filename
)
526 if (!loadData(filename
))
529 char token
[50], name
[50], groupName
[50], label
[80], options
[100], *line
;
536 line
= strtok((char*)dataBuffer
, "\n");
540 sscanf(line
, "%s", token
);
542 if (strcmp(token
, "END") == 0)
545 sscanf(line
, "%*s %s %s %*c %[^\"] %*c %*c %[^\"] %*c %d %d %d %d", name
, groupName
, label
, options
, &x
, &y
, &min
, &max
);
553 if (strcmp(token
, widgetName
[i
]) == 0)
556 if (strcmp("-1", widgetName
[i
]) == 0)
562 widget
->setProperties(name
, groupName
, label
, options
, x
, y
, min
, max
);
567 if ((line
= strtok(NULL
, "\n")) == NULL
)
571 highlightedWidget
= (Widget
*)widgetList
.getHead()->next
;
576 Widget
*Engine::getWidgetByName(char *name
)
578 Widget
*widget
= (Widget
*)widgetList
.getHead();
580 while (widget
->next
!= NULL
)
582 widget
= (Widget
*)widget
->next
;
584 if (strcmp(widget
->name
, name
) == 0)
588 debug(("No such widget '%s'\n", name
));
593 void Engine::showWidgetGroup(char *groupName
, bool show
)
597 Widget
*widget
= (Widget
*)widgetList
.getHead();
599 while (widget
->next
!= NULL
)
601 widget
= (Widget
*)widget
->next
;
603 if (strcmp(widget
->groupName
, groupName
) == 0)
605 widget
->visible
= show
;
612 debug(("Group '%s' does not exist\n", groupName
));
615 void Engine::enableWidgetGroup(char *groupName
, bool show
)
619 Widget
*widget
= (Widget
*)widgetList
.getHead();
621 while (widget
->next
!= NULL
)
623 widget
= (Widget
*)widget
->next
;
625 if (strcmp(widget
->groupName
, groupName
) == 0)
627 widget
->enabled
= show
;
634 debug(("Group '%s' does not exist\n", groupName
));
637 void Engine::showWidget(char *name
, bool show
)
639 Widget
*widget
= getWidgetByName(name
);
642 widget
->visible
= show
;
647 void Engine::enableWidget(char *name
, bool enable
)
649 Widget
*widget
= getWidgetByName(name
);
652 widget
->enabled
= enable
;
657 void Engine::setWidgetVariable(char *name
, int *variable
)
659 Widget
*widget
= getWidgetByName(name
);
661 widget
->value
= variable
;
664 bool Engine::widgetChanged(char *name
)
666 Widget
*widget
= getWidgetByName(name
);
668 return widget
->changed
;
673 void Engine::highlightWidget(int dir
)
675 highlightedWidget
->redraw();
681 if (highlightedWidget
->next
!= NULL
)
683 highlightedWidget
= (Widget
*)highlightedWidget
->next
;
687 highlightedWidget
= (Widget
*)widgetList
.getHead()->next
;
690 if (highlightedWidget
->type
== 4)
693 if ((highlightedWidget
->enabled
) && (highlightedWidget
->visible
))
702 if ((highlightedWidget
->previous
!= NULL
) && (highlightedWidget
->previous
!= (Widget
*)widgetList
.getHead()))
704 highlightedWidget
= highlightedWidget
->previous
;
708 highlightedWidget
= (Widget
*)widgetList
.getTail();
711 if (highlightedWidget
->type
== WG_LABEL
)
714 if ((highlightedWidget
->enabled
) && (highlightedWidget
->visible
))
719 highlightedWidget
->redraw();
722 void Engine::highlightWidget(char *name
)
724 highlightedWidget
= getWidgetByName(name
);
727 int Engine::processWidgets()
731 if (keyState
[SDLK_UP
])
738 if (keyState
[SDLK_DOWN
])
745 if (keyState
[SDLK_LEFT
] && (highlightedWidget
->type
!= WG_BUTTON
&& highlightedWidget
->type
!= WG_JOYPAD
))
749 if (*highlightedWidget
->value
> highlightedWidget
->min
)
751 *highlightedWidget
->value
= *highlightedWidget
->value
- 1;
753 if ((highlightedWidget
->type
== WG_RADIO
) || (highlightedWidget
->type
== WG_SLIDER
))
755 highlightedWidget
->changed
= true;
758 if ((highlightedWidget
->type
== WG_RADIO
) || (highlightedWidget
->type
== WG_SLIDER
))
762 if (keyState
[SDLK_RIGHT
] && (highlightedWidget
->type
!= WG_BUTTON
&& highlightedWidget
->type
!= WG_JOYPAD
))
766 if (*highlightedWidget
->value
< highlightedWidget
->max
)
768 *highlightedWidget
->value
= *highlightedWidget
->value
+ 1;
770 if ((highlightedWidget
->type
== WG_RADIO
) || (highlightedWidget
->type
== WG_SLIDER
))
772 highlightedWidget
->changed
= true;
775 if ((highlightedWidget
->type
== WG_RADIO
) || (highlightedWidget
->type
== WG_SLIDER
))
779 if ((keyState
[SDLK_RETURN
]) || (keyState
[SDLK_SPACE
]) || (keyState
[SDLK_LCTRL
]))
781 if (highlightedWidget
->value
== NULL
)
783 debug(("%s has not been implemented!\n", highlightedWidget
->name
));
787 if (highlightedWidget
->type
== WG_BUTTON
)
789 *highlightedWidget
->value
= 1;
790 highlightedWidget
->changed
= true;
792 else if (highlightedWidget
->type
== WG_JOYPAD
)
794 waitForButton
= true;
798 if (*highlightedWidget
->value
> -1000)
800 *highlightedWidget
->value
= (-1000 - *highlightedWidget
->value
);
803 else if (highlightedWidget
->type
== WG_KEYBOARD
)
806 waitForButton
= false;
808 *highlightedWidget
->value
= -*highlightedWidget
->value
;
823 char *strtok_r(char *s1
, const char *s2
, char **lasts
)
832 while (*s1
&& strchr(s2
, *s1
))
844 while(*s1
&& !strchr(s2
, *s1
))
861 Loads key-value defines into a linked list, comments are ignored. The defines.h file is used by the
862 game at compile time and run time, so everything is syncronised. This technique has the advantage of
863 allowing the game's data to be human readable and easy to maintain.
865 bool Engine::loadDefines()
867 char string
[2][1024];
869 if (!loadData("data/defines.h"))
872 char *token
= strtok((char*)dataBuffer
, "\n");
878 token
= strtok(NULL
, "\n");
882 if (!strstr(token
, "/*"))
884 sscanf(token
, "%*s %s %[^\n\r]", string
[0], string
[1]);
886 data
->set(string
[0], string
[1], 1, 1);
887 defineList
.add(data
);
895 Returns the value of a #defined value... ACTIVE is declared as 1 so it will
896 traverse the list and return 1 when it encounters ACTIVE. This has two advantages.
897 1) It makes the game data human readable and 2) It means if I change a #define in
898 the code, I don't have to change all the data entries too. You probably already
899 thought of that though... :)
901 int Engine::getValueOfDefine(char *word
)
905 Data
*data
= (Data
*)defineList
.getHead();
907 while (data
->next
!= NULL
)
909 data
= (Data
*)data
->next
;
911 if (strcmp(data
->key
, word
) == 0)
913 rtn
= atoi(data
->value
);
918 printf("ERROR: getValueOfDefine() : %s is not defined!\n", word
);
923 Does the opposite of the above(!)
925 char *Engine::getDefineOfValue(char *prefix
, int value
)
929 Data
*data
= (Data
*)defineList
.getHead();
931 while (data
->next
!= NULL
)
933 data
= (Data
*)data
->next
;
935 if (strstr(data
->key
, prefix
))
937 rtn
= atoi(data
->value
);
946 printf("ERROR: getDefineOfValue() : %s, %d is not defined!\n", prefix
, value
);
951 I like this function. It receives a list of flags declared by their #define name... like
952 the function above, delimited with plus signs. So ENT_FLIES+ENT_AIMS. It then works out the
953 flags (in a bit of a half arsed manner because of my lazy (2 << 25) declarations, adds all
954 the values together and then returns them... phew! Makes data files human readable though :)
956 int Engine::getValueOfFlagTokens(char *realLine
)
958 if (strcmp(realLine
, "0") == 0)
965 strcpy(line
, realLine
);
969 char *word
= strtok_r(line
, "+", &store
);
973 printf("ERROR: getValueOfFlagTokens() : NULL Pointer!\n");
981 data
= (Data
*)defineList
.getHead();
984 while (data
->next
!= NULL
)
986 data
= (Data
*)data
->next
;
988 if (strcmp(data
->key
, word
) == 0)
991 sscanf(data
->value
, "%d", &value
);
995 sscanf(data
->value
, "%*s %*d %*s %d", &value
);
1007 printf("ERROR: getValueOfFlagTokens() : Illegal Token '%s'\n", word
);
1008 #if IGNORE_FLAGTOKEN_ERRORS
1015 word
= strtok_r(NULL
, "+", &store
);
1023 void Engine::delay(unsigned int frameLimit
) {
1024 unsigned int ticks
= SDL_GetTicks();
1026 if(frameLimit
< ticks
)
1029 if(frameLimit
> ticks
+ 16)
1032 SDL_Delay(frameLimit
- ticks
);