Add Allegro frontend, add palette and scripts to prepare for embedding

images sucklessly, edit Lukifer's surprise animation, reformat TODO
This commit is contained in:
blitzdoughnuts 2025-03-16 20:40:48 -04:00
parent 7c0e6f9afe
commit 3996facb0a
10 changed files with 621 additions and 48 deletions

Binary file not shown.

114
DOCS/TODO.md Executable file
View file

@ -0,0 +1,114 @@
# Engine
- Figure out how to change speeds based on game FPS accurately, Anarch style
- Use Anarch-style delta time?
- Make the object creation function optionally override existing, non-active objects
- Find a way to embed assets INTO THE GAME!
- I made a method for Mr. Wendigo's Adventure. Maybe I can port that to Wake to Hell.
# SDL2
- Move demos to a mod?
- Figure out where the door SFX came from. They definitely weren't self-made, and while I remember they're CC0, I need to be able to prove it. As far as I know, I recall getting both door sounds from the same audio. All I know is that the audio is potentiall 44100 KHz, as the doorclose.wav sound is not resampled like dooropen.wav is. The earliest instance of these door sounds is June 12th, 2023. Some candidates:
- https://freesound.org/people/babuhr/sounds/513335/ (not it, but sounds akin to dooropen.wav)
- https://freesound.org/people/Pfannkuchn/sounds/342873/ (sounds similar to doorclose.wav, has different pitch)
- https://freesound.org/people/HECKFRICKER/sounds/669374/
- https://freesound.org/people/kyles/sounds/407311/ (has similar doorknob sounds, but too much reverb)
- https://freesound.org/people/SpliceSound/sounds/369888/ (peculiarly similar, not quite it though)a
- https://freesound.org/people/florianreichelt/sounds/451757/ (don't think this is it but DAMN it sounds very akin)
- Make font properly spaced (DONE)
- Remake Lucid Nightmares as a tracker module? It'll sound consistent across many platforms and won't be as expensive as WAV, OGG nor MIDI if on Fluidsynth (TRYING)
- Try using Fluidsynth directly instead of SDL2 Mixer? It may remove some bloat
# Gesturing
- Gesture functionality
- Be able to gesture on decor and gesture objects
- Add actual animations
- Flavor text?
# Stairs
- Stair functionality (DONE)
- Make sprites and animations
- Add a delay between actions, e.g. one for preparing to go up, and one for getting to the top
# Doors
- Door functionality (DONE)
- Make sprites and animations (DONE)
- Door can shut and open for flair (DONE)
- Sideways doors
- Downwards doors:
- Make a sprite that is just the regular door, but mirrored and checkerboarded to give it dithering-like "transparency". Probably also do-able in memory.
# Rooms
- Add room bounds to replace INTETYPE\_MOVEBLOCK?
- Lukifer's house (DONE)
- Idea: Place the knife on a table to the left of the bed, with a TON of blood. May leave speculators speculating :)
- Outdoor area:
- Litter a few details along the walking path, perhaps lore clues?
- Endless streets:
- Add a few buildings that can be reached in 1 or 2 "cycles" of the walk-trigger
- Maybe rid of the step-trigger, simply let the player loop around the map if they hit an edge.
- Hospital entrance:
- Needs seamless transition between ES and HE; preferably have Lukifer teleport to the left or right of the hospital based on his walking direction
- Alternatively, just create the door, the blocks, and the hospital in Lukifer's moving direction (be sure to remove everything else)
- Maybe block off movement to lure the player into the hospital?
- Hospital main lobby:
- Needs a way to translate a 3D area into a 2D sidescroller format: maybe add doors or walkways that change Lukifer's relative orientation?
- The doors should slam behind Lukifer as he walks away, entering for the first time in the session. ONLY activate if facing right, going deeper in the building. May need a special door object.
- Hospital patient rooms
## ES bonus buildings
- Bar:
- Funny idea: leave a photobook of the owner (female) with some interesting images in it [UNDERGOING]
- Therapist's office
# Player:
- Walking, jumping (DONE, jumping is scrapped)
- State system (DONE)
- Sprites and animations
- Maybe an optional system where animation frames can be picked by the frontend to do optimized animations that reuse frames? (WORKING ON IT)
- Properly implement cutscene-ish events
# Books:
- Hamie:
- Include her entrance of the hospital
- Beach photo? :)
- Add some random photographs of random events
- Limetown
# Paths:
- Path 1: Story-Accurate
- Grab the knife at the house
- Coat is not involved
- Go from the house to outdoors, then to the endless streets
- Lukifer keeps walking forth until he reaches the hospital.
- Grab the Lime Badge in the lobby
- Hospital patient rooms
- Grab a doughnut from the "dark room"
- Grab a mirror from Hamie's room
- Head back to the Hospital Lobby; the hospital doors should be open.
- Trying to go through the doors leads to a cutscene where the story outline is played out.
- Lukifer passes out and awakes in front of the hospital. The doors are locked.
- Path 2: Hot Chocolate
- Knife is not involved
- Make sure you have your coat
- Go from the house to outdoors, then to the endless streets
- Head to the Bar
- Look into the bar owner's photobook
- Exit the bar and head straight to the hospital
- The Lime Badge isn't really necessary
- Head to Hamie's patient room; a mug should be resting on the foreground bed where the Mirror would be
- Picking up the mug will make Lukifer pull a stool from in between the two beds and drink from it. The mug acts like the Mirror artifact otherwise
- Move to the dark room after drinking the mug. The doughnut will be missing, leaving only a pedestal.
- Interacting with the pedestal places the empty mug on it. Lukifer retains the Mirror artifact and silently gets the Doughnut.
- Path 1 may be followed regularly
- Path 3: Raw
- DON'T grab the Knife
- Make sure you DON"T have the coat
- Yada yada, go to the Endless Streets
- Visit the therapist's office on the way to the hospital
- At the hospital, grab the Mirror from Hamie's room
- Head to the dark room. The doughnut will be missing.
- Going near the Pedestal will engage a cutscene
- After having a talk with The Motherfucker, exit the dark room.
# Unsorted
- Smooth out the level change from the changeroom trigger object (at least don't jar the camera back to default position)
- Add idle animations for Lukifer
- Gesture ideas:
- Gesturing a stool will make Lukifer sit. Should he have a coat, he'll pull out a drink.
# POST-COMPLETION IDEAS
- Allow for non-16;9 resolutions. The camera will adjust to the internal WIDTH and HEIGHT, the frontend will offset drawing to better fit the resolution. Possible resolutions:
- 360x270 (4:3)
- 270x270 (1:1)
- Split SDL2 into a fancy (adjusts for any resolution, extra details, extend some game features) and simple (only 480x270, less detailed, bare game features) versions, maybe by making a mod?

2
game.h
View file

@ -599,7 +599,7 @@ void step() {
if (plr.flags & FLAG_HALTANIM) plr.flags ^= FLAG_HALTANIM;
};
plr.idleanimtimer++;
if (plr.idleanimtimer >= 400) {
if (plr.idleanimtimer >= 400 * (GAME_FPS / 60)) {
plr.animindex = WTH_PLR_IDLE1_SPR;
plr.animflimit = WTH_PLR_IDLE1_LEN;
if (!(plr.flags & FLAG_HALTANIM)) plr.flags ^= FLAG_HALTANIM;

398
main_allegro.c Executable file
View file

@ -0,0 +1,398 @@
/*
Allegro5 frontend for the game
Licensed under CC0, public domain, 2023-2024
Made by blitzdoughnuts
*/
#include <stdio.h>
#include <stdint.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
#undef main
#include "game.h" // keep in mind, MAIN can still access variables from the game!
#ifndef EDITMODE
#define EDITMODE 0
#endif
// 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_on[] = "ON";
static const char str_off[] = "OFF";
static const char str_exit[] = "Exit";
static const char str_savegamename[] = "WTH_SaveGame.bin";
//Mix_Music *music[3];
//Mix_Chunk *sfx[12];
//SDL_Texture *plrsprites[10];
//SDL_Texture *sprites[20];
//SDL_Rect dspdest_rect; // this is the DESTINATION, aka screen position
//SDL_Rect fade_rect; // used for fading in/out
ALLEGRO_SAMPLE *music[3];
ALLEGRO_SAMPLE *sfx[12];
ALLEGRO_BITMAP *plrsprites[10];
ALLEGRO_BITMAP *sprites[28];
ALLEGRO_DISPLAY *window;
uint8_t running;
void drawSprite(ALLEGRO_BITMAP *sprite, int x, int y) {
al_draw_bitmap(sprite, (float)x, (float)y, 0);
};
FILE *DaSave;
#if WTH_SDL_DEMOSUPPORT == 1
FILE *DaDemo;
uint8_t demoStatus;
uint8_t demowrite[1];
uint32_t demoPointer;
static const char str_wintitle[] = WINTITLE; // it's only here to cut down redundancies
#endif
void drawRepeatingSprite(ALLEGRO_BITMAP *sprite, int x, int y) {
};
void drawSpriteSheeted(ALLEGRO_BITMAP *sprite, int x, int y, int frame, int x_sprdist, int y_sprdist, uint8_t flipped) { // supports only purely horizontal sheets
al_draw_scaled_bitmap(sprite, x_sprdist * frame, 0, x_sprdist, y_sprdist, x, y, x_sprdist, y_sprdist, flipped);
};
void drawTextString(const char *stuff, int x, int y, uint8_t color) {
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;
};
};
void signalMisc(uint8_t signal) {
};
#define WTH_OPTIONTEXT_X 30
#define WTH_OPTIONTEXT_Y 40
void drawOptions() {
// drawRepeatingSprite has no functionality for VERTICAL tiling... fuck it, we ball
drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, 0);
drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, 64);
drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, 128);
drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, 192);
drawRepeatingSprite(sprites[WTH_SPR_OPTMENU], 0, 254);
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("Double Res", WTH_OPTIONTEXT_X,WTH_OPTIONTEXT_Y + 96, menu.menuselect == 3 ? 1 : 0);
drawTextString((options[0] & WTHOPTS_2XSIZE) ? "YES" : "NO", 320, WTH_OPTIONTEXT_Y + 96, menu.menuselect == 3 ? 1 : 0);
drawTextString("Fullscreen", WTH_OPTIONTEXT_X,WTH_OPTIONTEXT_Y + 128, menu.menuselect == 4 ? 1 : 0);
drawTextString((options[0] & WTHOPTS_FULLSC) ? str_on : str_off, 320, WTH_OPTIONTEXT_Y + 128, menu.menuselect == 4 ? 1 : 0);
drawTextString(str_exit, 20,238, menu.menuselect == 5 ? 1 : 0);
};
void signalDraw(uint8_t index) {
switch (index)
{
case DRAW_FADEIN: case DRAW_FADEOUT: case DRAW_HALTFADE:
if (options[0] & WTHOPTS_NOFADE) break;
switch (index)
{
case DRAW_FADEIN:
fade = 255;
fademode = 1;
break;
case DRAW_FADEOUT:
fade = 0;
fademode = 2;
break;
case DRAW_HALTFADE:
fade = 0;
fademode = 0;
break;
};
break;
case DRAW_PLRUPARROW:
drawSprite(sprites[WTH_SPR_UPARROW], plr.x - 20 - cam.x, plr.y - 150 - cam.y);
break;
};
};
// inline the simple stuff
static inline void signalPlaySFX(uint8_t signal) {
#ifndef WTHOPTS_SDL_NOMIXER
//Mix_PlayChannel(-1, sfx[signal], 0);
#endif
};
static inline void signalPlayMUS(uint8_t signal) {
#ifndef WTHOPTS_SDL_NOMIXER
//if (options[0] & WTHOPTS_DOSONG) Mix_PlayMusic(music[signal], -1);
#endif
};
void saveGame() {
DaSave = fopen(str_savegamename,"w");
fwrite(&options, 1, 2, DaSave);
fclose(DaSave);
};
void loadGame() {
if (!(DaSave = fopen(str_savegamename,"r"))) {
options[0] = DEFAULT_OPTIONS;
return;
};
fread(&options, 1, 2, DaSave);
fclose(DaSave);
};
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);
break;
case 1: case MINDEX_XOPTIONS:
drawOptions();
break;
}
drawTextString(VERSION_NUMBER, 0, 0, 0);
break;
case GSTATE_PLAYING:
//SDL_FillRect(winsurf, NULL, 400);
switch (level)
{
case ROOM_TEST: case ROOM_STREETS: case ROOM_H_ENT:
drawRepeatingSprite(sprites[WTH_SPR_BG_STREET], -cam.x, -cam.y);
break;
case ROOM_HOUSE:
drawSprite(sprites[WTH_SPR_BG_HOUSE], -90 - 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;
};
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:
drawSprite(sprites[WTH_SPR_DOOR], (interacts[i].x - 75) - cam.x, (interacts[i].y - 100) - cam.y);
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;
}
};
drawSpriteSheeted(plrsprites[(plr.flags & FLAG_HASCOAT) ? plr.animindex : plr.animindex + 5], (plr.x - 75) - cam.x, (plr.y - 100) - cam.y, plr.animframe, 150, 150, (plr.flags & FLAG_FLIPPED) ? 1 : 0);
#ifdef WTHCOMPILER_DEBUG
switch (level)
{
case 0: drawTextString("Test Room", 0, 0, 0); break;
case 1: drawTextString("House", 0, 0, 0); break;
case 2: drawTextString("Outside of House", 0, 0, 0); break;
case 3: drawTextString("Endless Sidewalk", 0, 0, 0); break;
case 4: drawTextString("Hospital Entrance", 0, 0, 0); break;
case 5: drawTextString("Hospital Lobby", 0, 0, 0); break;
case 11: drawTextString("Bar", 0, 0, 0); break;
};
#endif
al_draw_filled_rectangle(0,0,WIDTH,HEIGHT,al_map_rgba(0,0,0,fade));
break;
case GSTATE_PAUSED:
//SDL_FillRect(winsurf, NULL, 400);
if (plr.artifacts & 1 << ARTIFACT_BADGE) {
drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 0, 0, 0, 64, 64, 0);
};
if (plr.artifacts & 1 << ARTIFACT_MIRROR)
drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 64, 0, 1, 64, 64, 0);
if (plr.artifacts & 1 << ARTIFACT_DONUT)
drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 128, 0, 2, 64, 64, 0);
if (plr.artifacts & 1 << ARTIFACT_KNIFE)
drawSpriteSheeted(sprites[WTH_SPR_ARTIFACTS], 192, 0, 3, 64, 64, 0);
switch (menu.menuindex)
{
case 0:
drawTextString("PAUSED",200, 75, 0);
drawTextString("Resume", 200,120, menu.menuselect == 0 ? 1 : 0);
drawTextString("Options", 200,152, menu.menuselect == 1 ? 1 : 0);
drawTextString(str_exit, 200,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);
break;
};
};
uint8_t *keystates;
void keys() {
};
int main(int argc, char *argv[]) {
al_init();
al_init_image_addon();
al_install_audio();
al_init_acodec_addon();
al_init_primitives_addon();
window = al_create_display(WIDTH, HEIGHT);
al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW);
#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.");
FILE *malwareOSWarning;
fopen(malwareOSWarning, "WARNING.txt");
fprintf(malwareOSWarning, "You are running Wake to Hell under a malware OS. Please consider switching to a less harmful system.");
fclose(malwareOSWarning);
#endif
music[0] = al_load_audio_stream("NMARE.xm", 64, 512);
music[1] = al_load_audio_stream("CRIMSON.it", 64, 512);
music[2] = al_load_audio_stream("SHOPKEEP.mod", 64, 512);
sfx[0] = al_load_sample("sfx/step.wav");
sfx[1] = al_load_sample("sfx/jump.wav");
sfx[2] = al_load_sample("sfx/slam.wav");
sfx[3] = al_load_sample("sfx/coatpickup.wav");
sfx[4] = al_load_sample("sfx/dooropen.wav");
sfx[5] = al_load_sample("sfx/doorclose.wav");
sfx[6] = al_load_sample("sfx/artifact_badge.wav");
sfx[7] = al_load_sample("sfx/artifact_mirror.wav");
sfx[8] = al_load_sample("sfx/artifact_donut.wav");
sfx[9] = al_load_sample("sfx/artifact_knife.wav");
sfx[10] = al_load_sample("sfx/paperopen.wav");
sfx[11] = al_load_sample("sfx/paperclose.wav");
plrsprites[0] = al_load_bitmap("sprites/plr_idle.png"); // COATED
plrsprites[1] = al_load_bitmap("sprites/plr_walk.png");
plrsprites[2] = al_load_bitmap("sprites/plr_enterdoor.png");
plrsprites[3] = al_load_bitmap("sprites/plr_asleep.png");
plrsprites[4] = al_load_bitmap("sprites/plr_idle1.png");
plrsprites[5] = al_load_bitmap("sprites/plr_idle_coatless.png"); // COATLESS
plrsprites[6] = al_load_bitmap("sprites/plr_walk_coatless.png");
plrsprites[7] = al_load_bitmap("sprites/plr_enterdoor_coatless.png");
plrsprites[8] = al_load_bitmap("sprites/plr_asleep.png");
plrsprites[9] = al_load_bitmap("sprites/plr_idle1.png");
sprites[WTH_SPR_MENU] = al_load_bitmap("sprites/MENU.png");
sprites[WTH_SPR_FONTMAP] = al_load_bitmap("sprites/fontmap.png");
sprites[WTH_SPR_MENUBUTTONS] = al_load_bitmap("sprites/MENUBUTTONS.png");
sprites[WTH_SPR_UPARROW] = al_load_bitmap("sprites/uparrow.png");
sprites[WTH_SPR_OPTMENU] = al_load_bitmap("sprites/OPTIONSMENU.png");
sprites[WTH_SPR_BG_STREET] = al_load_bitmap("sprites/bg.png");
sprites[WTH_SPR_BG_HOUSE] = al_load_bitmap("sprites/bg_house.png");
sprites[WTH_SPR_BG_OUTDOORS] = al_load_bitmap("sprites/bg_outdoors.png");
sprites[WTH_SPR_BG_HOSPITAL] = al_load_bitmap("sprites/bg_hospital.png");
sprites[WTH_SPR_COATRACK] = al_load_bitmap("sprites/coatrack.png");
sprites[WTH_SPR_DOOR] = al_load_bitmap("sprites/door.png");
sprites[WTH_SPR_ARTIFACTS] = al_load_bitmap("sprites/artifacts.png");
sprites[WTH_SPR_YOU] = al_load_bitmap("sprites/you_idle.png");
sprites[WTH_SPR_DECOR_BED] = al_load_bitmap("sprites/bed.png");
sprites[WTH_SPR_DECOR_MAILBOX] = al_load_bitmap("sprites/decor_mailbox.png");
sprites[WTH_SPR_DECOR_HATRACK] = al_load_bitmap("sprites/decor_hatrack.png");
sprites[WTH_SPR_BOOK_HAMIE] = al_load_bitmap("sprites/book.png");
sprites[WTH_SPR_READ_HAMIE] = al_load_bitmap("sprites/read_hamie.png");
if (!al_install_keyboard()) {
puts("ALLEGRO: Couldn't install keyboard!");
return 1;
};
int running = 1;
ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
ALLEGRO_EVENT event;
ALLEGRO_KEYBOARD_STATE keyboard;
al_register_event_source(queue, al_get_keyboard_event_source());
// to-do: figure out what the hell is causing keyboard inputs to crash the game
start();
signalDraw(DRAW_CHECK2XSIZE);
signalDraw(DRAW_CHECKFULLSC);
while (running) {
if (!al_is_event_queue_empty(queue)) {
while (al_get_next_event(queue, &event)) {
};
};
#if (HEIGHT != 270)
cam.y = -CAM_VERTOFFSET;
#endif
draw();
al_get_keyboard_state(&keyboard);
if (al_key_down(&keyboard, ALLEGRO_KEY_Z)) input_keys ^= KEY_GESTURE;
if (al_key_down(&keyboard, ALLEGRO_KEY_UP)) input_keys ^= KEY_UP;
if (al_key_down(&keyboard, ALLEGRO_KEY_DOWN)) input_keys ^= KEY_DOWN;
if (al_key_down(&keyboard, ALLEGRO_KEY_LEFT)) input_keys ^= KEY_LEFT;
if (al_key_down(&keyboard, ALLEGRO_KEY_RIGHT)) input_keys ^= KEY_RIGHT;
if (al_key_down(&keyboard, ALLEGRO_KEY_ESCAPE)) input_keys ^= KEY_MENU;
step();
al_flip_display();
}
printf("Exiting game...\n");
return 0;
};

View file

@ -496,25 +496,24 @@ void keys() {
if (keystates[SDL_SCANCODE_LSHIFT]) xtrakeys |= KEY_ATTACK;
if (controllerinput) {
printf("Registering controller input...\n");
#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;
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;
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
@ -576,30 +575,6 @@ void keys() {
DEBUG_gameFPS = GAME_FPS;
};
if (DEBUG_pressed(1 << 7)) {
puts("== DEBUG PRINT==\n");
printf("Game state: %i\n", GAME_STATE);
printf("Current room: %i\n", level);
printf("\n");
printf("Player pos: (%i, %i)\n", plr.x, plr.y);
puts("Player has: ");
if (plr.artifacts & ARTIFACT_BADGE) puts("-- BADGE");
if (plr.artifacts & ARTIFACT_MIRROR) puts("-- MIRROR");
if (plr.artifacts & ARTIFACT_KNIFE) puts("-- KNIFE");
if (plr.artifacts & ARTIFACT_DONUT) puts("-- DONUT");
if (plr.flags & FLAG_HASCOAT) puts("-- COAT");
printf("\n");
printf("OBJ count: %i\n", interacts_count);
for (uint8_t i = 0; i < interacts_count; i++) {
if (!(interacts[i].flags & INTER_ACTIVE)) puts("OBJECT IS NOT ACTIVE!");
printf("Object %i:\nID %i\nFlags %b\n", i, interacts[i].objID, interacts[i].flags);
};
puts("== DEBUG PRINT END ==");
};
DEBUG_lastkeys = DEBUG_keys;
DEBUG_keys = 0;
#endif

5
palette.h Normal file
View file

@ -0,0 +1,5 @@
uint16_t palette565[48] = {
0,6368,67,226,256,8320,6464,6150,4258,12710,21130,27469,33808,40147,46518,57051,
29192,24836,43203,57344,18884,29185,50081,58176,19013,27457,52708,59104,17060,21505,36512,40704,
23435,2817,13670,1794,17292,2791,3567,1819,21197,2350,8756,252,12616,12301,24725,51228,
};

15
scripts/makeSprites.sh Normal file
View file

@ -0,0 +1,15 @@
#!/bin/sh
# Helper script to automatically convert .bmp files to
# C arrays for embedding sucklessly
if [ ! -f G2C ]; then
gcc spr2code.c -O3 -lSDL2 -o G2C
fi
rm ../sprites.h
for i in ../spr/*.bmp; do
./G2C $i -n `basename $i .bmp` >> ../sprites.h
printf '\n' >> ../sprites.h
done

54
scripts/spr2code.c Normal file
View file

@ -0,0 +1,54 @@
// Reads .bmp images and pushes them into
// a uint16_t C array in paletted format
// NEEDS SDL2
#include <SDL2/SDL.h>
#include "../palette.h"
void main(int argc, char *argv[]) {
puts("// AUTOGENERATED BY I2C\n");
char arrayName[30] = "myCoolSprite";
SDL_Surface *img;
if (argc > 1) {
uint8_t openedImage = 0;
for (uint8_t i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] == 'h' && !argv[i][2]) {
printf("usage: %s [-h] -[n NAME] level\n", argv[0]);
continue;
};
if (argv[i][0] == '-' && argv[i][1] == 'n' && !argv[i][2]) {
i++;
for (uint8_t ii = 0; ii < 16; ii++) arrayName[ii] = argv[i][ii];
continue;
};
if (!openedImage) {
img = SDL_LoadBMP(argv[i]);
if (img) openedImage = 1;
};
};
if (!openedImage) return;
};
// make ABSOLUTELY SURE the loaded .bmp is RGB565 by converting it
SDL_Surface *spr = SDL_ConvertSurfaceFormat(img, SDL_PIXELFORMAT_RGB565, 0);
SDL_FreeSurface(img);
printf("#define %s_WIDTH %i\n", arrayName, spr->w);
printf("#define %s_HEIGHT %i\n", arrayName, spr->h);
printf("uint8_t %s_SPR[%i] = {\n", arrayName, spr->w * spr->h);
uint16_t *px = (uint16_t*) spr->pixels;
uint8_t color = 0;
for (uint32_t i = 0; i < spr->w * spr->h; i++) {
// look for a corresponding palette color to assign
for (uint8_t ii = 0; ii < 64; ii++) {
if (palette565[ii] == px[i]) {
color = ii;
break;
};
};
printf("%i,", color);
color = 0;
if (i % 16 == 15) printf("\n");
};
puts("};");
_END:
SDL_FreeSurface(spr);
};

View file

@ -1,11 +1,21 @@
// Settings file for Wake to Hell, separate from in-game options.
// See constants.h for macros and stuff
// See the main.c files for settings exclusive to those frontends
/*
Settings file for Wake to Hell, separate from in-game options.
See constants.h for macros and stuff
See the main.c files for settings exclusive to those frontends
*/
// Default settings for the game to fall back to. Also applies when
// the options menu is inaccessible.
/*
Default settings for the game to fall back to. Also applies when
the options menu is inaccessible.
*/
#define DEFAULT_OPTIONS (WTHOPTS_DOSONG)
/*
Suckless mode; disables file IO and packs most assets into the
executable. WORK IN PROGRESS!
*/
#define WTH_SUCKLESS 1
#ifndef GAME_FPS
#define GAME_FPS 60
#endif
@ -26,14 +36,16 @@
// starting room for WTH_DEBUG
#define DEBUG_STARTROOM ROOM_TEST
/* If defined, find an empty index among the interactibles
instead of blindly trusting the interactible count.
Helps when dynamically "destroying" interactibles in
gameplay */
/*
If defined, find an empty index among the interactibles
instead of blindly trusting the interactible count.
Helps when dynamically "destroying" interactibles in
gameplay
*/
//#define WTH_LOOPOBJS
#define WTH_DEBUG // Enable debugging options that show variables and other details
#define WTH_ARTIFACTS 0x0F // Set the artifacts Lukifer starts with. If not defined, defaults to 8
//#define WTH_ARTIFACTS 0x0F // Set the artifacts Lukifer starts with. If not defined, defaults to 8
//#define WTH_NOOPTIONS // Disable the Options menu and use the DEFAULT_OPTIONS macro
//#define WTH_DEMOS // Enable demo recording on frontends that support it
//#define WTH_NOSOUND // Disable audio on frontends that use it

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB