/* SDL2 frontend for Wake to Hell Licensed under CC0, public domain, 2023-2025 Made by blitzdoughnuts */ #include #include #ifdef __EMSCRIPTEN__ #include #endif #include #include #undef main #define WTH_PRINT(x...) printf(x) #include "game.h" // keep in mind, MAIN can still access variables from the game! // SDL2 SETTINGS #define WTHSDL_HZ 48000 // sample rate // for aspect correction #define CAM_VERTOFFSET ((HEIGHT - 270) / 4) // lookup table for font offsets, to offset the character afterwards to the left by this amount static const uint8_t fontOffsets_left[90] = { 21, 12, 3, 11, 7, 14, 22, 20, 20, 4, 4, 21, 1, 20, 11, // 33-47 8, 10, 6, 11, 10, 8, 9, 6, 13, 7, 5, 23, 21, 5, 24, 6, 24, // 48-64 0, 7, 7, 7, 4, 7, 4, 0, 0, 0, 9, 7, 0, 9, 4, 9, 5, 11, 9, 6, 6, 10, 3, 3, 9, 5, // 64-96 (A-Z) 12, 12, 12, 16, 3, 21, // 97-102 14, 16, 13, 16, 14, 15, 12, 11, 23, // 103-122 (a-z) 18, 18, 21, 3, 12, 12, 15, 10, 12, 13, 13, 13, 15, 5, 13, 13, 13 // 123-139 }; // strings here, for both ease of access and also to reduce redundancy in program string lists static const char str_savegamename[] = "WTH_SaveGame.bin"; char *gestures[18] = { GESTURESTR_INVALID, GESTURESTR_BED, GESTURESTR_COMPUTER, GESTURESTR_BADGE, GESTURESTR_MIRROR, GESTURESTR_DONUT, GESTURESTR_KNIFE, GESTURESTR_YOU, GESTURESTR_STOOL, GESTURESTR_RECEPTIONIST, GESTURESTR_OUTDOORS, GESTURESTR_BURNING, GESTURESTR_GASOLINE, GESTURESTR_MAIL, GESTURESTR_COMPUTER2, GESTURESTR_NEWS1, GESTURESTR_NEWS2, GESTURESTR_NEWS3 }; #ifndef WTH_NOSOUND #include #define WTH_MUSCOUNT 3 #define WTH_SFXCOUNT 12 Mix_Music *music[WTH_MUSCOUNT]; Mix_Chunk *sfx[WTH_SFXCOUNT]; #endif SDL_Texture *wintext; SDL_Texture *plrsprites[WTH_PLR_SPRCOUNT * 2]; SDL_Texture *sprites[WTH_SPRCOUNT]; SDL_Rect dspdest_rect; // this is the DESTINATION, aka screen position SDL_Rect fade_rect; // used for fading in/out SDL_Point zeropoint = {0,0}; SDL_Renderer *render; SDL_Window *win; SDL_Event event; uint8_t renderFlags; // flags to tell SDL2 what to draw, modified by signalDraw() void drawSprite(SDL_Texture *sprite, int x, int y) { dspdest_rect = (SDL_Rect){x, y, 0, 0}; SDL_QueryTexture(sprite, NULL, NULL, &dspdest_rect.w, &dspdest_rect.h); SDL_RenderCopy(render, sprite, NULL, &dspdest_rect); }; FILE *DaSave; #ifdef WTH_DEMOS FILE *DaDemo; uint8_t demoStatus; uint8_t demowrite[1]; uint32_t demoPointer; static const char str_wintitle[] = GAMETITLE; // it's only here to cut down redundancies #endif #ifdef WTH_DEBUG uint16_t DEBUG_keys; uint16_t DEBUG_lastkeys; uint8_t DEBUG_objSel; SDL_Texture *DEBUG_sprites[2]; double DEBUG_gameFPS; #endif void drawRepeatingSprite(SDL_Texture *sprite, int x, int y) { int _x = x; dspdest_rect.x = x; dspdest_rect.y = y; SDL_QueryTexture(sprite, NULL, NULL, &dspdest_rect.w, &dspdest_rect.h); while (_x < WIDTH) { if (_x < -dspdest_rect.w) { _x += dspdest_rect.w; dspdest_rect.x = _x; continue; }; SDL_RenderCopy(render, sprite, NULL, &dspdest_rect); _x += dspdest_rect.w; dspdest_rect.x = _x; }; _x = x; while (_x > -dspdest_rect.w) { if (_x > WIDTH) { _x -= dspdest_rect.w; dspdest_rect.x = _x; continue; }; _x -= dspdest_rect.w; SDL_RenderCopy(render, sprite, NULL, &dspdest_rect); dspdest_rect.x = _x; }; }; void drawSpriteSheeted(SDL_Texture *sprite, int x, int y, int frame, int x_sprdist, int y_sprdist, uint8_t flipped) { // supports only purely horizontal sheets if (x < -x_sprdist || x > x_sprdist + WIDTH) return; SDL_Rect destrect = {x, y, x_sprdist, y_sprdist}; dspdest_rect.x = x_sprdist * frame; dspdest_rect.y = 0; // this somehow fixes an issue where the sprite would vertically stretch when moving the cam_ra vertically, but crop off within the sprite's intended bounds. what? dspdest_rect.w = x_sprdist, dspdest_rect.h = y_sprdist, SDL_RenderCopyEx(render, sprite, &dspdest_rect, &destrect, 0, &zeropoint, flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE); }; void drawTextString(const char *stuff, int x, int y, uint8_t color) { // to-do: may need optimizing? switch (color) { case 1: SDL_SetTextureColorMod(sprites[WTH_SPR_FONTMAP], 224, 0, 0); break; /* case 2: SDL_SetTextureColorMod(sprites[5], 0, 224, 21); break; case 3: SDL_SetTextureColorMod(sprites[5], 0, 31, 224); break; case 4: SDL_SetTextureColorMod(sprites[5], 255, 255, 0); break; case 5: SDL_SetTextureColorMod(sprites[5], 0, 255, 255); break; case 6: SDL_SetTextureColorMod(sprites[5], 255, 0, 255); break; case 7: SDL_SetTextureColorMod(sprites[5], 0, 255, 255); break; case 8: SDL_SetTextureColorMod(sprites[5], 255, 255, 0); break; case 9: SDL_SetTextureColorMod(sprites[5], 255, 255, 255); break; case 10: SDL_SetTextureColorMod(sprites[5], 0, 0, 0); break; */ default: SDL_SetTextureColorMod(sprites[WTH_SPR_FONTMAP], 218, 218, 218); break; } int16_t _x = x; for (uint8_t i = 0; i < 255; i++) { if (stuff[i] == '\0') break; // terminator character? then get outta there before stuff gets nasty if (_x < -27 || _x > 27 + WIDTH) return; SDL_Rect destrect = {_x, y, 27, 30}; dspdest_rect.x = 27 * (stuff[i] - 33); dspdest_rect.y = 0; dspdest_rect.w = 27; dspdest_rect.h = 30; SDL_RenderCopy(render, sprites[WTH_SPR_FONTMAP], &dspdest_rect, &destrect); _x += (stuff[i] == 32) ? 16 : 27 - fontOffsets_left[stuff[i] - 33]; }; }; uint8_t found = 0; uint8_t gesture = 0; // keeps track of added gesture objects void signalMisc(uint8_t signal) { switch (signal) { #ifndef WTH_NOSOUND case MISC_PAUSEMUSIC: case MISC_RESUMEMUSIC: case MISC_STOPMUSIC: if (!(options[0] & WTHOPTS_DOSONG)) break; switch (signal) { case MISC_PAUSEMUSIC: Mix_PauseMusic(); break; case MISC_RESUMEMUSIC: Mix_ResumeMusic(); break; case MISC_STOPMUSIC: Mix_HaltMusic(); break; } break; #endif case MISC_GESTURE: for (uint8_t i = 0; i < interacts_count; i++) { if (interacts[i].objID == INTERTYPE_ARTIFACT && interacts[i].x - 30 <= plr.x && interacts[i].x + 30 >= plr.x) { puts(gestures[3 + interacts[i].vars[0]]); found = 1; break; }; if (interacts[i].objID != INTERTYPE_GESTURE) continue; if (interacts[i].x - 30 <= plr.x && interacts[i].x + 30 >= plr.x) { puts(gestures[interacts[i].vars[0]]); found = 1; break; }; }; if (!found) { if (level == ROOM_OUTDOORS) puts(gestures[GESTURE_OUTDOORS]); else puts(gestures[GESTURE_INVALID]); }; break; case MISC_NEWROOM: switch (level) { case ROOM_HOUSE: gesture = addObject(438, GROUNDLEVEL, INTERTYPE_GESTURE); interacts[gesture].vars[0] = GESTURE_COMPUTER; break; case ROOM_OUTDOORS: gesture = addObject(128,GROUNDLEVEL,INTERTYPE_GESTURE); interacts[gesture].vars[0] = GESTURE_MAIL; break; }; break; } }; #define WTH_OPTIONTEXT_X 30 #define WTH_OPTIONTEXT_Y 40 void drawOptions() { // drawRepeatingSprite has no functionality for VERTICAL tiling... fuck it, we ball for (uint16_t i = 0; i < HEIGHT; i += 64) { drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, i); }; drawTextString("Fade", WTH_OPTIONTEXT_X,WTH_OPTIONTEXT_Y, menu.menuselect == 0 ? 1 : 0); drawTextString((options[0] & WTHOPTS_NOFADE) ? str_off : str_on, 320, WTH_OPTIONTEXT_Y, menu.menuselect == 0 ? 1 : 0); drawTextString("Freecam", WTH_OPTIONTEXT_X,WTH_OPTIONTEXT_Y + 32, menu.menuselect == 1 ? 1 : 0); drawTextString((options[0] & WTHOPTS_DEVCAM) ? str_on : str_off, 320, WTH_OPTIONTEXT_Y + 32, menu.menuselect == 1 ? 1 : 0); drawTextString("Music", WTH_OPTIONTEXT_X,WTH_OPTIONTEXT_Y + 64, menu.menuselect == 2 ? 1 : 0); drawTextString((options[0] & WTHOPTS_DOSONG) ? str_on : str_off, 320, WTH_OPTIONTEXT_Y + 64, menu.menuselect == 2 ? 1 : 0); drawTextString(str_exit, 32,HEIGHT - 48, menu.menuselect == 3 ? 1 : 0); }; void signalDraw(uint8_t index) { switch (index) { case DRAW_PLRUPARROW: renderFlags ^= 1; break; case DRAW_PLRDNARROW: renderFlags ^= 2; break; }; }; // inline the simple stuff static inline void signalPlaySFX(uint8_t signal) { #ifndef WTH_NOSOUND Mix_PlayChannel(-1, sfx[signal], 0); #endif }; static inline void signalPlayMUS(uint8_t signal) { #ifndef WTH_NOSOUND if (options[0] & WTHOPTS_DOSONG) Mix_PlayMusic(music[signal], -1); #endif }; void saveGame() { #ifndef WTH_NOOPTIONS DaSave = fopen(str_savegamename,"w"); fwrite(&options, 1, 2, DaSave); fclose(DaSave); #endif }; void loadGame() { #ifndef WTH_NOOPTIONS if (!(DaSave = fopen(str_savegamename,"r"))) { options[0] = DEFAULT_OPTIONS; return; }; fread(&options, 1, 2, DaSave); fclose(DaSave); #else options[0] = DEFAULT_OPTIONS; #endif }; void draw() { switch (GAME_STATE) { case GSTATE_MENU: //SDL_FillRect(winsurf, NULL, 400); switch (menu.menuindex) { case 0: drawSprite(sprites[WTH_SPR_MENU], 0, 0); drawSpriteSheeted(sprites[WTH_SPR_MENUBUTTONS], 47, 147, (menu.menuselect == 0) ? 1 : 0, 99, 23, 0); drawSpriteSheeted(sprites[WTH_SPR_MENUBUTTONS], 47, 170, (menu.menuselect == 1) ? 3 : 2, 99, 23, 0); drawSpriteSheeted(sprites[WTH_SPR_MENUBUTTONS], 47, 193, (menu.menuselect == 2) ? 5 : 4, 99, 23, 0); #ifdef WTH_FANCY drawTextString("Fancy :)", 0, HEIGHT - 48, 0); #endif break; case 1: case MINDEX_XOPTIONS: drawOptions(); break; } drawTextString(VERSION_NUMBER, 0, 0, 0); break; case GSTATE_PLAYING: // draw background switch (level) { case ROOM_TEST: case ROOM_STREETS: drawRepeatingSprite(sprites[WTH_SPR_BG_STREET], -cam_x, -cam_y); break; case ROOM_HOUSE: drawSprite(sprites[WTH_SPR_BG_HOUSE], -456 - cam_x - 75, -cam_y); break; case ROOM_OUTDOORS: drawRepeatingSprite(sprites[WTH_SPR_BG_OUTDOORS], -cam_x / 2, -cam_y); break; case ROOM_HOSPITAL: drawSprite(sprites[WTH_SPR_BG_HOSPITAL], -45 - cam_x, -cam_y); break; case ROOM_H_PATIENTS: drawSprite(sprites[WTH_SPR_BG_HOS_PATIENTS], -30 - cam_x, -cam_y); break; case ROOM_H_HAMIE: drawSprite(sprites[WTH_SPR_BG_HOS_HAMIE], -45 - cam_x, -cam_y); break; case ROOM_H_RICHIE: drawSprite(sprites[WTH_SPR_BG_HOS_RICHIE], -45 - cam_x, -cam_y); break; case ROOM_BAR: drawSprite(sprites[WTH_SPR_BG_BAR], -250 - cam_x, -cam_y); break; }; for (uint8_t i = 0; i < interacts_count; i++) { if (!(interacts[i].flags & INTER_ACTIVE)) continue; switch (interacts[i].objID) { case 255: drawSpriteSheeted(sprites[WTH_SPR_YOU], (interacts[i].x - 75) - cam_x, (interacts[i].y - 100) - cam_y, interacts[i].vars[1], 150, 150, (plr.x < interacts[i].x) ? 1 : 0); break; case INTERTYPE_COAT: drawSpriteSheeted(sprites[WTH_SPR_COATRACK], interacts[i].x - 35 - cam_x, (interacts[i].y - 100) - cam_y, (plr.flags & FLAG_HASCOAT) ? 1 : 0, 70, 100, 0); break; case INTERTYPE_DECOR: drawSprite(sprites[interacts[i].vars[0]], interacts[i].x - cam_x, interacts[i].y - cam_y); break; case INTERTYPE_ARTIFACT: drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], (interacts[i].x - 32) - cam_x, (interacts[i].y - 32) - cam_y, interacts[i].vars[0], 64, 64, 0); break; case INTERTYPE_DOOR: drawSpriteSheeted(sprites[WTH_SPR_DOOR], (interacts[i].x - 75) - cam_x, (interacts[i].y - 100) - cam_y, ((interacts[i].flags & 1 << 2) || interacts[i].vars[1]) ? 1 : 0, 150, 150, 0); break; case INTERTYPE_STAIRS: drawSpriteSheeted(sprites[WTH_SPR_STAIRS], (interacts[i].x - 75) - cam_x, (interacts[i].y - 100) - cam_y, 0, 150, 150, 0); break; case INTERTYPE_BOOK: drawSpriteSheeted(sprites[WTH_SPR_BOOK_HAMIE], (interacts[i].x - 32) - cam_x, (interacts[i].y - 32) - cam_y, ((interacts[i].flags & 1 << 2) || interacts[i].vars[1]) ? 1 : 0, 64, 64, 0); break; #ifdef WTH_DEBUG case INTERTYPE_GESTURE: drawSprite(DEBUG_sprites[0], (interacts[i].x - 75) - cam_x, (interacts[i].y - 100) - cam_y); break; #endif } }; // draw player uint8_t plrFrame = plr.animframe; if (plr.animindex == WTH_PLR_SPOOKED_SPR) { switch (plr.animframe) { case 2: case 3: // stall Lukifer's initial shock for 3 frames plrFrame = 1; break; case 4: case 5: case 6: case 7: // cue turnaround plrFrame -= 3; break; case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: // line boil Lukifer turned around plrFrame = 4 + (plr.animframe & 1); break; case 21: case 22: // Lukifer reacts in unamusement plrFrame -= 16; break; case 23: case 24: case 25: case 26: case 27: case 28: // loop unamusement plrFrame = 7; break; case 29: case 30: // go back to turning right plrFrame -= 21; break; }; }; drawSpriteSheeted(plrsprites[(plr.flags & FLAG_HASCOAT) ? plr.animindex : plr.animindex + WTH_PLR_SPRCOUNT], (plr.x - 75) - cam_x, (plr.y - 100) - cam_y, plrFrame, 150, 150, (plr.flags & FLAG_FLIPPED) ? 1 : 0); if (renderFlags & 1) drawSprite(sprites[WTH_SPR_UPARROW], plr.x - 20 - cam_x, plr.y - 150 - cam_y); if (renderFlags & 2) drawSprite(sprites[WTH_SPR_UPARROW], plr.x - 20 - cam_x, plr.y + 25 - cam_y); #ifdef WTH_DEBUG switch (level) { case ROOM_TEST: drawTextString("Test Room", 0, 0, 0); break; case ROOM_HOUSE: drawTextString("House", 0, 0, 0); break; case ROOM_OUTDOORS: drawTextString("Outside of House", 0, 0, 0); break; case ROOM_STREETS: drawTextString("Endless Sidewalk", 0, 0, 0); break; case ROOM_HOSPITAL: drawTextString("Hospital Lobby", 0, 0, 0); break; case ROOM_H_PATIENTS: drawTextString("Hospital Patient Lobby", 0, 0, 0); break; case ROOM_H_HAMIE: drawTextString("Hamie's Room", 0, 0, 0); break; case ROOM_H_RICHIE: drawTextString("Richie's Room", 0, 0, 0); break; case ROOM_H_DARK: drawTextString("Dark Room", 0, 0, 0); break; case ROOM_YOU: drawTextString("Dark Room?", 0, 0, 0); break; case ROOM_BAR: drawTextString("Bar", 0, 0, 0); break; }; #endif if (fade != 0) { SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(render, 0,0,0, fade); SDL_RenderFillRect(render, NULL); } else SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); break; case GSTATE_PAUSED: //SDL_FillRect(winsurf, NULL, 400); switch (menu.menuindex) { case 0: if (plr.artifacts & 1 << ARTIFACT_BADGE) drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 248, 96, 0, 64, 64, 0); if (plr.artifacts & 1 << ARTIFACT_MIRROR) drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 312, 96, 1, 64, 64, 0); if (plr.artifacts & 1 << ARTIFACT_DONUT) drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 248, 144, 2, 64, 64, 0); if (plr.artifacts & 1 << ARTIFACT_KNIFE) drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 312, 144, 3, 64, 64, 0); if (plr.flags & FLAG_HASCOAT) drawSpriteSheeted(sprites[WTH_SPR_COATRACK], 376, 108, 0, 100, 100, 0); if (GAME_FLAGS & FLAG_HAMIEBOOK) // TODO: Proper sprite for Hamie's book drawTextString("Read Hamie's book", 312, 200, 0); drawTextString("PAUSED",80, 64, 0); drawTextString("Resume", 80, 120, menu.menuselect == 0 ? 1 : 0); drawTextString("Options", 80, 152, menu.menuselect == 1 ? 1 : 0); drawTextString(str_exit, 80, 184, menu.menuselect == 2 ? 1 : 0); break; case 1: drawOptions(); break; } break; case GSTATE_BOOK: drawSpriteSheeted(sprites[WTH_SPR_READ_HAMIE], 0, 0, bookpage & 0x0F, 480, 270, 0); if (fade != 0) { SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(render, 0,0,0, fade); SDL_RenderFillRect(render, NULL); } else SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); break; }; renderFlags = 0; }; uint8_t *keystates; SDL_Joystick *controllerinput; void keys() { #ifdef WTH_DEMOS if (demoStatus != 2) { #endif if (keystates[SDL_SCANCODE_LEFT]) input_keys |= KEY_LEFT; if (keystates[SDL_SCANCODE_RIGHT]) input_keys |= KEY_RIGHT; if (keystates[SDL_SCANCODE_UP]) input_keys |= KEY_UP; if (keystates[SDL_SCANCODE_DOWN]) input_keys |= KEY_DOWN; if (keystates[SDL_SCANCODE_Z]) input_keys |= KEY_GESTURE; if (keystates[SDL_SCANCODE_ESCAPE]) input_keys |= KEY_MENU; #ifdef WTH_DEMOS }; #endif if (keystates[SDL_SCANCODE_A]) xtrakeys |= KEY_LEFT; if (keystates[SDL_SCANCODE_D]) xtrakeys |= KEY_RIGHT; if (keystates[SDL_SCANCODE_W]) xtrakeys |= KEY_UP; if (keystates[SDL_SCANCODE_S]) xtrakeys |= KEY_DOWN; if (keystates[SDL_SCANCODE_LSHIFT]) xtrakeys |= KEY_ATTACK; if (controllerinput) { #ifdef WTH_DEMOS if (demoStatus != 2) { #endif if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_DPAD_LEFT) || SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_LEFTX) < -16383) input_keys |= KEY_LEFT; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_DPAD_RIGHT) || SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_LEFTX) > 16383) input_keys |= KEY_RIGHT; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_DPAD_UP) || SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_LEFTY) < -16383) input_keys |= KEY_UP; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_DPAD_DOWN) || SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_LEFTY) > 16383) input_keys |= KEY_DOWN; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_A)) input_keys |= KEY_GESTURE; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_START)) input_keys |= KEY_MENU; #ifdef WTH_DEMOS }; #endif if (SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_RIGHTX) < -16383) xtrakeys |= KEY_LEFT; if (SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_RIGHTX) > 16383) xtrakeys |= KEY_RIGHT; if (SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_RIGHTY) < -16383) xtrakeys |= KEY_UP; if (SDL_JoystickGetAxis(controllerinput, SDL_CONTROLLER_AXIS_RIGHTY) > 16383) xtrakeys |= KEY_DOWN; if (SDL_JoystickGetButton(controllerinput, SDL_CONTROLLER_BUTTON_X)) xtrakeys |= KEY_ATTACK; } #ifdef WTH_DEBUG int mx, my; int win_width, win_height; SDL_GetMouseState(&mx, &my); SDL_GetWindowSize(win, &win_width, &win_height); if (keystates[SDL_SCANCODE_5]) DEBUG_keys ^= 1; if (keystates[SDL_SCANCODE_1]) DEBUG_keys ^= 1 << 1; if (keystates[SDL_SCANCODE_2]) DEBUG_keys ^= 1 << 2; if (keystates[SDL_SCANCODE_HOME]) DEBUG_keys ^= 1 << 3; if (keystates[SDL_SCANCODE_END]) DEBUG_keys ^= 1 << 4; if (keystates[SDL_SCANCODE_INSERT]) DEBUG_keys ^= 1 << 5; if (keystates[SDL_SCANCODE_PAGEUP]) DEBUG_keys ^= 1 << 6; if (keystates[SDL_SCANCODE_BACKSPACE]) DEBUG_keys ^= 1 << 7; if (keystates[SDL_SCANCODE_TAB]) DEBUG_keys ^= 1 << 8; if (keystates[SDL_SCANCODE_DELETE]) DEBUG_keys ^= 1 << 9; if (keystates[SDL_SCANCODE_PAGEDOWN]) DEBUG_keys ^= 1 << 10; #define DEBUG_pressed(key) ((DEBUG_keys ^ key) && !(DEBUG_lastkeys ^ key)) if (DEBUG_pressed(1)) addObject( (mx - cam_x) / (win_width / WIDTH), (my - cam_y) / (win_height / HEIGHT), INTERTYPE_COAT ); if (DEBUG_pressed(1 << 1)) { level--; LoadInRoom(); }; if (DEBUG_pressed(1 << 2)) { level++; LoadInRoom(); }; if (DEBUG_pressed(1 << 3)) { DEBUG_objSel--; printf("OBJECT SELECTED: %i\n", DEBUG_objSel); }; if (DEBUG_pressed(1 << 4)) { DEBUG_objSel++; printf("OBJECT SELECTED: %i\n", DEBUG_objSel); }; if (DEBUG_pressed(1 << 5)) { interacts[DEBUG_objSel].x -= 16; printf("%i\n", interacts[DEBUG_objSel].x); }; if (DEBUG_pressed(1 << 6)) { interacts[DEBUG_objSel].x += 16; printf("%i\n", interacts[DEBUG_objSel].x); }; if (DEBUG_pressed(1 << 8)) { options[0] ^= WTHOPTS_DEVCAM; }; if (DEBUG_pressed(1 << 9)) { DEBUG_gameFPS /= 2; }; if (DEBUG_pressed(1 << 10)) { DEBUG_gameFPS = GAME_FPS; }; DEBUG_lastkeys = DEBUG_keys; DEBUG_keys = 0; #endif }; void gameLoop() { if (!running) { printf("Exiting game...\n"); #ifndef WTH_NOSOUND for (int i = 0; i < WTH_MUSCOUNT; i++) { Mix_FreeMusic(music[i]); } for (int i = 0; i < WTH_SFXCOUNT; i++) { Mix_FreeChunk(sfx[i]); } #endif for (int i = 0; i < WTH_SPRCOUNT; i++) { SDL_DestroyTexture(sprites[i]); } SDL_DestroyRenderer(render); SDL_DestroyWindow(win); SDL_Quit(); #ifdef __EMSCRIPTEN emscripten_cancel_main_loop(); #endif return; }; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: running = 0; break; } } keys(); #ifdef WTH_DEMOS if (keystates[SDL_SCANCODE_F1] && demoStatus != 2) { if (demoStatus != 1) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, str_wintitle, "Recording demo...", NULL); DaDemo = fopen("WTH_Demo.wthdem", "w"); demoStatus = 1; } else { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, str_wintitle, "Demo recording stopped", NULL); fclose(DaDemo); demoStatus = 0; }; } if (keystates[SDL_SCANCODE_F2] && demoStatus != 1) { if (demoStatus != 2) { DaDemo = fopen("WTH_Demo.wthdem", "r"); if (DaDemo) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, str_wintitle, "Playing back demo...", NULL); demoStatus = 2; }; } else if (demoStatus == 2) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, str_wintitle, "Demo playback stopped", NULL); fclose(DaDemo); demoStatus = 0; }; } switch (demoStatus) { case 1: demowrite[0] = input_keys; fwrite(demowrite, 1, 1, DaDemo); break; case 2: fread(demowrite, 1, 1, DaDemo); input_keys = demowrite[0]; fseek(DaDemo, demoPointer, SEEK_SET); demoPointer++; break; } #endif #if (HEIGHT != 270) cam_y = -CAM_VERTOFFSET; #endif draw(); step(); SDL_RenderPresent(render); SDL_RenderClear(render); #ifdef WTH_DEBUG SDL_Delay((uint32_t)(1.0f / DEBUG_gameFPS * 1000)); #else SDL_Delay((uint32_t)(1.0f / GAME_FPS * 1000)); #endif }; int main(int argc, char *argv[]) { #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__APPLE__) puts("WARNING: You are running Wake to Hell under a malware OS. Please consider switching to a less harmful system."); #endif #define REALGAMETITLE GAMETITLE " " VERSION_NUMBER #ifdef WTH_NOSOUND if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK) != 0) { #else if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | MIX_INIT_MID | SDL_INIT_JOYSTICK) != 0) { #endif puts("SDL2: Cannot initialize!"); return 1; }; win = SDL_CreateWindow(REALGAMETITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); render = SDL_CreateRenderer(win, -1, SDL_RENDERER_PRESENTVSYNC); // parse arguments if (argc > 1) { for (uint8_t i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 'h' && !argv[i][2]) { // HELP printf(REALGAMETITLE " (SDL2)"); puts(" by blitzdoughnuts"); puts("This program is FREE SOFTWARE, licensed under the Creative Commons Zero plus a waiver of remaining rights. You should have gotten licensing information with the packaged game or source repository.\nSee readme.txt for more information."); return 0; }; if (argv[i][0] == '-' && argv[i][1] == 's' && argv[i][2] && !argv[i][3]) { // WINDOW SCALE if (argv[i][2] < '0' || argv[i][2] > '9') { puts("Please give an argument to the -s parameter.\ne.g. -s2"); return 0; }; if (argv[i][2] == '0') { SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP); continue; }; SDL_SetWindowSize(win, WIDTH * (argv[i][2] - '0'), HEIGHT * (argv[i][2] - '0')); SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); }; }; }; #undef REALGAMETITLE SDL_RenderSetLogicalSize(render, WIDTH, HEIGHT); // keep that cwispy pixew wesowutiown UwU SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); if ((SDL_NumJoysticks() > 0)) controllerinput = SDL_JoystickOpen(0); #ifndef WTH_NOSOUND if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 1, 2048) != 0) puts("The game couldn't find a usable audio system. Check your audio devices!"); else { music[MUS_NMARE] = Mix_LoadMUS(MUSF_NMARE); music[MUS_BAR] = Mix_LoadMUS(MUSF_BAR); music[MUS_CRC] = Mix_LoadMUS(MUSF_CRC); sfx[0] = Mix_LoadWAV("sfx/step.wav"); sfx[1] = Mix_LoadWAV("sfx/jump.wav"); sfx[2] = Mix_LoadWAV("sfx/slam.wav"); sfx[3] = Mix_LoadWAV("sfx/coatpickup.wav"); sfx[4] = Mix_LoadWAV("sfx/dooropen.wav"); sfx[5] = Mix_LoadWAV("sfx/doorclose.wav"); sfx[6] = Mix_LoadWAV("sfx/artifact_badge.wav"); sfx[7] = Mix_LoadWAV("sfx/artifact_mirror.wav"); sfx[8] = Mix_LoadWAV("sfx/artifact_donut.wav"); sfx[9] = Mix_LoadWAV("sfx/artifact_knife.wav"); sfx[10] = Mix_LoadWAV("sfx/paperopen.wav"); sfx[11] = Mix_LoadWAV("sfx/paperclose.wav"); }; #endif SDL_SetRenderDrawColor(render, 0, 0x01, 0x90, 255); keystates = SDL_GetKeyboardState(NULL); // this was called every time keys() is ran, but apparently it's only needed to be called ONCE :) // COAT plrsprites[WTH_PLR_IDLE_SPR] = IMG_LoadTexture(render, "sprites/plr_idle.png"); plrsprites[WTH_PLR_WALK_SPR] = IMG_LoadTexture(render, "sprites/plr_walk.png"); plrsprites[WTH_PLR_DOOR_SPR] = IMG_LoadTexture(render, "sprites/plr_enterdoor.png"); plrsprites[WTH_PLR_SLEEP_SPR] = IMG_LoadTexture(render, "sprites/plr_asleep.png"); plrsprites[WTH_PLR_IDLE1_SPR] = IMG_LoadTexture(render, "sprites/plr_idle1.png"); plrsprites[WTH_PLR_UPSTAIR1_SPR] = IMG_LoadTexture(render, "sprites/plr_enterdoor.png"); plrsprites[WTH_PLR_UPSTAIR2_SPR] = IMG_LoadTexture(render, "sprites/plr_upstairs2.png"); plrsprites[WTH_PLR_DNSTAIR1_SPR] = IMG_LoadTexture(render, "sprites/plr_idle1.png"); plrsprites[WTH_PLR_DNSTAIR2_SPR] = IMG_LoadTexture(render, "sprites/plr_walk.png"); plrsprites[WTH_PLR_SPOOKED_SPR] = IMG_LoadTexture(render, "sprites/plr_surprise.png"); // NO COAT plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_IDLE_SPR] = IMG_LoadTexture(render, "sprites/plr_idle_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_WALK_SPR] = IMG_LoadTexture(render, "sprites/plr_walk_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_DOOR_SPR] = IMG_LoadTexture(render, "sprites/plr_enterdoor_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_SLEEP_SPR] = IMG_LoadTexture(render, "sprites/plr_asleep.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_IDLE1_SPR] = IMG_LoadTexture(render, "sprites/plr_idle1_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_UPSTAIR1_SPR] = IMG_LoadTexture(render, "sprites/plr_enterdoor_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_UPSTAIR2_SPR] = IMG_LoadTexture(render, "sprites/plr_upstairs2.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_DNSTAIR1_SPR] = IMG_LoadTexture(render, "sprites/plr_idle1.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_DNSTAIR2_SPR] = IMG_LoadTexture(render, "sprites/plr_walk_coatless.png"); plrsprites[WTH_PLR_SPRCOUNT + WTH_PLR_SPOOKED_SPR] = IMG_LoadTexture(render, "sprites/plr_surprise.png"); sprites[WTH_SPR_MENU] = IMG_LoadTexture(render, "sprites/MENU.png"); sprites[WTH_SPR_FONTMAP] = IMG_LoadTexture(render, "sprites/fontmap.png"); sprites[WTH_SPR_MENUBUTTONS] = IMG_LoadTexture(render, "sprites/MENUBUTTONS.png"); sprites[WTH_SPR_UPARROW] = IMG_LoadTexture(render, "sprites/uparrow.png"); sprites[WTH_SPR_OPTMENU] = IMG_LoadTexture(render, "sprites/OPTIONSMENU.png"); sprites[WTH_SPR_BG_STREET] = IMG_LoadTexture(render, "sprites/bg.png"); sprites[WTH_SPR_BG_HOUSE] = IMG_LoadTexture(render, "sprites/bg_house.png"); sprites[WTH_SPR_BG_OUTDOORS] = IMG_LoadTexture(render, "sprites/bg_outdoors.png"); sprites[WTH_SPR_BG_HOSPITAL] = IMG_LoadTexture(render, "sprites/bg_hospital.png"); sprites[WTH_SPR_BG_HOS_PATIENTS] = IMG_LoadTexture(render, "sprites/bg_hos_patients.png"); sprites[WTH_SPR_BG_HOS_HAMIE] = IMG_LoadTexture(render, "sprites/bg_hos_hamie.png"); sprites[WTH_SPR_BG_HOS_RICHIE] = IMG_LoadTexture(render, "sprites/bg_hos_richie.png"); sprites[WTH_SPR_BG_BAR] = IMG_LoadTexture(render, "sprites/bg_bar.png"); sprites[WTH_SPR_BG_BAROUT] = IMG_LoadTexture(render, "sprites/bg_BARHOUSE.png"); sprites[WTH_SPR_COATRACK] = IMG_LoadTexture(render, "sprites/coatrack.png"); sprites[WTH_SPR_DOOR] = IMG_LoadTexture(render, "sprites/door.png"); sprites[WTH_SPR_STAIRS] = IMG_LoadTexture(render, "sprites/stairs.png"); sprites[WTH_SPR_ARTIFACTS] = IMG_LoadTexture(render, "sprites/artifacts.png"); sprites[WTH_SPR_YOU] = IMG_LoadTexture(render, "sprites/you_idle.png"); sprites[WTH_SPR_DECOR_BED] = IMG_LoadTexture(render, "sprites/bed.png"); sprites[WTH_SPR_DECOR_MAILBOX] = IMG_LoadTexture(render, "sprites/decor_mailbox.png"); sprites[WTH_SPR_DECOR_BARSTOOL] = IMG_LoadTexture(render, "sprites/decor_barstool.png"); sprites[WTH_SPR_DECOR_HATRACK] = IMG_LoadTexture(render, "sprites/decor_hatrack.png"); sprites[WTH_SPR_BOOK_HAMIE] = IMG_LoadTexture(render, "sprites/book.png"); sprites[WTH_SPR_READ_HAMIE] = IMG_LoadTexture(render, "sprites/read_hamie.png"); #ifdef WTH_DEBUG DEBUG_gameFPS = GAME_FPS; DEBUG_sprites[0] = IMG_LoadTexture(render, "sprites/DEBUG_gesture.png"); #endif running = 1; start(); #ifdef __EMSCRIPTEN__ emscripten_set_main_loop(gameLoop, 0, 1); #else while (running) { gameLoop(); }; #endif return 0; };