-
-
Save Myvar/d0aaf3c34baee8aafc5f5d080b44abc1 to your computer and use it in GitHub Desktop.
Nasty Hackky code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//stuff like this nastyness | |
extern boolean isInMenu; | |
extern boolean isInDialog; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef SDL_PATHS | |
#include <unistd.h> | |
#endif | |
#include <limits.h> | |
#include <SDL_image.h> | |
#include <SDL_gamecontroller.h> | |
#include "platform.h" | |
#include "tiles.h" | |
#include "GlobalsBase.h" | |
#define PAUSE_BETWEEN_EVENT_POLLING 36L // 17 | |
#define MAX_REMAPS 128 | |
struct keypair | |
{ | |
char from; | |
char to; | |
}; | |
static struct keypair remapping[MAX_REMAPS]; | |
static size_t nremaps = 0; | |
static enum graphicsModes showGraphics = TEXT_GRAPHICS; | |
static SDL_GameController *controller = NULL; | |
static rogueEvent lastEvent; | |
static void sdlfatal(char *file, int line) | |
{ | |
fprintf(stderr, "Fatal SDL error (%s:%d): %s\n", file, line, SDL_GetError()); | |
exit(EXIT_STATUS_FAILURE_PLATFORM_ERROR); | |
} | |
static void imgfatal(char *file, int line) | |
{ | |
fprintf(stderr, "Fatal SDL_image error (%s:%d): %s\n", file, line, IMG_GetError()); | |
exit(EXIT_STATUS_FAILURE_PLATFORM_ERROR); | |
} | |
/* | |
If the key is to be processed, returns true and updates event. False | |
otherwise. This function only listens for keypresses which do not produce | |
corresponding TextInputEvents. | |
*/ | |
static boolean eventFromKey(rogueEvent *event, SDL_Keycode key) | |
{ | |
event->param1 = -1; | |
switch (key) | |
{ | |
case SDLK_ESCAPE: | |
event->param1 = ESCAPE_KEY; | |
return true; | |
case SDLK_UP: | |
event->param1 = UP_ARROW; | |
return true; | |
case SDLK_DOWN: | |
event->param1 = DOWN_ARROW; | |
return true; | |
case SDLK_RIGHT: | |
event->param1 = RIGHT_ARROW; | |
return true; | |
case SDLK_LEFT: | |
event->param1 = LEFT_ARROW; | |
return true; | |
case SDLK_RETURN: | |
case SDLK_KP_ENTER: | |
event->param1 = RETURN_KEY; | |
return true; | |
case SDLK_BACKSPACE: | |
event->param1 = DELETE_KEY; | |
return true; | |
case SDLK_TAB: | |
event->param1 = TAB_KEY; | |
return true; | |
case SDLK_PRINTSCREEN: | |
event->param1 = PRINTSCREEN_KEY; | |
return true; | |
} | |
/* | |
Only process keypad events when we're holding a modifier, as there is no | |
TextInputEvent then. | |
*/ | |
if (event->shiftKey || event->controlKey) | |
{ | |
switch (key) | |
{ | |
case SDLK_KP_0: | |
event->param1 = NUMPAD_0; | |
return true; | |
case SDLK_KP_1: | |
event->param1 = NUMPAD_1; | |
return true; | |
case SDLK_KP_2: | |
event->param1 = NUMPAD_2; | |
return true; | |
case SDLK_KP_3: | |
event->param1 = NUMPAD_3; | |
return true; | |
case SDLK_KP_4: | |
event->param1 = NUMPAD_4; | |
return true; | |
case SDLK_KP_5: | |
event->param1 = NUMPAD_5; | |
return true; | |
case SDLK_KP_6: | |
event->param1 = NUMPAD_6; | |
return true; | |
case SDLK_KP_7: | |
event->param1 = NUMPAD_7; | |
return true; | |
case SDLK_KP_8: | |
event->param1 = NUMPAD_8; | |
return true; | |
case SDLK_KP_9: | |
event->param1 = NUMPAD_9; | |
return true; | |
} | |
} | |
// Ctrl+letter doesn't give a TextInputEvent | |
if (event->controlKey && key >= SDLK_a && key <= SDLK_z) | |
{ | |
event->param1 = 'a' + (key - SDLK_a); | |
if (event->shiftKey) | |
event->param1 -= 'a' - 'A'; | |
return true; | |
} | |
return false; | |
} | |
static boolean _modifierHeld(int mod) | |
{ | |
SDL_Keymod km = SDL_GetModState(); | |
return mod == 0 && (km & (KMOD_LSHIFT | KMOD_RSHIFT)) || mod == 1 && (km & (KMOD_LCTRL | KMOD_RCTRL)); | |
} | |
static char applyRemaps(char c) | |
{ | |
for (size_t i = 0; i < nremaps; i++) | |
{ | |
if (remapping[i].from == c) | |
return remapping[i].to; | |
} | |
return c; | |
} | |
int prevxDir = 0; | |
int prevyDir = 0; | |
int toggle = 0; | |
int mouseX = 0; | |
int mouseY = 0; | |
/* | |
If an event is available, returns true and updates returnEvent. Otherwise | |
it returns false and an error event. This function also processes | |
platform-specific inputs/behaviours. | |
*/ | |
static boolean pollBrogueEvent(rogueEvent *returnEvent, boolean textInput) | |
{ | |
static int mx = 0, my = 0; | |
returnEvent->eventType = EVENT_ERROR; | |
returnEvent->shiftKey = _modifierHeld(0); | |
returnEvent->controlKey = _modifierHeld(1); | |
SDL_Event event; | |
boolean ret = false; | |
// ~ for (int i=0; i < 100 && SDL_PollEvent(&event); i++) { | |
while (SDL_PollEvent(&event)) | |
{ | |
if (event.type == SDL_QUIT) | |
{ | |
// the player clicked the X button! | |
SDL_Quit(); | |
int statusCode = quitImmediately(); | |
exit(statusCode); | |
} | |
else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) | |
{ | |
resizeWindow(event.window.data1, event.window.data2); | |
} | |
else if (event.type == SDL_KEYDOWN) | |
{ | |
SDL_Keycode key = event.key.keysym.sym; | |
if (key == SDLK_PAGEUP) | |
{ | |
resizeWindow(max(windowWidth * 11 / 10, windowWidth + 1), max(windowHeight * 11 / 10, windowHeight + 1)); | |
continue; | |
} | |
else if (key == SDLK_PAGEDOWN) | |
{ | |
fullScreen = false; | |
resizeWindow(max(windowWidth * 10 / 11, 1), max(windowHeight * 10 / 11, 1)); | |
continue; | |
} | |
else if (key == SDLK_F11 || key == SDLK_F12 || key == SDLK_RETURN && (SDL_GetModState() & KMOD_ALT)) | |
{ | |
fullScreen = !fullScreen; | |
resizeWindow(-1, -1); // Reset to starting resolution | |
continue; | |
} | |
if (eventFromKey(returnEvent, key)) | |
{ | |
returnEvent->eventType = KEYSTROKE; | |
return true; | |
} | |
} | |
else if (event.type == SDL_TEXTINPUT && (unsigned char)(event.text.text[0]) < 0x80) | |
{ | |
/* | |
It's difficult/impossible to check what characters are on the | |
shifts of keys. So to detect '&', '>' etc. reliably we need to | |
listen for text input events as well as keydowns. This results | |
in hybrid keyboard code, where Brogue KEYSTROKEs can come from | |
different SDL events. | |
*/ | |
char c = event.text.text[0]; | |
if (!textInput) | |
{ | |
c = applyRemaps(c); | |
if (c == '=' || c == '+') | |
{ | |
resizeWindow(max(windowWidth * 11 / 10, windowWidth + 1), max(windowHeight * 11 / 10, windowHeight + 1)); | |
} | |
else if (c == '-') | |
{ | |
fullScreen = false; | |
resizeWindow(max(windowWidth * 10 / 11, 1), max(windowHeight * 10 / 11, 1)); | |
} | |
} | |
returnEvent->eventType = KEYSTROKE; | |
returnEvent->param1 = c; | |
// ~ printf("textinput %s\n", event.text.text); | |
return true; | |
} | |
else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) | |
{ | |
if (event.button.button == SDL_BUTTON_LEFT || event.button.button == SDL_BUTTON_RIGHT) | |
{ | |
if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) | |
{ | |
returnEvent->eventType = MOUSE_DOWN; | |
} | |
else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT) | |
{ | |
returnEvent->eventType = MOUSE_UP; | |
} | |
else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) | |
{ | |
returnEvent->eventType = RIGHT_MOUSE_DOWN; | |
} | |
else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_RIGHT) | |
{ | |
returnEvent->eventType = RIGHT_MOUSE_UP; | |
} | |
returnEvent->param1 = event.button.x * COLS / windowWidth; | |
returnEvent->param2 = event.button.y * ROWS / windowHeight; | |
return true; | |
} | |
} | |
else if (event.type == SDL_MOUSEMOTION) | |
{ | |
// We don't want to return on a mouse motion event, because only the last | |
// in the queue is important. That's why we just set ret=true | |
int xcell = event.motion.x * COLS / windowWidth, | |
ycell = event.motion.y * ROWS / windowHeight; | |
if (xcell != mx || ycell != my) | |
{ | |
returnEvent->eventType = MOUSE_ENTERED_CELL; | |
returnEvent->param1 = xcell; | |
returnEvent->param2 = ycell; | |
mx = xcell; | |
my = ycell; | |
ret = true; | |
} | |
} | |
else if (event.type == SDL_CONTROLLERAXISMOTION) | |
{ | |
int xDir = 0; | |
int yDir = 0; | |
const int JOYSTICK_DEAD_ZONE = 8000; | |
// Motion on controller 0 | |
// X axis motion | |
if (event.jaxis.axis == 0) | |
{ | |
// Left of dead zone | |
if (event.jaxis.value < -JOYSTICK_DEAD_ZONE) | |
{ | |
xDir = -1; | |
} | |
// Right of dead zone | |
else if (event.jaxis.value > JOYSTICK_DEAD_ZONE) | |
{ | |
xDir = 1; | |
} | |
else | |
{ | |
xDir = 0; | |
} | |
} | |
// Y axis motion | |
else if (event.jaxis.axis == 1) | |
{ | |
// Below of dead zone | |
if (event.jaxis.value < -JOYSTICK_DEAD_ZONE) | |
{ | |
yDir = -1; | |
} | |
// Above of dead zone | |
else if (event.jaxis.value > JOYSTICK_DEAD_ZONE) | |
{ | |
yDir = 1; | |
} | |
else | |
{ | |
yDir = 0; | |
} | |
} | |
int speed = 30; | |
mouseX += xDir * speed; | |
mouseY += yDir * speed; | |
if (mouseX < 0) | |
{ | |
mouseX = 0; | |
} | |
if (mouseX > windowWidth) | |
{ | |
mouseX = windowWidth; | |
} | |
if (mouseY < 0) | |
{ | |
mouseY = 0; | |
} | |
if (mouseY > windowHeight) | |
{ | |
mouseY = windowHeight; | |
} | |
// int xcell = mouseX * COLS / windowWidth, | |
// ycell = mouseY * ROWS / windowHeight; | |
// returnEvent->eventType = MOUSE_ENTERED_CELL; | |
// returnEvent->param1 = xcell; | |
// returnEvent->param2 = ycell; | |
// ret = true; | |
if (event.jaxis.axis == 5) | |
{ | |
returnEvent->eventType = KEYSTROKE; | |
returnEvent->param1 = RETURN_KEY; | |
return true; | |
} | |
prevxDir = xDir; | |
prevyDir = yDir; | |
} | |
else if (event.type == SDL_CONTROLLERBUTTONDOWN) | |
{ | |
returnEvent->eventType = KEYSTROKE; | |
if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) | |
{ | |
toggle = 1; | |
returnEvent->param1 = 'n'; | |
return true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) | |
{ | |
returnEvent->param1 = toggle ? 'y' : LEFT_ARROW; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) | |
{ | |
returnEvent->param1 = toggle ? 'n' : RIGHT_ARROW; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP) | |
{ | |
returnEvent->param1 = toggle ? 'u' : UP_ARROW; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) | |
{ | |
returnEvent->param1 = toggle ? 'b' : DOWN_ARROW; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A) | |
{ | |
if (toggle) | |
{ | |
returnEvent->eventType = MOUSE_DOWN; | |
int xcell = mouseX * COLS / windowWidth, | |
ycell = mouseY * ROWS / windowHeight; | |
returnEvent->param1 = xcell; | |
returnEvent->param2 = ycell; | |
} | |
else | |
{ | |
if(isInMenu) { | |
returnEvent->param1 = 'a'; | |
} else { | |
returnEvent->param1 = 'x'; | |
} | |
} | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y) | |
{ | |
returnEvent->param1 = 't'; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_B) | |
{ | |
if(isInMenu) { | |
returnEvent->param1 = ESCAPE_KEY; | |
ret = true; | |
} else { | |
returnEvent->param1 = 'z'; | |
ret = true; | |
} | |
} else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_START) | |
{ | |
returnEvent->param1 = 'i'; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) | |
{ | |
returnEvent->param1 = 'y'; | |
ret = true; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK) | |
{ | |
returnEvent->param1 = '>'; | |
ret = true; | |
} | |
} | |
else if (event.type == SDL_CONTROLLERBUTTONUP) | |
{ | |
if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) | |
{ | |
toggle = 0; | |
} | |
else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A) | |
{ | |
if (toggle) | |
{ | |
returnEvent->eventType = MOUSE_UP; | |
int xcell = mouseX * COLS / windowWidth, | |
ycell = mouseY * ROWS / windowHeight; | |
returnEvent->param1 = xcell; | |
returnEvent->param2 = ycell; | |
return true; | |
} | |
} | |
} | |
else if (event.type == SDL_CONTROLLERDEVICEADDED) | |
{ | |
printf("device added\n"); | |
} | |
else if (event.type == SDL_CONTROLLERDEVICEREMOVED) | |
{ | |
printf("device removed\n"); | |
} | |
} | |
return ret; | |
} | |
static void _gameLoop() | |
{ | |
#ifdef SDL_PATHS | |
char *path = SDL_GetBasePath(); | |
if (path) | |
{ | |
fprintf(stderr, "Base path: %s\n", path); | |
path[strlen(path) - 1] = '\0'; // remove trailing separator | |
strcpy(dataDirectory, path); | |
} | |
else | |
{ | |
fprintf(stderr, "Failed to find the path to the application\n"); | |
exit(EXIT_STATUS_FAILURE_PLATFORM_ERROR); | |
} | |
free(path); | |
path = SDL_GetPrefPath("Brogue", "Brogue CE"); | |
if (!path || chdir(path) != 0) | |
{ | |
fprintf(stderr, "Failed to find or change to the save directory\n"); | |
exit(EXIT_STATUS_FAILURE_PLATFORM_ERROR); | |
} | |
fprintf(stderr, "Save path: %s\n", path); | |
free(path); | |
#endif | |
SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1"); | |
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) | |
sdlfatal(__FILE__, __LINE__); | |
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) | |
imgfatal(__FILE__, __LINE__); | |
initTiles(); | |
lastEvent.eventType = EVENT_ERROR; | |
resizeWindow(windowWidth, windowHeight); | |
int nJoysticks = SDL_NumJoysticks(); | |
int nController = nJoysticks; | |
printf("Starting: num of joys: %d, num of cont: %d ...\n", nJoysticks, nController); | |
int nGameControllers = 0; | |
for (int i = 0; i < nJoysticks - 1; i++) | |
{ | |
printf("Found Controller: [%d] %s\n", i, SDL_GameControllerNameForIndex(i)); | |
if (SDL_IsGameController(i)) | |
{ | |
controller = SDL_GameControllerOpen(i); | |
break; | |
} | |
} | |
int statusCode = rogueMain(); | |
SDL_GameControllerClose(controller); | |
SDL_Quit(); | |
exit(statusCode); | |
} | |
static long lastDelayTime = 0; | |
// Like SDL_Delay, but reduces the delay if time has passed since the last delay | |
static void _delayUpTo(short ms) | |
{ | |
long curTime = SDL_GetTicks(); | |
long timeDiff = curTime - lastDelayTime; | |
ms -= timeDiff; | |
if (ms > 0) | |
{ | |
SDL_Delay(ms); | |
} // else delaying further would go past the time we want to delay until | |
lastDelayTime = SDL_GetTicks(); | |
} | |
static boolean _pauseForMilliseconds(short ms, PauseBehavior behavior) | |
{ | |
updateScreen(); | |
_delayUpTo(ms); | |
if (lastEvent.eventType != EVENT_ERROR && (lastEvent.eventType != MOUSE_ENTERED_CELL || behavior.interuptForMouseMove)) | |
{ | |
return true; // SDL already gave us an interrupting event to process | |
} | |
return pollBrogueEvent(&lastEvent, false) // ask SDL for a new event if one is available | |
&& lastEvent.eventType != EVENT_ERROR // and check if it is interrupting | |
&& (lastEvent.eventType != MOUSE_ENTERED_CELL || behavior.interuptForMouseMove); | |
} | |
static void _nextKeyOrMouseEvent(rogueEvent *returnEvent, boolean textInput, boolean colorsDance) | |
{ | |
updateScreen(); | |
if (lastEvent.eventType != EVENT_ERROR) | |
{ | |
*returnEvent = lastEvent; | |
lastEvent.eventType = EVENT_ERROR; | |
return; | |
} | |
while (true) | |
{ | |
if (colorsDance) | |
{ | |
shuffleTerrainColors(3, true); | |
commitDraws(); | |
} | |
updateScreen(); | |
if (pollBrogueEvent(returnEvent, textInput)) | |
break; | |
_delayUpTo(PAUSE_BETWEEN_EVENT_POLLING); | |
} | |
} | |
/* | |
Returns the index of the sprite representing the given glyph. Sprites <256 are | |
from the text font sheet, 256+ are from the tiles sheet. | |
*/ | |
static int fontIndex(enum displayGlyph glyph) | |
{ | |
// These are the only non-ASCII glyphs which always come from the font sheet | |
if (glyph == G_UP_ARROW) | |
return 0x90; | |
if (glyph == G_DOWN_ARROW) | |
return 0x91; | |
if (glyph < 128) | |
{ | |
// ASCII characters map directly | |
return glyph; | |
} | |
else if (showGraphics == TILES_GRAPHICS || (showGraphics == HYBRID_GRAPHICS && isEnvironmentGlyph(glyph))) | |
{ | |
// Tile glyphs have sprite indices starting at 256 | |
// -2 to disregard the up and down arrow glyphs | |
return glyph + 128 - 2; | |
} | |
else | |
{ | |
unsigned int code = glyphToUnicode(glyph); | |
switch (code) | |
{ | |
case U_MIDDLE_DOT: | |
return 0x80; | |
case U_FOUR_DOTS: | |
return 0x81; | |
case U_DIAMOND: | |
return 0x82; | |
case U_FLIPPED_V: | |
return 0x83; | |
case U_ARIES: | |
return 0x84; | |
case U_ESZETT: | |
return 0xdf; | |
case U_ANKH: | |
return 0x85; | |
case U_MUSIC_NOTE: | |
return 0x86; | |
case U_CIRCLE: | |
return 0x87; | |
case U_LIGHTNING_BOLT: | |
return 0x99; | |
case U_FILLED_CIRCLE: | |
return 0x89; | |
case U_NEUTER: | |
return 0x8a; | |
case U_U_ACUTE: | |
return 0xda; | |
case U_CURRENCY: | |
return 0xa4; | |
case U_UP_ARROW: | |
return 0x90; | |
case U_DOWN_ARROW: | |
return 0x91; | |
case U_LEFT_ARROW: | |
return 0x92; | |
case U_RIGHT_ARROW: | |
return 0x93; | |
case U_OMEGA: | |
return 0x96; | |
case U_CIRCLE_BARS: | |
return 0x8c; | |
case U_FILLED_CIRCLE_BARS: | |
return 0x8d; | |
case U_LEFT_TRIANGLE: | |
return 0x8e; | |
default: | |
brogueAssert(code < 256); | |
return code; | |
} | |
} | |
} | |
static void _plotChar( | |
enum displayGlyph inputChar, | |
short x, short y, | |
short foreRed, short foreGreen, short foreBlue, | |
short backRed, short backGreen, short backBlue) | |
{ | |
updateTile(y, x, fontIndex(inputChar), | |
foreRed, foreGreen, foreBlue, | |
backRed, backGreen, backBlue); | |
} | |
static void _remap(const char *from, const char *to) | |
{ | |
if (nremaps < MAX_REMAPS) | |
{ | |
remapping[nremaps].from = from[0]; | |
remapping[nremaps].to = to[0]; | |
nremaps++; | |
} | |
} | |
/* | |
* Take screenshot in current working directory (ScreenshotN.png) | |
*/ | |
static boolean _takeScreenshot() | |
{ | |
SDL_Surface *screenshot = captureScreen(); | |
if (!screenshot) | |
return false; | |
// choose filename | |
char screenshotFilepath[BROGUE_FILENAME_MAX]; | |
getAvailableFilePath(screenshotFilepath, "Screenshot", SCREENSHOT_SUFFIX); | |
strcat(screenshotFilepath, SCREENSHOT_SUFFIX); | |
// save to PNG | |
IMG_SavePNG(screenshot, screenshotFilepath); | |
SDL_FreeSurface(screenshot); | |
return true; | |
} | |
static enum graphicsModes _setGraphicsMode(enum graphicsModes mode) | |
{ | |
showGraphics = mode; | |
refreshScreen(); | |
updateScreen(); | |
return mode; | |
} | |
struct brogueConsole sdlConsole = { | |
_gameLoop, | |
_pauseForMilliseconds, | |
_nextKeyOrMouseEvent, | |
_plotChar, | |
_remap, | |
_modifierHeld, | |
NULL, | |
_takeScreenshot, | |
_setGraphicsMode}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment