├── res ├── .DS_Store ├── gbat2.bmp ├── ship2.bmp ├── bootTvTex.png ├── iconTex.png └── spsacegame.bmp ├── data └── sounds │ └── cruise.mp3 ├── .gitignore ├── src ├── music.h ├── switch │ ├── music.c │ ├── platform.h │ ├── platform.c │ ├── paddata.h │ ├── switch_paddata.c │ ├── switch_draw.c │ └── font.h ├── platform.h ├── images.h ├── draw.h ├── wiiu │ ├── memory.h │ ├── platform.c │ ├── memory.c │ ├── wiiu_draw.c │ └── music.c ├── space.h ├── program.h ├── draw.c ├── program.c ├── images.c └── space.c ├── .github └── workflows │ └── main.yml ├── license.txt ├── README.md ├── Making_of.md ├── Makefile └── Makefile.switch /res/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/.DS_Store -------------------------------------------------------------------------------- /res/gbat2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/gbat2.bmp -------------------------------------------------------------------------------- /res/ship2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/ship2.bmp -------------------------------------------------------------------------------- /res/bootTvTex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/bootTvTex.png -------------------------------------------------------------------------------- /res/iconTex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/iconTex.png -------------------------------------------------------------------------------- /res/spsacegame.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/res/spsacegame.bmp -------------------------------------------------------------------------------- /data/sounds/cruise.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vgmoose/wiiu-space/HEAD/data/sounds/cruise.mp3 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.DS_Store 3 | .vscode 4 | *.elf 5 | *.rpx 6 | *.wuhb 7 | wiiu-space.* 8 | *.nacp 9 | *.nro 10 | *.nso 11 | *.orig -------------------------------------------------------------------------------- /src/music.h: -------------------------------------------------------------------------------- 1 | #ifndef MUSIC_H 2 | #define MUSIC_H 3 | 4 | void initMusicPlayer(char* filePath); 5 | void playMusic(); 6 | void updateMusic(); 7 | void stopMusic(); 8 | 9 | #endif /* MUSIC_H */ -------------------------------------------------------------------------------- /src/switch/music.c: -------------------------------------------------------------------------------- 1 | #include "../music.h" 2 | 3 | void initMusicPlayer(char* filePath) { 4 | 5 | } 6 | 7 | void playMusic() { 8 | 9 | } 10 | 11 | void updateMusic() { 12 | } 13 | 14 | void stopMusic() { 15 | 16 | } -------------------------------------------------------------------------------- /src/switch/platform.h: -------------------------------------------------------------------------------- 1 | // These files implement WiiU-style wrappers for reading controller/touch data on the Switch 2 | #ifndef SWITCH_PLATFORM_H 3 | #define SWITCH_PLATFORM_H 4 | unsigned int OSGetTime(); 5 | 6 | #define __os_snprintf snprintf 7 | #define OSFatal printf 8 | #endif -------------------------------------------------------------------------------- /src/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_H 2 | #define PLATFORM_H 3 | #include 4 | #include "program.h" 5 | #if !defined(__WIIU__) 6 | #include "switch/platform.h" 7 | #endif 8 | void platformInit(); 9 | bool AppRunning(struct SpaceGlobals* mySpaceGlobals); 10 | 11 | #endif /* PLATFORM_H */ -------------------------------------------------------------------------------- /src/switch/platform.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "platform.h" 4 | 5 | unsigned int OSGetTime() 6 | { 7 | return svcGetSystemTick(); 8 | } 9 | void platformInit() { 10 | 11 | } 12 | bool AppRunning(struct SpaceGlobals* mySpaceGlobals) 13 | { 14 | // TODO: allow exiting 15 | return true; 16 | } -------------------------------------------------------------------------------- /src/images.h: -------------------------------------------------------------------------------- 1 | extern unsigned const char title_palette[40][3]; 2 | extern signed const char compressed_title[3061]; 3 | extern signed const char compressed_ship[511]; 4 | extern unsigned const char ship_palette[15][3]; 5 | extern signed const char compressed_enemy[206]; 6 | extern unsigned const char enemy_palette[10][3]; 7 | extern signed const char compressed_boss[740]; 8 | extern unsigned const char boss_palette[40][3]; 9 | extern signed const char compressed_boss2[662]; 10 | extern unsigned const char boss2_palette[40][3]; 11 | extern const signed char compressed_ship2[452]; 12 | extern unsigned const char ship2_palette[6][3]; -------------------------------------------------------------------------------- /src/draw.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAW_H 2 | #define DRAW_H 3 | #include "program.h" 4 | 5 | //Function declarations for my graphics library 6 | void flipBuffers(); 7 | void fillScreen(char r, char g, char b, char a); 8 | void drawString(int x, int y, char * string); 9 | void drawStringTv(int x, int y, char * string); 10 | void drawRect(int x1, int y1, int x2, int y2, char r, char g, char b, char a); 11 | void drawPixel(int x, int y, char r, char g, char b); 12 | 13 | void drawPixels(struct Pixel pixels[200]); 14 | void drawBitmap(int ox, int oy, int width, int height, unsigned char input[][width], unsigned const char palette[][3]); 15 | void fillRect(int ox, int oy, int width, int height, int r, int g, int b); 16 | 17 | void putAPixel(int x, int y, int r, int g, int b); 18 | void screenInit(); 19 | void screenDeinit(); 20 | 21 | #endif /* DRAW_H */ -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build wiiu/switch apps 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - switch-rewrite 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | all: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | include: 18 | - platform: wiiu 19 | ext: wuhb 20 | - platform: switch 21 | ext: nro 22 | container: 23 | image: ghcr.io/fortheusers/sealeo:evo 24 | steps: 25 | - uses: actions/checkout@main 26 | with: 27 | submodules: recursive 28 | - if: matrix.platform == 'wiiu' 29 | name: Build wiiu app 30 | run: make 31 | - if: matrix.platform == 'switch' 32 | name: Build switch app 33 | run: make -f Makefile.switch 34 | - uses: actions/upload-artifact@v4 35 | with: 36 | name: wiiu-space.${{ matrix.ext }} 37 | path: /__w/wiiu-space/wiiu-space/wiiu-space.${{ matrix.ext }} -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 VGMoose 2 | 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/wiiu/memory.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2015 Dimok 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 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. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | ****************************************************************************/ 17 | #ifndef __MEMORY_H_ 18 | #define __MEMORY_H_ 19 | 20 | #include 21 | 22 | void memoryInitialize(void); 23 | void memoryRelease(void); 24 | 25 | void * MEM2_alloc(unsigned int size, unsigned int align); 26 | void MEM2_free(void *ptr); 27 | 28 | void * MEM1_alloc(unsigned int size, unsigned int align); 29 | void MEM1_free(void *ptr); 30 | 31 | void * MEMBucket_alloc(unsigned int size, unsigned int align); 32 | void MEMBucket_free(void *ptr); 33 | 34 | #endif // __MEMORY_H_ 35 | -------------------------------------------------------------------------------- /src/switch/paddata.h: -------------------------------------------------------------------------------- 1 | // These files implement WiiU-style wrappers for reading controller/touch data on the Switch 2 | #ifndef SWITCH_PADDATA_H 3 | #define SWITCH_PADDATA_H 4 | 5 | #define BIT(x) (1 << (x)) 6 | 7 | #define PAD_BUTTON_LEFT BIT(12) 8 | #define PAD_BUTTON_RIGHT BIT(14) 9 | #define PAD_BUTTON_UP BIT(13) 10 | #define PAD_BUTTON_DOWN BIT(15) 11 | 12 | #define PAD_BUTTON_MINUS BIT(11) 13 | #define PAD_BUTTON_PLUS BIT(10) 14 | 15 | #define PAD_BUTTON_A BIT(0) 16 | #define PAD_BUTTON_B BIT(2) 17 | 18 | // define these as the same as the wiiu constants 19 | // TODO: move wiiu to use these instead 20 | #define VPAD_BUTTON_LEFT PAD_BUTTON_LEFT 21 | #define VPAD_BUTTON_RIGHT PAD_BUTTON_RIGHT 22 | #define VPAD_BUTTON_UP PAD_BUTTON_UP 23 | #define VPAD_BUTTON_DOWN PAD_BUTTON_DOWN 24 | 25 | #define VPAD_BUTTON_MINUS PAD_BUTTON_MINUS 26 | #define VPAD_BUTTON_PLUS PAD_BUTTON_PLUS 27 | 28 | #define VPAD_BUTTON_A PAD_BUTTON_A 29 | #define VPAD_BUTTON_B PAD_BUTTON_B 30 | 31 | typedef struct Vec2D { 32 | float x; 33 | float y; 34 | } Vec2D; 35 | 36 | typedef struct PADData { 37 | int btns_h; 38 | 39 | Vec2D leftStick; 40 | Vec2D rightStick; 41 | 42 | int isTouched; 43 | Vec2D touchData; 44 | } PADData; 45 | 46 | void PADInit(); 47 | void PADDestroy(); 48 | void PADRead(struct PADData* data); 49 | 50 | typedef PADData VPADStatus; 51 | typedef Vec2D VPADVec2D; 52 | 53 | // wiiu wrappers 54 | void VPADRead(int chan, struct PADData *data, int num, int *error); 55 | 56 | #endif -------------------------------------------------------------------------------- /src/switch/switch_paddata.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "paddata.h" 4 | 5 | PadState pad; 6 | 7 | void PADInit() 8 | { 9 | padConfigureInput(1, HidNpadStyleSet_NpadStandard); 10 | 11 | padInitializeDefault(&pad); 12 | 13 | // init touch screen 14 | hidInitializeTouchScreen(); 15 | 16 | } 17 | 18 | void PADDestroy() 19 | { 20 | 21 | } 22 | 23 | void VPADRead(int chan, struct PADData *data, int num, int *error) { 24 | PADRead(data); 25 | } 26 | 27 | void PADRead(struct PADData* data) 28 | { 29 | // reset buttons 30 | data->btns_h = 0b00000000; 31 | 32 | data->leftStick = (Vec2D){0, 0}; 33 | data->rightStick = (Vec2D){0, 0}; 34 | 35 | padUpdate(&pad); 36 | 37 | // update pushed buttons 38 | // data->btns_d = padGetButtonsDown(&pad); 39 | data->btns_h = padGetButtons(&pad); 40 | 41 | // update sticks 42 | HidAnalogStickState analog_stick_l = padGetStickPos(&pad, 0); 43 | HidAnalogStickState analog_stick_r = padGetStickPos(&pad, 1); 44 | data->leftStick = (Vec2D){analog_stick_l.x, analog_stick_l.y}; 45 | data->rightStick = (Vec2D){analog_stick_r.x, analog_stick_r.y}; 46 | 47 | // reset touched flag 48 | data->isTouched = 0; 49 | 50 | HidTouchScreenState state={0}; 51 | int largest_touch = 0; 52 | if (hidGetTouchScreenStates(&state, 1)) { 53 | for(s32 i=0; i largest_touch) 58 | { 59 | largest_touch = curTouch; 60 | data->isTouched = 1; // mark as touched 61 | data->touchData.x = state.touches[i].x; 62 | data->touchData.y = state.touches[i].y; 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Space Game 2 | Space game is a graphical shooter game on the Wii U! This is a homebrew application from 2016. To view a more recent PC port of it, see [this repo](https://github.com/vgmoose/space-game). 3 | 4 | ![Logo](http://vgmoose.com/posts/24261201%20-%20[release]%20Space%20Game!%20(for%20Wii%20U).post/title.png) 5 | 6 | ### Credits and License 7 | This program is licensed under [the MIT license](https://opensource.org/licenses/MIT), which grants anyone permission to do pretty much whatever they want as long as the copyright notice stays intact.* 8 | - Programmed by [VGMoose](https://github.com/vgmoose), with features and bugfixes by [CreeperMario](https://github.com/CreeperMario), [brienj](https://github.com/xhp-creations), [Compucat](https://github.com/compucat) 9 | - Original codebase based on [libwiiu pong](https://github.com/wiiudev/libwiiu/tree/master/osscreenexamples/pong) by [Relys](https://github.com/Relys) 10 | - Music is [\~\*cruise\*\~](https://t-tb.bandcamp.com/track/cruise) by [(T-T)b](https://t-tb.bandcamp.com/)* 11 | - Space ship sprite by [Gungriffon Geona](http://shmups.system11.org/viewtopic.php?p=421436&sid=c7c9dc0b51eb40aa10bd77f724f45bb1#p421436) 12 | - Logo font by [Iconian Fonts](http://www.dafont.com/ozda.font) 13 | - OSScreen-similar font by [M+ Fonts](http://mplus-fonts.osdn.jp/about-en2.html) 14 | - libwiiu/library: [MarioNumber1](https://github.com/MarioNumber1), [NWPlayer123](https://github.com/NWPlayer123), [dimok](https://github.com/dimok789), [Maschell](https://github.com/Maschell), [GaryOderNichts](https://github.com/GaryOderNichts), [QuarkTheAwesome](QuarkTheAwesome) 15 | 16 | *The song [\~\*cruise\*\~](https://t-tb.bandcamp.com/track/cruise) is available under [CC BY-NC-ND](https://ptesquad.bandcamp.com/album/pizza-planet-ep), and is excluded from the MIT licensing. 17 | 18 | ![In game](http://vgmoose.com/posts/24261201%20-%20[release]%20Space%20Game!%20(for%20Wii%20U).post/gameplay.png) 19 | 20 | ### Techniques and Info 21 | 22 | Since it was originally designed to be executed via the .mp4 exploit in 5.5.x, there were several challenges that were imposed on its development in terms of efficiency and storage. The workarounds to these constraints are detailed in Making_of.md -------------------------------------------------------------------------------- /src/space.h: -------------------------------------------------------------------------------- 1 | #ifndef SPACE_H 2 | #define SPACE_H 3 | 4 | #include "program.h" 5 | #include "images.h" 6 | #include "draw.h" 7 | 8 | //Function declarations for space functions. 9 | void renderShip(struct SpaceGlobals *mySpaceGlobals); 10 | void renderInitialPlayers(struct SpaceGlobals *mySpaceGlobals); 11 | void renderReset(struct SpaceGlobals *mySpaceGlobals); 12 | void reset(struct SpaceGlobals *mySpaceGlobals); 13 | void resetRenderFlags(struct SpaceGlobals *mySpaceGlobals); 14 | void render(struct SpaceGlobals *mySpaceGlobals); 15 | void p1Move(struct SpaceGlobals *mySpaceGlobals); 16 | void renderTexts(struct SpaceGlobals *mySpaceGlobals); 17 | void initStars(struct SpaceGlobals *mySpaceGlobals); 18 | void handleCollisions(struct SpaceGlobals * mySpaceGlobals); 19 | void displayTitle(struct SpaceGlobals * mySpaceGlobals); 20 | void doMenuAction(struct SpaceGlobals *mySpaceGlobals); 21 | void drawMenuCursor(struct SpaceGlobals *mySpaceGlobals); 22 | void moveBullets(struct SpaceGlobals *mySpaceGlobals); 23 | void renderStars(struct SpaceGlobals *mySpaceGlobals); 24 | void decompress_sprite(int arraysize, int width, int height, const signed char* input, void *targ, char transIndex); 25 | void renderTexts(struct SpaceGlobals *mySpaceGlobals); 26 | void render(struct SpaceGlobals *mySpaceGlobals); 27 | void blackout(); 28 | void totallyRefreshState(struct SpaceGlobals *mySpaceGlobals); 29 | void p1Shoot(struct SpaceGlobals * mySpaceGlobals); 30 | void displayPause(struct SpaceGlobals * mySpaceGlobals); 31 | void makeRotationMatrix(float angle, int width, void *orig, void *targ, int transIndex); 32 | void doPasswordMenuAction(struct SpaceGlobals * mySpaceGlobals); 33 | void displayPasswordScreen(struct SpaceGlobals * mySpaceGlobals); 34 | void checkPause(struct SpaceGlobals * mySpaceGlobals); 35 | void addNewEnemies(struct SpaceGlobals * mySpaceGlobals); 36 | void tryPassword(struct SpaceGlobals * mySpaceGlobals); 37 | void initGameState(struct SpaceGlobals * mySpaceGlobals); 38 | void displayGameOver(struct SpaceGlobals * mySpaceGlobals); 39 | void handleExplosions(struct SpaceGlobals * mySpaceGlobals); 40 | void makeScaleMatrix(int frame, int width, void *orig, void *targ, int transIndex); 41 | void drawControllerSelectScreen(struct SpaceGlobals *mySpaceGlobals); 42 | 43 | #endif /* SPACE_H */ 44 | -------------------------------------------------------------------------------- /src/wiiu/platform.c: -------------------------------------------------------------------------------- 1 | #include "../platform.h" 2 | #include "../program.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../draw.h" 17 | 18 | 19 | void SaveCallback() 20 | { 21 | OSSavesDone_ReadyToRelease(); // Required 22 | } 23 | 24 | void platformInit() 25 | { 26 | WHBLogCafeInit(); 27 | WHBLogUdpInit(); 28 | 29 | OSDynLoad_Module avm_handle = 0; 30 | OSDynLoad_Acquire("avm.rpl", &avm_handle); 31 | bool(*AVMSetTVScale)(int width, int height); 32 | OSDynLoad_FindExport(avm_handle, 0, "AVMSetTVScale", (void **)&AVMSetTVScale); 33 | AVMSetTVScale(854, 480); // Not working, hope to find a solution 34 | 35 | OSScreenInit(); 36 | ProcUIInit(&SaveCallback); 37 | } 38 | 39 | bool initialized = false; 40 | bool isAppRunning = true; 41 | 42 | bool AppRunning(struct SpaceGlobals* mySpaceGlobals) 43 | { 44 | if(!OSIsMainCore()) 45 | { 46 | ProcUISubProcessMessages(true); 47 | } 48 | else 49 | { 50 | ProcUIStatus status = ProcUIProcessMessages(true); 51 | 52 | if(status == PROCUI_STATUS_EXITING) 53 | { 54 | // Being closed, deinit things and prepare to exit 55 | isAppRunning = false; 56 | 57 | if(initialized) 58 | { 59 | initialized = false; 60 | screenDeinit(); 61 | } 62 | ProcUIShutdown(); 63 | } 64 | else if(status == PROCUI_STATUS_RELEASE_FOREGROUND) 65 | { 66 | // Free up MEM1 to next foreground app, etc. 67 | initialized = false; 68 | 69 | screenDeinit(); 70 | ProcUIDrawDoneRelease(); 71 | } 72 | else if(status == PROCUI_STATUS_IN_FOREGROUND) 73 | { 74 | // Reallocate MEM1, reinit screen, etc. 75 | if(!initialized) 76 | { 77 | initialized = true; 78 | screenInit(); 79 | 80 | // redraw the screen upon resume 81 | mySpaceGlobals->invalid = 1; 82 | } 83 | } 84 | } 85 | 86 | return isAppRunning; 87 | } 88 | -------------------------------------------------------------------------------- /src/program.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_H 2 | #define PROGRAM_H 3 | 4 | #ifdef __WIIU__ 5 | #include 6 | #include 7 | #else 8 | #include "switch/paddata.h" 9 | #include 10 | #endif 11 | 12 | struct Bullet { 13 | int x; 14 | int y; 15 | float m_x; 16 | float m_y; 17 | int active; 18 | }; 19 | 20 | struct Enemy { 21 | float angle; 22 | struct Bullet position; 23 | unsigned char rotated_sprite[23][23]; 24 | }; 25 | 26 | struct Pixel { 27 | int x; 28 | int y; 29 | int r; 30 | int g; 31 | int b; 32 | }; 33 | 34 | //Struct for global variables for pong 35 | struct SpaceGlobals{ 36 | //Flag for restarting the entire game. 37 | int restart; 38 | 39 | //Gameplay boundry 40 | unsigned int frame; 41 | 42 | unsigned int seed; 43 | 44 | unsigned char rotated_ship[36][36]; 45 | unsigned char orig_ship[36][36]; 46 | const unsigned char (*curPalette)[3]; 47 | unsigned char enemy[23][23]; 48 | unsigned char title[100][200]; 49 | 50 | int passwordList[100]; 51 | int playerExplodeFrame; 52 | 53 | //Globals for player1 location and movement dx/dy 54 | float p1X; 55 | float p1Y; 56 | float angle; 57 | 58 | int touched; 59 | int touchX; 60 | int touchY; 61 | int titleScreenRefresh; 62 | 63 | //Game engine globals 64 | uint32_t button; 65 | VPADVec2D lstick; 66 | VPADVec2D rstick; 67 | 68 | // only 20 bullets can be onscreen at a time 69 | struct Bullet bullets[20]; 70 | 71 | // the locations of the 200 random stars 72 | struct Pixel stars[200]; 73 | 74 | // the location of enemies 75 | struct Enemy enemies[100]; 76 | 77 | int renderResetFlag; 78 | int invalid; 79 | int transIndex; 80 | 81 | // bonuses 82 | int playerChoice; 83 | int dontKeepTrackOfScore; 84 | int noEnemies; 85 | int enemiesSeekPlayer; 86 | 87 | int state; // 1 is title screen, 2 is gameplay, 3 is password, 4 is about 88 | int lives; 89 | int score; 90 | int level; 91 | 92 | int menuChoice; 93 | int passwordEntered; 94 | int allowInput; 95 | 96 | int displayHowToPlay; 97 | int firstShotFired; 98 | 99 | }; 100 | 101 | extern void* screenBuffer; 102 | 103 | #endif /* PROGRAM_H */ -------------------------------------------------------------------------------- /src/draw.c: -------------------------------------------------------------------------------- 1 | #include "draw.h" 2 | #include "space.h" 3 | #include "program.h" 4 | 5 | // draw black rect all at once 6 | void fillRect(int ox, int oy, int width, int height, int r, int g, int b) 7 | { 8 | 9 | int rx; 10 | for (rx=0; rx Index color. I extracted the palettes manually by using a hex editor. I've provided the three bitmaps that I used in this repo, although the actual image files are not used by the game. There are other ways to create bitmaps like this (I believe older mspaint supports it) 21 | -------------------------------------------------------------------------------- /src/switch/switch_draw.c: -------------------------------------------------------------------------------- 1 | #include "font.h" 2 | #include "../draw.h" 3 | #include 4 | 5 | #define FB_WIDTH 1920 6 | #define FB_HEIGHT 1080 7 | 8 | 9 | Framebuffer fb; 10 | u32 stride; 11 | 12 | bool bufferOpen = false; 13 | 14 | void screenInit() 15 | { 16 | NWindow* win = nwindowGetDefault(); 17 | 18 | // Create a linear double-buffered framebuffer 19 | framebufferCreate(&fb, win, FB_WIDTH, FB_HEIGHT, PIXEL_FORMAT_RGBA_8888, 2); 20 | framebufferMakeLinear(&fb); 21 | 22 | //Clear both framebuffers. 23 | for (int ii = 0; ii < 2; ii++) 24 | { 25 | fillScreen(0,0,0,0); 26 | flipBuffers(); 27 | } 28 | } 29 | 30 | void screenDeinit() 31 | { 32 | for(int ii = 0; ii < 2; ii++) 33 | { 34 | fillScreen(0,0,0,0); 35 | flipBuffers(); 36 | } 37 | 38 | framebufferClose(&fb); 39 | } 40 | 41 | void flipBuffers() 42 | { 43 | if (bufferOpen) { 44 | framebufferEnd(&fb); 45 | bufferOpen = false; 46 | } else { 47 | // Retrieve the framebuffer 48 | u32* framebuf = (u32*) framebufferBegin(&fb, &stride); 49 | bufferOpen = true; 50 | } 51 | } 52 | 53 | /** 54 | This is the main function that does the grunt work of drawing to both screens. It takes in the 55 | Services structure that is constructed in program.c, which contains the pointer to the function 56 | that is responsible for putting a pixel on the screen. By doing it this way, the OSScreenPutPixelEx function pointer is only 57 | looked up once, at the program initialization, which makes successive calls to this pixel caller quicker. 58 | **/ 59 | void putAPixel(int x, int y, int r, int g, int b) 60 | { 61 | uint32_t num = (r << 24) | (g << 16) | (b << 8) | 0; 62 | x *= 2; 63 | y *= 2; 64 | 65 | int ax, ay; 66 | for (ay=0; ay<2; ay++) 67 | for (ax=0; ax<2; ax++) { 68 | u32 pos = (y+ay) * stride / sizeof(u32) + (x+ax); 69 | // if (pos < FB_WIDTH * FB_HEIGHT) 70 | ((u32*)fb.buf)[pos] = num; 71 | } 72 | } 73 | 74 | void drawString(int xi, int yi, char * string) 75 | { 76 | // on Switch, we only use the TV screen 77 | drawStringTv(xi, yi, string); 78 | } 79 | 80 | void drawStringTv(int xi, int yi, char * string) 81 | { 82 | // for every character in the string, if it's within range, render it at the current position 83 | // and move over 8 characters 84 | 85 | xi *= 6.25; 86 | yi *= 13; 87 | 88 | char next = -1; 89 | int i = 0; 90 | while (next != '\0') 91 | { 92 | next = string[i++]; 93 | 94 | // actually draw this char pixel by pixel, if it's within range 95 | if (next >= 0 && next < 128) 96 | { 97 | char* bitmap = font[next]; 98 | int x, y; 99 | for (x=0; x < 8; x++) { 100 | for (y=0; y < 8; y++) { 101 | if (bitmap[x] & 1 << y) 102 | putAPixel(xi+y+i*8, yi+x, 0xff, 0xff, 0xff); 103 | } 104 | // printf("\n"); 105 | } 106 | } 107 | } 108 | } 109 | 110 | void fillScreen(char r,char g,char b,char a) 111 | { 112 | uint32_t num = (r << 24) | (g << 16) | (b << 8) | a; 113 | 114 | // TODO: clear screen 115 | // OSScreenClearBufferEx(0, num); 116 | // OSScreenClearBufferEx(1, num); 117 | } -------------------------------------------------------------------------------- /src/wiiu/memory.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2015 Dimok 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 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. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | ****************************************************************************/ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "memory.h" 23 | 24 | #define MEMORY_ARENA_1 0 25 | #define MEMORY_ARENA_2 1 26 | #define MEMORY_ARENA_3 2 27 | #define MEMORY_ARENA_4 3 28 | #define MEMORY_ARENA_5 4 29 | #define MEMORY_ARENA_6 5 30 | #define MEMORY_ARENA_7 6 31 | #define MEMORY_ARENA_8 7 32 | #define MEMORY_ARENA_FG_BUCKET 8 33 | 34 | static void *mem1_heap; 35 | static void *bucket_heap; 36 | 37 | void memoryInitialize(void) 38 | { 39 | void *mem1_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_1); 40 | unsigned int mem1_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(mem1_heap_handle, 4); 41 | void *mem1_memory = MEMAllocFromFrmHeapEx(mem1_heap_handle, mem1_allocatable_size, 4); 42 | if(mem1_memory) 43 | mem1_heap = MEMCreateExpHeapEx(mem1_memory, mem1_allocatable_size, 0); 44 | 45 | void *bucket_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET); 46 | unsigned int bucket_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(bucket_heap_handle, 4); 47 | void *bucket_memory = MEMAllocFromFrmHeapEx(bucket_heap_handle, bucket_allocatable_size, 4); 48 | if(bucket_memory) 49 | bucket_heap = MEMCreateExpHeapEx(bucket_memory, bucket_allocatable_size, 0); 50 | } 51 | 52 | void memoryRelease(void) 53 | { 54 | MEMDestroyExpHeap(mem1_heap); 55 | MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_1), 3); 56 | mem1_heap = NULL; 57 | 58 | MEMDestroyExpHeap(bucket_heap); 59 | MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET), 3); 60 | bucket_heap = NULL; 61 | } 62 | 63 | //!------------------------------------------------------------------------------------------- 64 | //! some wrappers 65 | //!------------------------------------------------------------------------------------------- 66 | void * MEM2_alloc(unsigned int size, unsigned int align) 67 | { 68 | return memalign(align, size); 69 | } 70 | 71 | void MEM2_free(void *ptr) 72 | { 73 | free(ptr); 74 | } 75 | 76 | void * MEM1_alloc(unsigned int size, unsigned int align) 77 | { 78 | if (align < 4) 79 | align = 4; 80 | return MEMAllocFromExpHeapEx(mem1_heap, size, align); 81 | } 82 | 83 | void MEM1_free(void *ptr) 84 | { 85 | MEMFreeToExpHeap(mem1_heap, ptr); 86 | } 87 | 88 | void * MEMBucket_alloc(unsigned int size, unsigned int align) 89 | { 90 | if (align < 4) 91 | align = 4; 92 | return MEMAllocFromExpHeapEx(bucket_heap, size, align); 93 | } 94 | 95 | void MEMBucket_free(void *ptr) 96 | { 97 | MEMFreeToExpHeap(bucket_heap, ptr); 98 | } 99 | -------------------------------------------------------------------------------- /src/wiiu/wiiu_draw.c: -------------------------------------------------------------------------------- 1 | #include "../draw.h" 2 | #include "memory.h" 3 | 4 | #include 5 | #include 6 | 7 | void screenInit() 8 | { 9 | //Grab the buffer size for each screen (TV and gamepad) 10 | int buf0_size = OSScreenGetBufferSizeEx(0); 11 | int buf1_size = OSScreenGetBufferSizeEx(1); 12 | 13 | //Set the buffer area. 14 | screenBuffer = MEM1_alloc(buf0_size + buf1_size, 0x100); 15 | 16 | OSScreenSetBufferEx(0, screenBuffer); 17 | OSScreenSetBufferEx(1, (screenBuffer + buf0_size)); 18 | 19 | OSScreenEnableEx(0, 1); 20 | OSScreenEnableEx(1, 1); 21 | 22 | //Clear both framebuffers. 23 | for (int ii = 0; ii < 2; ii++) 24 | { 25 | fillScreen(0,0,0,0); 26 | flipBuffers(); 27 | } 28 | } 29 | 30 | void screenDeinit() 31 | { 32 | for(int ii = 0; ii < 2; ii++) 33 | { 34 | fillScreen(0,0,0,0); 35 | flipBuffers(); 36 | } 37 | 38 | MEM1_free(screenBuffer); 39 | } 40 | 41 | void flipBuffers() 42 | { 43 | //Grab the buffer size for each screen (TV and gamepad) 44 | int buf0_size = OSScreenGetBufferSizeEx(0); 45 | int buf1_size = OSScreenGetBufferSizeEx(1); 46 | 47 | //Flush the cache 48 | DCFlushRange((void *)screenBuffer + buf0_size, buf1_size); 49 | DCFlushRange((void *)screenBuffer, buf0_size); 50 | 51 | //Flip the buffer 52 | OSScreenFlipBuffersEx(0); 53 | OSScreenFlipBuffersEx(1); 54 | } 55 | 56 | /** 57 | This is the main function that does the grunt work of drawing to both screens. It takes in the 58 | Services structure that is constructed in program.c, which contains the pointer to the function 59 | that is responsible for putting a pixel on the screen. By doing it this way, the OSScreenPutPixelEx function pointer is only 60 | looked up once, at the program initialization, which makes successive calls to this pixel caller quicker. 61 | **/ 62 | void putAPixel(int x, int y, int r, int g, int b) 63 | { 64 | uint32_t num = (r << 24) | (g << 16) | (b << 8) | 0; 65 | x *= 2; 66 | y *= 2; 67 | 68 | int ax, ay, az; 69 | for (ax=0; ax<2; ax++) 70 | for (ay=0; ay<2; ay++) 71 | for (az=0; az<2; az++) 72 | if (ax) { // uncomment for fullscreen on TV, text on the TV will have to be moved though 73 | OSScreenPutPixelEx(ax, x + ay, y + az, num); 74 | } // uncomment for fullscreen on TV, text on the TV will have to be moved though 75 | else { // uncomment for fullscreen on TV, text on the TV will have to be moved though 76 | int a; // uncomment for fullscreen on TV, text on the TV will have to be moved though 77 | for (a = 0; a < 2; a++) { // uncomment for fullscreen on TV, text on the TV will have to be moved though 78 | int x1 = ( ( (x + ay) * 3 ) / 2 ) + a; // uncomment for fullscreen on TV, text on the TV will have to be moved though 79 | int y1 = ( ( (y + az) * 3 ) / 2 ) + a; // uncomment for fullscreen on TV, text on the TV will have to be moved though 80 | int x2 = ( ( (x + ay) * 3 ) / 2 ) + ( 1 - a ); // uncomment for fullscreen on TV, text on the TV will have to be moved though 81 | int y2 = ( ( (y + az) * 3 ) / 2 ) + a; // uncomment for fullscreen on TV, text on the TV will have to be moved though 82 | OSScreenPutPixelEx( 0, x1, y1, num ); // uncomment for fullscreen on TV, text on the TV will have to be moved though 83 | OSScreenPutPixelEx( 0, x2, y2, num ); // uncomment for fullscreen on TV, text on the TV will have to be moved though 84 | } // uncomment for fullscreen on TV, text on the TV will have to be moved though 85 | OSScreenPutPixelEx( 1, x, y, num ); // uncomment for fullscreen on TV, text on the TV will have to be moved though 86 | } // uncomment for fullscreen on TV, text on the TV will have to be moved though 87 | } 88 | 89 | 90 | void drawString(int x, int y, char * string) 91 | { 92 | //OSScreenPutFontEx(0, x, y, string); 93 | OSScreenPutFontEx(1, x, y, string); 94 | } 95 | 96 | void drawStringTv(int x, int y, char * string) 97 | { 98 | OSScreenPutFontEx(0, x, y, string); 99 | } 100 | 101 | void fillScreen(char r,char g,char b,char a) 102 | { 103 | uint32_t num = (r << 24) | (g << 16) | (b << 8) | a; 104 | 105 | OSScreenClearBufferEx(0, num); 106 | OSScreenClearBufferEx(1, num); 107 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # default this environment variable 2 | DEVKITPRO ?= /opt/devkitpro 3 | DEVKITPPC ?= $(DEVKITPRO)/devkitPPC 4 | WUT_ROOT ?= $(DEVKITPRO)/wut 5 | export DEVKITPRO 6 | export DEVKITPPC 7 | export WUT_ROOT 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITPRO)/wut/share/wut_rules 11 | 12 | export APP_NAME ?= Space Game 13 | export APP_AUTHOR ?= vgmoose 14 | export APP_VERSION ?= 2.0 15 | 16 | export APP_TV_SPLASH := $(PWD)/res/bootTvTex.png 17 | export APP_DRC_SPLASH := $(PWD)/res/bootTvTex.png 18 | export APP_ICON := $(PWD)/res/iconTex.png 19 | export APP_CONTENT := $(PWD)/data 20 | 21 | TARGET := $(notdir $(CURDIR)) 22 | BUILD := build 23 | SOURCES := src src/wiiu 24 | INCLUDES := include 25 | 26 | #------------------------------------------------------------------------------- 27 | # options for code generation 28 | #------------------------------------------------------------------------------- 29 | CFLAGS := -Wall -O2 -std=c11 \ 30 | -ffast-math \ 31 | $(MACHDEP) 32 | 33 | CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -DMUSIC 34 | 35 | CXXFLAGS := $(CFLAGS) 36 | 37 | ASFLAGS := -g $(MACHDEP) 38 | LDFLAGS := -g $(MACHDEP) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) 39 | 40 | LIBS := -lwut -lmpg123 -lm 41 | 42 | #------------------------------------------------------------------------------- 43 | # list of directories containing libraries, this must be the top level 44 | # containing include and lib 45 | #------------------------------------------------------------------------------- 46 | LIBDIRS := $(PORTLIBS) $(WUT_ROOT) 47 | 48 | 49 | #------------------------------------------------------------------------------- 50 | # no real need to edit anything past this point unless you need to add additional 51 | # rules for different file extensions 52 | #------------------------------------------------------------------------------- 53 | ifneq ($(BUILD),$(notdir $(CURDIR))) 54 | #------------------------------------------------------------------------------- 55 | 56 | export OUTPUT := $(CURDIR)/$(TARGET) 57 | export TOPDIR := $(CURDIR) 58 | 59 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 60 | export DEPSDIR := $(CURDIR)/$(BUILD) 61 | 62 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 63 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 64 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 65 | 66 | #------------------------------------------------------------------------------- 67 | # use CXX for linking C++ projects, CC for standard C 68 | #------------------------------------------------------------------------------- 69 | ifeq ($(strip $(CPPFILES)),) 70 | #------------------------------------------------------------------------------- 71 | export LD := $(CC) 72 | #------------------------------------------------------------------------------- 73 | else 74 | #------------------------------------------------------------------------------- 75 | export LD := $(CXX) 76 | #------------------------------------------------------------------------------- 77 | endif 78 | #------------------------------------------------------------------------------- 79 | 80 | export SRCFILES := $(CPPFILES) $(CFILES) $(SFILES) 81 | export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 82 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 83 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 84 | -I$(CURDIR)/$(BUILD) 85 | 86 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 87 | 88 | .PHONY: $(BUILD) clean all 89 | 90 | #------------------------------------------------------------------------------- 91 | all: $(BUILD) 92 | 93 | $(BUILD): $(SRCFILES) 94 | @[ -d $@ ] || mkdir -p $@ 95 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 96 | 97 | #------------------------------------------------------------------------------- 98 | clean: 99 | @echo clean ... 100 | @rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf 101 | 102 | #------------------------------------------------------------------------------- 103 | else 104 | .PHONY: all 105 | 106 | DEPENDS := $(OFILES:.o=.d) 107 | 108 | #------------------------------------------------------------------------------- 109 | # main targets 110 | #------------------------------------------------------------------------------- 111 | all : $(OUTPUT).wuhb 112 | 113 | $(OUTPUT).wuhb : $(OUTPUT).rpx 114 | $(OUTPUT).rpx : $(OUTPUT).elf 115 | $(OUTPUT).elf : $(OFILES) 116 | 117 | -include $(DEPENDS) 118 | 119 | #------------------------------------------------------------------------------- 120 | endif 121 | #------------------------------------------------------------------------------- 122 | -------------------------------------------------------------------------------- /src/program.c: -------------------------------------------------------------------------------- 1 | #ifdef __WIIU__ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #endif 15 | 16 | #include "program.h" 17 | #include "platform.h" 18 | #include "draw.h" 19 | #include "images.h" 20 | #include "space.h" 21 | #include 22 | #include 23 | #include 24 | #include "music.h" 25 | 26 | void* screenBuffer; 27 | 28 | char log_buf[0x400]; 29 | 30 | struct SpaceGlobals mySpaceGlobals; 31 | 32 | void cleanSlate() 33 | { 34 | // clear both buffers 35 | int ii; 36 | for(ii=0;ii<2;ii++) 37 | { 38 | fillScreen(0,0,0,0); 39 | flipBuffers(); 40 | } 41 | } 42 | 43 | int main(int argc, char **argv) 44 | { 45 | platformInit(); 46 | 47 | /****************************> Globals <****************************/ 48 | //struct SpaceGlobals mySpaceGlobals; 49 | //Flag for restarting the entire game. 50 | mySpaceGlobals.restart = 1; 51 | 52 | // initial state is title screen 53 | mySpaceGlobals.state = 1; 54 | mySpaceGlobals.titleScreenRefresh = 1; 55 | 56 | //Flags for render states 57 | mySpaceGlobals.renderResetFlag = 0; 58 | mySpaceGlobals.menuChoice = 0; // 0 is play, 1 is password 59 | 60 | // setup the password list 61 | int x; 62 | for (x=0; x<100; x++) 63 | mySpaceGlobals.passwordList[x] = (int)(rand()*100000); 64 | 65 | mySpaceGlobals.seed = OSGetTime(); 66 | 67 | /****************************> VPAD Loop <****************************/ 68 | int error; 69 | VPADStatus vpad_data; 70 | 71 | // decompress compressed things into their arrays, final argument is the transparent color in their palette 72 | decompress_sprite(3061, 200, 100, compressed_title, mySpaceGlobals.title, 39); 73 | decompress_sprite(511, 36, 36, compressed_ship, mySpaceGlobals.orig_ship, 14); 74 | decompress_sprite(206, 23, 23, compressed_enemy, mySpaceGlobals.enemy, 9); 75 | 76 | // setup palette and transparent index 77 | mySpaceGlobals.curPalette = ship_palette; 78 | mySpaceGlobals.transIndex = 14; 79 | 80 | // initialize starfield for this game 81 | initStars(&mySpaceGlobals); 82 | 83 | mySpaceGlobals.invalid = 1; 84 | 85 | initMusicPlayer("fs:/vol/content/sounds/cruise.mp3"); 86 | playMusic(); 87 | while (AppRunning(&mySpaceGlobals)) 88 | { 89 | updateMusic(); // TODO: use return value 90 | 91 | VPADRead(0, &vpad_data, 1, &error); 92 | 93 | mySpaceGlobals.rstick = vpad_data.rightStick; 94 | mySpaceGlobals.lstick = vpad_data.leftStick; 95 | 96 | //Get the status of the gamepad 97 | #if defined(__WIIU__) 98 | // TODO: move out to a wiiu_paddata.c file, and use PAD instead of VPAD 99 | mySpaceGlobals.button = vpad_data.hold; 100 | 101 | mySpaceGlobals.touched = vpad_data.tpNormal.touched; 102 | if (mySpaceGlobals.touched == 1) 103 | { 104 | mySpaceGlobals.touchX = ((vpad_data.tpNormal.x / 9) - 11); 105 | mySpaceGlobals.touchY = ((3930 - vpad_data.tpNormal.y) / 16); 106 | } 107 | #else 108 | mySpaceGlobals.button = vpad_data.btns_h; 109 | 110 | mySpaceGlobals.touched = vpad_data.isTouched; 111 | if (mySpaceGlobals.touched == 1) 112 | { 113 | mySpaceGlobals.touchX = vpad_data.touchData.x; 114 | mySpaceGlobals.touchY = vpad_data.touchData.y; 115 | } 116 | #endif 117 | 118 | if (mySpaceGlobals.restart == 1) 119 | { 120 | reset(&mySpaceGlobals); 121 | mySpaceGlobals.restart = 0; 122 | } 123 | 124 | if (mySpaceGlobals.state == 1) // title screen 125 | { 126 | displayTitle(&mySpaceGlobals); 127 | doMenuAction(&mySpaceGlobals); 128 | } 129 | else if (mySpaceGlobals.state == 2) // password screen 130 | { 131 | displayPasswordScreen(&mySpaceGlobals); 132 | doPasswordMenuAction(&mySpaceGlobals); 133 | } 134 | else if (mySpaceGlobals.state == 3) // pause screen 135 | { 136 | displayPause(&mySpaceGlobals); 137 | doMenuAction(&mySpaceGlobals); 138 | } 139 | else if (mySpaceGlobals.state == 4) // game over screen 140 | { 141 | displayGameOver(&mySpaceGlobals); 142 | doMenuAction(&mySpaceGlobals); 143 | } 144 | else // game play 145 | { 146 | //Update location of player1 and 2 paddles 147 | p1Move(&mySpaceGlobals); 148 | 149 | // perform any shooting 150 | p1Shoot(&mySpaceGlobals); 151 | 152 | // handle any collisions 153 | handleCollisions(&mySpaceGlobals); 154 | 155 | // do explosions 156 | handleExplosions(&mySpaceGlobals); 157 | 158 | // if we're out of lives, break 159 | if (mySpaceGlobals.lives <= 0 && mySpaceGlobals.state == 4) 160 | continue; 161 | 162 | // add any new enemies 163 | addNewEnemies(&mySpaceGlobals); 164 | 165 | //Render the scene 166 | render(&mySpaceGlobals); 167 | 168 | // check for pausing 169 | checkPause(&mySpaceGlobals); 170 | } 171 | 172 | } 173 | 174 | stopMusic(); 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /src/wiiu/music.c: -------------------------------------------------------------------------------- 1 | #include "../music.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | // based off immaterial's Music.cpp: https://github.com/glastonbridge/immaterial-wiiu-demo/blob/952a683ae05e676ea839c90a5178653616b325b1/sound/Music.cpp 21 | // and the SDL2 port's wiiu_audio.cpp: https://github.com/GaryOderNichts/SDL/blob/wiiu-sdl2-2.26/src/audio/wiiu/SDL_wiiuaudio.c 22 | 23 | typedef struct { 24 | mpg123_handle *mh; 25 | unsigned char *buffer; 26 | size_t buffer_size; 27 | int16_t *bufferLeft; 28 | int16_t *bufferRight; 29 | AXVoice *voiceLeft; 30 | AXVoice *voiceRight; 31 | AXVoiceOffsets bufferInfo; 32 | int channels; 33 | long rate; 34 | 35 | int16_t *songData; // fully decoded interleaved PCM data 36 | } MusicPlayer; 37 | 38 | MusicPlayer player; 39 | 40 | void initMusicPlayer(char* filePath) { 41 | int err; 42 | 43 | WHBLogPrint("Initializing music player..."); 44 | 45 | AXInitParams init = {AX_INIT_RENDERER_48KHZ, 0, 0}; 46 | AXInitWithParams(&init); 47 | 48 | mpg123_init(); 49 | player.mh = mpg123_new(NULL, &err); 50 | player.buffer_size = mpg123_outblock(player.mh); 51 | player.buffer = (unsigned char*) malloc(player.buffer_size * sizeof(unsigned char)); 52 | 53 | // open the path and read it all into memory 54 | FILE *fp = fopen(filePath, "rb"); 55 | if (!fp) { 56 | WHBLogPrintf("Failed to open file %s", filePath); 57 | return; 58 | } 59 | fseek(fp, 0, SEEK_END); 60 | long fileSize = ftell(fp); 61 | fseek(fp, 0, SEEK_SET); 62 | 63 | unsigned char* dataBuffer = (unsigned char*)malloc(fileSize); 64 | size_t bytesRead = fread(dataBuffer, 1, fileSize, fp); 65 | fclose(fp); 66 | 67 | // give the data buffer to mpg123 as a feed 68 | mpg123_open_feed(player.mh); 69 | mpg123_feed(player.mh, dataBuffer, bytesRead); 70 | free(dataBuffer); 71 | 72 | mpg123_getformat(player.mh, &player.rate, &player.channels, &err); 73 | 74 | // we need enoughn space for the song, which is interleaved left/right audio (assuming 2 channels) 75 | size_t capacity = mpg123_length(player.mh) * player.channels; 76 | 77 | size_t totalSamples = 0; 78 | player.songData = malloc(capacity * sizeof(int16_t)); 79 | 80 | // read audio data from our memory buffer into the mp3 player buffer 81 | size_t done; 82 | while (mpg123_read(player.mh, player.buffer, player.buffer_size, &done) == MPG123_OK && done > 0) { 83 | size_t numSamples = done / sizeof(int16_t); 84 | memcpy(player.songData + totalSamples, player.buffer, done); 85 | totalSamples += numSamples; 86 | } 87 | 88 | size_t totalFrames = totalSamples / 2; 89 | player.bufferLeft = malloc(totalFrames * sizeof(int16_t)); 90 | player.bufferRight = malloc(totalFrames * sizeof(int16_t)); 91 | 92 | for (size_t i = 0; i < totalFrames; i++) { 93 | player.bufferLeft[i] = player.songData[i * 2]; 94 | player.bufferRight[i] = player.songData[i * 2 + 1]; 95 | } 96 | DCFlushRange(player.bufferLeft, totalFrames * sizeof(int16_t)); 97 | DCFlushRange(player.bufferRight, totalFrames * sizeof(int16_t)); 98 | 99 | player.voiceLeft = AXAcquireVoice(31, NULL, NULL); 100 | player.voiceRight = AXAcquireVoice(31, NULL, NULL); 101 | 102 | // setup voice buffers with the full de-interleaved data 103 | player.bufferInfo.dataType = AX_VOICE_FORMAT_LPCM16; 104 | player.bufferInfo.loopingEnabled = AX_VOICE_LOOP_ENABLED; 105 | player.bufferInfo.loopOffset = 0; // TODO: make music loop smoothly with this 106 | player.bufferInfo.endOffset = totalFrames; 107 | player.bufferInfo.currentOffset = 0; 108 | 109 | player.bufferInfo.data = player.bufferLeft; 110 | AXSetVoiceOffsets(player.voiceLeft, &player.bufferInfo); 111 | player.bufferInfo.data = player.bufferRight; 112 | AXSetVoiceOffsets(player.voiceRight, &player.bufferInfo); 113 | 114 | // playback rates are adjusted from the mp3 (44khz) to the device's 48khz 115 | AXSetVoiceSrcType(player.voiceLeft, AX_VOICE_SRC_TYPE_LINEAR); 116 | AXSetVoiceSrcRatio(player.voiceLeft, (float)player.rate / 48000.0f); 117 | AXSetVoiceSrcType(player.voiceRight, AX_VOICE_SRC_TYPE_LINEAR); 118 | AXSetVoiceSrcRatio(player.voiceRight, (float)player.rate / 48000.0f); 119 | 120 | AXVoiceVeData volumeInfo = {0x8000, 0}; // second arg unused 121 | AXSetVoiceVe(player.voiceLeft, &volumeInfo); 122 | AXSetVoiceVe(player.voiceRight, &volumeInfo); 123 | 124 | // setting the volume for both left/right channels and the tv/gamepad 125 | // https://github.com/glastonbridge/immaterial-wiiu-demo/blob/952a683ae05e676ea839c90a5178653616b325b1/sound/Music.cpp#L111 126 | // first sets 0'th index to full volume, then undoes that and sets the 1'th index to full volume (for right channel?) 127 | // and then the other 4 for TV are ignored 128 | AXVoiceDeviceMixData deviceVolumeData[6]; 129 | memset(&deviceVolumeData, 0, sizeof(deviceVolumeData)); 130 | deviceVolumeData[0].bus[0].volume = 0x8000; // left to full, for both 131 | AXSetVoiceDeviceMix(player.voiceLeft, AX_DEVICE_TYPE_TV, 0, deviceVolumeData); 132 | AXSetVoiceDeviceMix(player.voiceLeft, AX_DEVICE_TYPE_DRC, 0, deviceVolumeData); 133 | deviceVolumeData[0].bus[0].volume = 0; 134 | deviceVolumeData[1].bus[0].volume = 0x8000; // left to 0, right to full 135 | AXSetVoiceDeviceMix(player.voiceRight, AX_DEVICE_TYPE_TV, 0, deviceVolumeData); 136 | AXSetVoiceDeviceMix(player.voiceRight, AX_DEVICE_TYPE_DRC, 0, deviceVolumeData); 137 | 138 | WHBLogPrint("Music player initialized"); 139 | } 140 | 141 | void playMusic() { 142 | // start our two channels, each of which has been connected to the song and tv/gamepad 143 | AXSetVoiceCurrentOffset(player.voiceLeft, 0); 144 | AXSetVoiceState(player.voiceLeft, AX_VOICE_STATE_PLAYING); 145 | AXSetVoiceCurrentOffset(player.voiceRight, 0); 146 | AXSetVoiceState(player.voiceRight, AX_VOICE_STATE_PLAYING); 147 | } 148 | 149 | void updateMusic() { 150 | // Could be used to advance the music each frame 151 | } 152 | 153 | void stopMusic() { 154 | AXSetVoiceState(player.voiceLeft, AX_VOICE_STATE_STOPPED); 155 | AXSetVoiceState(player.voiceRight, AX_VOICE_STATE_STOPPED); 156 | 157 | free(player.buffer); 158 | free(player.bufferLeft); 159 | free(player.bufferRight); 160 | free(player.songData); 161 | AXFreeVoice(player.voiceLeft); 162 | AXFreeVoice(player.voiceRight); 163 | mpg123_close(player.mh); 164 | mpg123_delete(player.mh); 165 | mpg123_exit(); 166 | AXQuit(); 167 | } -------------------------------------------------------------------------------- /Makefile.switch: -------------------------------------------------------------------------------- 1 | # default this environment variable 2 | DEVKITPRO ?= /opt/devkitpro 3 | DEVKITA64 ?= $(DEVKITPRO)/devkitA64 4 | 5 | export DEVKITPRO 6 | export DEVKITA64 7 | 8 | TOPDIR ?= $(CURDIR) 9 | include $(DEVKITPRO)/libnx/switch_rules 10 | 11 | export APP_TITLE ?= Space Game 12 | export APP_AUTHOR ?= vgmoose 13 | export APP_VERSION ?= 2.0 14 | 15 | TARGET := $(notdir $(CURDIR)) 16 | BUILD := build 17 | SOURCES := src src/switch 18 | INCLUDES := include 19 | ROMFS := data 20 | 21 | DIST_PATH := $(TARGET)_v$(APP_VERSION) 22 | 23 | #--------------------------------------------------------------------------------- 24 | # options for code generation 25 | #--------------------------------------------------------------------------------- 26 | ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE 27 | 28 | CFLAGS := -g -Wall -O2 -ffunction-sections \ 29 | $(ARCH) $(DEFINES) `freetype-config --cflags` 30 | 31 | CFLAGS += $(INCLUDE) -D__SWITCH__ -DVERSION=\"v$(APP_VERSION)\" 32 | 33 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 34 | 35 | ASFLAGS := -g $(ARCH) 36 | LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 37 | 38 | LIBS := -lm -lnx 39 | 40 | #--------------------------------------------------------------------------------- 41 | # list of directories containing libraries, this must be the top level containing 42 | # include and lib 43 | #--------------------------------------------------------------------------------- 44 | LIBDIRS := $(PORTLIBS) $(LIBNX) 45 | 46 | 47 | #--------------------------------------------------------------------------------- 48 | # no real need to edit anything past this point unless you need to add additional 49 | # rules for different file extensions 50 | #--------------------------------------------------------------------------------- 51 | ifneq ($(BUILD),$(notdir $(CURDIR))) 52 | #--------------------------------------------------------------------------------- 53 | 54 | export OUTPUT := $(CURDIR)/$(TARGET) 55 | export TOPDIR := $(CURDIR) 56 | 57 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 58 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 59 | 60 | export DEPSDIR := $(CURDIR)/$(BUILD) 61 | 62 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 63 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 64 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 65 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 66 | 67 | #--------------------------------------------------------------------------------- 68 | # use CXX for linking C++ projects, CC for standard C 69 | #--------------------------------------------------------------------------------- 70 | ifeq ($(strip $(CPPFILES)),) 71 | #--------------------------------------------------------------------------------- 72 | export LD := $(CC) 73 | #--------------------------------------------------------------------------------- 74 | else 75 | #--------------------------------------------------------------------------------- 76 | export LD := $(CXX) 77 | #--------------------------------------------------------------------------------- 78 | endif 79 | #--------------------------------------------------------------------------------- 80 | 81 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) 82 | export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 83 | export OFILES := $(OFILES_BIN) $(OFILES_SRC) 84 | export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) 85 | 86 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 87 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 88 | -I$(CURDIR)/$(BUILD) 89 | 90 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 91 | 92 | ifeq ($(strip $(CONFIG_JSON)),) 93 | jsons := $(wildcard *.json) 94 | ifneq (,$(findstring $(TARGET).json,$(jsons))) 95 | export APP_JSON := $(TOPDIR)/$(TARGET).json 96 | else 97 | ifneq (,$(findstring config.json,$(jsons))) 98 | export APP_JSON := $(TOPDIR)/config.json 99 | endif 100 | endif 101 | else 102 | export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) 103 | endif 104 | 105 | ifeq ($(strip $(ICON)),) 106 | icons := $(wildcard *.jpg) 107 | ifneq (,$(findstring $(TARGET).jpg,$(icons))) 108 | export APP_ICON := $(TOPDIR)/$(TARGET).jpg 109 | else 110 | ifneq (,$(findstring icon.jpg,$(icons))) 111 | export APP_ICON := $(TOPDIR)/icon.jpg 112 | endif 113 | endif 114 | else 115 | export APP_ICON := $(TOPDIR)/$(ICON) 116 | endif 117 | 118 | ifeq ($(strip $(NO_ICON)),) 119 | export NROFLAGS += --icon=$(APP_ICON) 120 | endif 121 | 122 | ifeq ($(strip $(NO_NACP)),) 123 | export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp 124 | endif 125 | 126 | ifneq ($(APP_TITLEID),) 127 | export NACPFLAGS += --titleid=$(APP_TITLEID) 128 | endif 129 | 130 | ifneq ($(ROMFS),) 131 | export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) 132 | endif 133 | 134 | .PHONY: $(BUILD) clean all dist-bin 135 | 136 | #--------------------------------------------------------------------------------- 137 | all: $(BUILD) 138 | 139 | $(BUILD): 140 | @[ -d $@ ] || mkdir -p $@ 141 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.switch 142 | 143 | #--------------------------------------------------------------------------------- 144 | clean: 145 | @echo clean ... 146 | ifeq ($(strip $(APP_JSON)),) 147 | @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf 148 | else 149 | @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf 150 | endif 151 | 152 | #--------------------------------------------------------------------------------- 153 | dist-bin: all 154 | @mkdir -p $(DIST_PATH) 155 | @cp $(OUTPUT).nro $(DIST_PATH)/hbmenu.nro 156 | @zip -rj $(DIST_PATH).zip $(DIST_PATH) 157 | 158 | #--------------------------------------------------------------------------------- 159 | else 160 | .PHONY: all 161 | 162 | DEPENDS := $(OFILES:.o=.d) 163 | 164 | #--------------------------------------------------------------------------------- 165 | # main targets 166 | #--------------------------------------------------------------------------------- 167 | ifeq ($(strip $(APP_JSON)),) 168 | 169 | all : $(OUTPUT).nro 170 | 171 | ifeq ($(strip $(NO_NACP)),) 172 | $(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp 173 | else 174 | $(OUTPUT).nro : $(OUTPUT).elf 175 | endif 176 | 177 | else 178 | 179 | all : $(OUTPUT).nsp 180 | 181 | $(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm 182 | 183 | $(OUTPUT).nso : $(OUTPUT).elf 184 | 185 | endif 186 | 187 | menu.o : $(TOPDIR)/Makefile 188 | $(OUTPUT).elf : $(OFILES) 189 | 190 | $(OFILES_SRC) : $(HFILES_BIN) 191 | 192 | #--------------------------------------------------------------------------------- 193 | # you need a rule like this for each extension you use as binary data 194 | #--------------------------------------------------------------------------------- 195 | %.bin.o %_bin.h : %.bin 196 | #--------------------------------------------------------------------------------- 197 | @echo $(notdir $<) 198 | @$(bin2o) 199 | 200 | -include $(DEPENDS) 201 | 202 | #--------------------------------------------------------------------------------------- 203 | endif 204 | #--------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /src/switch/font.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 8x8 monochrome bitmap fonts for rendering 3 | * Author: Daniel Hepper 4 | * 5 | * License: Public Domain 6 | * 7 | * Based on: 8 | * // Summary: font8x8.h 9 | * // 8x8 monochrome bitmap fonts for rendering 10 | * // 11 | * // Author: 12 | * // Marcel Sondaar 13 | * // International Business Machines (public domain VGA fonts) 14 | * // 15 | * // License: 16 | * // Public Domain 17 | * 18 | * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm 19 | **/ 20 | 21 | // Constant: font8x8_basic 22 | // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) 23 | char font[128][8] = { 24 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) 25 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 26 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 27 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 28 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 29 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 30 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 31 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 32 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 33 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 34 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A 35 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B 36 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C 37 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D 38 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E 39 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F 40 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 41 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 42 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 43 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 44 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 45 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 46 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 47 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 48 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 49 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 50 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A 51 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B 52 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C 53 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D 54 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E 55 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F 56 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) 57 | { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) 58 | { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") 59 | { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) 60 | { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) 61 | { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) 62 | { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) 63 | { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') 64 | { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() 65 | { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) 66 | { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) 67 | { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) 68 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) 69 | { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) 70 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) 71 | { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) 72 | { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) 73 | { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) 74 | { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) 75 | { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) 76 | { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) 77 | { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) 78 | { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) 79 | { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) 80 | { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) 81 | { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) 82 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) 83 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//) 84 | { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) 85 | { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) 86 | { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) 87 | { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) 88 | { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) 89 | { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) 90 | { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) 91 | { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) 92 | { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) 93 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) 94 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) 95 | { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) 96 | { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) 97 | { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) 98 | { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) 99 | { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) 100 | { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) 101 | { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) 102 | { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) 103 | { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) 104 | { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) 105 | { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) 106 | { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) 107 | { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) 108 | { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) 109 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) 110 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) 111 | { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) 112 | { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) 113 | { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) 114 | { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) 115 | { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) 116 | { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) 117 | { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) 118 | { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) 119 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) 120 | { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) 121 | { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) 122 | { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) 123 | { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) 124 | { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) 125 | { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) 126 | { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) 127 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) 128 | { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) 129 | { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) 130 | { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) 131 | { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) 132 | { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) 133 | { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) 134 | { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) 135 | { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) 136 | { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) 137 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) 138 | { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) 139 | { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) 140 | { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) 141 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) 142 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) 143 | { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) 144 | { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) 145 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) 146 | { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) 147 | { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) 148 | { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) 149 | { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) 150 | { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) 151 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F 152 | }; -------------------------------------------------------------------------------- /src/images.c: -------------------------------------------------------------------------------- 1 | /** 2 | This file contains compressed bitmaps that are loaded, decompresed, and used in game. 3 | The file format is very hacky. There is most likely a faster way to do this with gx2, 4 | and they could be even more compressed if they were stored at the bit level rather than the byte level. 5 | 6 | The compression format is as follows (does not apply to palettes, they are uncompressed): 7 | - Palette element sare in {B, G, R} format, as this is what is in windows style bitmap hex 8 | - When uncompressed, bitmaps are stored as matrices of indices for the corresponding pallette. 9 | - For example, bitmap = {{0, 1, 0}, 10 | {1, 2, 1}, 11 | {0, 1, 0}} 12 | palette = {{0x00, 0x00, 0x00}, {0xFF, 0x00, 0x00}, {0x00, 0x00, 0xFF}} 13 | This would result in a 3x3 image, with: 14 | - a black background (palette[0]) (four pixels in each corner) 15 | - a blue plus sign (palette[1]) (four pixels up, down, left, right) 16 | - a red dot in the center (palette[2]) (middle pixel) 17 | - For compression: 18 | - The first number is a count and the second number is the color index number: 19 | {44, 3, 52, 1} // this would draw forty-four palette[3] colors, followed by fifty-two palette[1] colors 20 | - If a negative number is encountered, that pixel is just drawn (this is to compress {1, 3} cases, this would instead just be {-3} 21 | - If a -120 is encountered, a very special case happens: It expects the number after it to be the number of rows to paint with the LAST color in the palette (typically transparent). This is to quickly compress transparent rows that may be used for rotations or logos. 22 | { -120, 5 } // this would put 5 rows of the transparent color (whichever is 0x272727 in the palette, should be at the end) 23 | 24 | I know this explanation is a bit messy, but you're really going to have to think about how you want this implementation 25 | to go down in order to squeeze as many images into your size-restrained binary as possible. 26 | 27 | I have two helper python scripts that I've been using to encode and compress the bitmaps: 28 | - https://gist.github.com/vgmoose/1a6810aacc46c28344ab 29 | - https://gist.github.com/vgmoose/0f80a9b6192096f7aac6 30 | **/ 31 | 32 | unsigned const char title_palette[40][3] = {{0x00, 0x00, 0x00},{0xFF, 0xFF, 0xFF},{0xF8, 0xF5, 0xF5},{0xF6, 0xF5, 0xF5},{0x9A, 0x68, 0x5F},{0xBF, 0xA7, 0xA3},{0xD5, 0xCA, 0xC8},{0xF1, 0xEB, 0xEA},{0xE6, 0xE0, 0xDF},{0xA5, 0x86, 0x80},{0xC9, 0xBA, 0xB7},{0x7C, 0x35, 0x23},{0x88, 0x4E, 0x41},{0xDF, 0xD6, 0xD4},{0x20, 0x07, 0x00},{0x58, 0x2F, 0x23},{0x80, 0x71, 0x6D},{0x77, 0x1C, 0x00},{0x68, 0x19, 0x00},{0x65, 0x18, 0x00},{0x61, 0x17, 0x00},{0x5D, 0x16, 0x00},{0x5A, 0x15, 0x00},{0x54, 0x14, 0x00},{0x4B, 0x12, 0x00},{0x46, 0x11, 0x00},{0x42, 0x0F, 0x00},{0x3D, 0x0E, 0x00},{0x32, 0x0C, 0x00},{0x2C, 0x0A, 0x00},{0x26, 0x09, 0x00},{0x22, 0x08, 0x00},{0x1D, 0x07, 0x00},{0x1A, 0x06, 0x00},{0x64, 0x4D, 0x46},{0x38, 0x0E, 0x00},{0x40, 0x2B, 0x23},{0xA7, 0xA3, 0xA1},{0xEC, 0xEB, 0xEA},{0x27, 0x27, 0x27}}; 33 | 34 | const char compressed_title[3061] = {-120, 11, 19, 39, 63, 1, 6, 39, 30, 1, 12, 39, 30, 1, 3, 39, 29, 1, 8, 39, 16, 39, 68, 1, 3, 39, 33, 1, 7, 39, 34, 1, -39, 32, 1, 6, 39, 15, 39, 3, 1, -13, -9, -4, 28, 17, -4, -1, -9, 28, 17, -11, -9, -7, 2, 1, 2, 39, -1, -7, 27, 17, -4, -5, -2, 2, 1, 5, 39, 3, 1, -13, -9, -11, 27, 17, -2, 3, 1, -10, -4, 25, 17, -12, -9, -7, 2, 1, 5, 39, 14, 39, 2, 1, -2, -4, 31, 17, -5, -1, -12, 31, 17, -13, 2, 1, -39, -1, -10, 29, 17, -12, -7, 2, 1, 2, 39, 3, 1, -8, -4, 29, 17, -4, 3, 1, -9, 29, 17, -11, -7, -1, 5, 39, 13, 39, 2, 1, -8, -11, 32, 17, -6, -8, 32, 17, -11, -7, 3, 1, -9, 30, 17, -4, 2, 1, -39, 3, 1, -5, 31, 17, -5, -1, -2, -4, 31, 17, -9, 2, 1, 4, 39, 13, 39, 2, 1, -12, 33, 17, -2, -10, 33, 17, -13, 3, 1, -11, 31, 17, 4, 1, -2, -4, 32, 17, -13, -1, -5, 32, 17, -4, 2, 1, 4, 39, 13, 39, -1, -10, 33, 17, -4, -1, -9, 33, 17, -13, 2, 1, -8, 32, 17, 3, 1, -2, -4, 33, 17, -1, -7, 33, 17, -9, 2, 1, 4, 39, 12, 39, 2, 1, -9, 33, 17, -5, -1, 34, 17, -2, 2, 1, -5, 31, 17, -4, 2, 1, -2, -4, 33, 17, -9, -1, -5, 33, 17, -10, -1, 5, 39, 12, 39, 2, 1, 34, 17, -8, -13, 33, 17, -4, 3, 1, -4, 31, 17, -5, 2, 1, -5, 34, 17, -10, -1, -12, 33, 17, -8, -1, 5, 39, 12, 39, -1, -13, 33, 17, -11, -1, -5, 33, 17, -5, 3, 1, 32, 17, -13, -1, -13, 35, 17, 2, 8, 33, 17, -12, 2, 1, 5, 39, 11, 39, 2, 1, -5, 33, 17, -9, -1, -4, 33, 17, -6, 2, 1, -13, 32, 17, 2, 1, -4, 34, 17, -11, -1, -5, 33, 17, -9, 2, 1, 5, 39, 11, 39, 2, 1, -4, 10, 17, -12, -6, -2, 21, 1, -2, 11, 17, 12, 5, -11, 10, 17, 23, 1, -6, 11, 17, -4, -1, -13, 13, 17, -4, 21, 5, -10, -1, -4, 10, 17, -9, 11, 5, -4, 10, 17, -10, -1, 6, 39, 11, 39, -1, -2, 11, 17, -8, 23, 1, -6, 10, 17, -9, 12, 1, -13, 9, 17, -4, 2, 1, -39, 21, 1, -4, 10, 17, -10, -1, -9, 11, 17, -4, -7, 23, 1, -2, 11, 17, 13, 1, -4, 9, 17, -7, -1, 6, 39, 11, 39, -1, -6, 10, 17, -12, 18, 13, 6, 1, -5, 10, 17, -10, 12, 1, -5, 9, 17, -5, 5, 1, -2, 17, 13, -6, -11, 10, 17, -8, -2, 11, 17, -4, -2, 24, 1, -6, 10, 17, -9, 12, 1, -2, -11, 8, 17, -4, 2, 1, 6, 39, 10, 39, 2, 1, -9, 30, 17, -9, -2, 3, 1, -12, 10, 17, -8, 10, 1, -2, -5, 10, 17, -8, 2, 1, -2, -5, -12, 29, 17, -11, -1, -10, 10, 17, -11, -2, 2, 1, 21, 39, 2, 1, -5, 10, 17, -10, 11, 1, -8, -4, 9, 17, -5, 2, 1, 6, 39, 10, 39, 2, 1, -12, 31, 17, -12, -2, -1, -7, 33, 17, -11, 2, 1, -8, -11, 31, 17, -9, -1, -9, 10, 17, -10, 2, 1, 22, 39, 2, 1, -12, 33, 17, -6, -1, 7, 39, 10, 39, -1, -7, 33, 17, -5, -1, -10, 33, 17, -9, -1, -13, -11, 32, 17, -10, -2, 10, 17, -12, 2, 1, 23, 39, -1, -7, 34, 17, -2, -1, 7, 39, 10, 39, -1, -10, 33, 17, -4, -1, -9, 33, 17, -10, -1, -12, 33, 17, -7, -6, 10, 17, -5, 2, 1, 23, 39, -1, -10, 33, 17, -4, 2, 1, 7, 39, 9, 39, 2, 1, -9, 33, 17, -5, -1, -11, 33, 17, -7, -13, 33, 17, -12, -1, -5, 10, 17, -7, -1, 23, 39, 2, 1, -9, 33, 17, -5, 2, 1, 7, 39, 9, 39, 2, 1, -4, 33, 17, -13, -8, 33, 17, -12, -1, -5, 33, 17, -9, -1, -4, 9, 17, -11, 2, 1, 23, 39, 2, 1, -11, 33, 17, -8, -1, 8, 39, 9, 39, 2, 1, -4, 33, 17, -1, -10, 33, 17, -13, -1, -4, 33, 17, -6, -2, 10, 17, -4, 2, 1, 23, 39, -1, -8, 33, 17, -9, 2, 1, 8, 39, 9, 39, 2, 1, -10, 32, 17, -4, -1, -9, 31, 17, -11, -6, -1, -2, 34, 17, -2, -10, 10, 17, -4, 2, 1, 23, 39, -1, -10, 32, 17, -9, 2, 1, 9, 39, 10, 39, 2, 1, -5, 31, 17, -10, -1, 30, 17, -11, -5, -2, 2, 1, -6, 9, 17, -11, -9, -6, 10, 13, -10, 10, 17, -4, -1, -9, 10, 17, -4, 2, 1, 22, 39, 2, 1, -9, 30, 17, -12, -10, 2, 1, 10, 39, 11, 39, 2, 1, -7, 20, 5, -4, 9, 17, -8, -13, 10, 17, -11, 17, 4, -9, -10, -2, 4, 1, -9, 9, 17, -10, 12, 1, -5, 10, 17, -5, -1, -12, 10, 17, -12, 2, 1, 22, 39, 2, 1, 11, 17, -9, 18, 5, -13, -2, 2, 1, 11, 39, 8, 39, 26, 1, -4, 8, 17, -11, -1, -5, 10, 17, -5, 21, 1, -39, 2, 1, -12, 9, 17, 13, 1, -4, 10, 17, -13, -1, 12, 17, -6, 24, 1, -13, 10, 17, -4, 22, 1, 12, 39, 7, 39, 25, 1, -2, -10, 9, 17, -9, -1, -4, 10, 17, -8, 18, 1, 4, 39, -1, -7, 10, 17, -5, 12, 13, 11, 17, 2, 1, 13, 17, -9, -6, 20, 13, -8, -1, -5, 11, 17, -8, 21, 1, 12, 39, 7, 39, 2, 1, -4, 33, 17, -10, -2, 10, 17, -11, 2, 1, 21, 39, -1, -10, 33, 17, -9, 2, 1, -4, 34, 17, -9, -1, -4, 11, 17, -12, -9, 18, 5, -13, -1, 12, 39, 7, 39, -1, -2, 34, 17, -7, -6, 10, 17, -9, 2, 1, 20, 39, 2, 1, -9, 33, 17, -10, 2, 1, -4, 34, 17, -10, -2, 32, 17, -13, -1, 12, 39, 7, 39, -1, -6, 33, 17, -12, -1, -9, 10, 17, -10, -1, 21, 39, 2, 1, -11, 33, 17, -7, 2, 1, -9, 34, 17, -7, -6, 32, 17, 2, 1, 12, 39, 6, 39, 2, 1, -5, 33, 17, -5, -1, -12, 10, 17, -7, -1, 21, 39, -1, -8, 33, 17, -4, 3, 1, -10, 33, 17, -4, -1, -9, 31, 17, -9, 2, 1, 12, 39, 6, 39, 2, 1, -4, 33, 17, -6, -7, 10, 17, -12, 2, 1, 20, 39, 2, 1, -5, 33, 17, -10, 3, 1, -7, 33, 17, -5, -1, -12, 31, 17, -10, -1, 13, 39, 6, 39, -1, -2, 33, 17, -12, -1, -10, 10, 17, -9, 2, 1, 20, 39, 2, 1, -5, 32, 17, -12, 2, 1, -39, 2, 1, -4, 32, 17, -6, -1, 32, 17, -8, -1, 13, 39, 6, 39, -1, -10, 33, 17, -10, -1, -9, 10, 17, -10, -1, 21, 39, 2, 1, -5, 32, 17, -13, 2, 1, -39, 2, 1, -13, 32, 17, -2, -1, -4, 30, 17, -11, 2, 1, 13, 39, 5, 39, 2, 1, -9, 32, 17, -10, 2, 1, -11, 10, 17, -2, -1, 22, 39, -1, -8, 30, 17, -11, -8, 2, 1, 3, 39, 2, 1, -9, 30, 17, -4, 2, 1, -8, 30, 17, -9, 2, 1, 13, 39, 5, 39, 2, 1, -12, 30, 17, -9, -13, 2, 1, -8, 10, 17, -4, 2, 1, 22, 39, 2, 1, -6, -12, 27, 17, -12, -8, 2, 1, 5, 39, 2, 1, -5, 29, 17, -5, 3, 1, -8, -4, 28, 17, -10, -1, 14, 39, 5, 39, 2, 1, 28, 5, -10, -13, -7, 4, 1, -8, 10, 5, -6, 2, 1, 23, 39, 3, 1, -13, -10, 23, 5, -10, -8, 3, 1, 7, 39, 2, 1, -7, -10, 27, 5, -7, -1, -39, 3, 1, -7, -10, 26, 5, -7, -1, 14, 39, 6, 39, 33, 1, 2, 39, 14, 1, 25, 39, 31, 1, 9, 39, 32, 1, 2, 39, 32, 1, 14, 39, 7, 39, 28, 1, 8, 39, 10, 1, 31, 39, 23, 1, 16, 39, 27, 1, 8, 39, 26, 1, 16, 39, -120, 4, 33, 39, 30, 1, 2, 39, 29, 1, 5, 39, 44, 1, 10, 39, 29, 1, 18, 39, 30, 39, 66, 1, 2, 39, 47, 1, 7, 39, 32, 1, 16, 39, 28, 39, 4, 1, -6, -9, -11, 27, 18, 3, 1, -9, 26, 18, -11, -9, -13, 4, 1, -9, 41, 18, -11, -9, -2, 2, 1, 5, 39, 2, 1, -10, -4, 25, 18, -12, -9, -7, 2, 1, 15, 39, 27, 39, 3, 1, -10, -12, 29, 19, -9, 3, 1, -12, 29, 19, -37, 3, 1, 44, 19, -11, -8, 2, 1, 3, 39, 2, 1, -9, 29, 19, -11, -7, -1, 15, 39, 26, 39, 2, 1, -7, -4, 31, 19, -10, 2, 1, -7, 31, 19, -13, -1, -13, 45, 19, -11, -2, -1, 2, 39, 2, 1, -9, 31, 19, -9, 2, 1, 14, 39, 25, 39, 2, 1, -8, -11, 32, 20, -8, 2, 1, -10, 31, 20, -5, -1, -5, 46, 20, -9, 4, 1, -5, 32, 20, -4, 2, 1, 14, 39, 24, 39, 2, 1, -8, -11, 32, 20, -11, 3, 1, -9, 31, 20, -5, -1, -12, 47, 20, -7, 2, 1, -2, 33, 20, -4, 2, 1, 14, 39, 23, 39, 2, 1, -7, -11, 33, 21, -9, 3, 1, -11, 31, 21, -10, -2, 48, 21, -10, 2, 1, -10, 33, 21, -5, 2, 1, 14, 39, 23, 39, 2, 1, -4, 34, 22, -10, 2, 1, -8, 32, 22, -7, -6, 48, 22, -9, 2, 1, -12, 33, 22, -8, -1, 15, 39, 22, 39, 2, 1, -10, 35, 22, -38, 2, 1, -10, 31, 22, -12, -1, -37, 48, 22, -16, -1, -38, 33, 22, -15, 2, 1, 15, 39, 22, 39, 2, 1, -34, 34, 23, -34, 3, 1, -9, 31, 23, -37, -1, -34, 48, 23, -16, -1, -10, 33, 23, -9, 2, 1, 15, 39, 21, 39, 2, 1, -10, 13, 23, -12, 21, 5, -6, 22, 1, -2, -9, 11, 23, -6, -38, 49, 23, -9, -1, -9, 10, 23, -9, 11, 5, -16, 10, 23, -10, -1, 16, 39, 21, 39, 2, 1, -12, 11, 23, -9, -38, 24, 1, 2, 39, 20, 1, -8, 11, 23, -2, -10, 11, 23, -10, 7, 1, -10, 10, 23, -16, 2, 1, -8, -13, -10, -12, 12, 23, -10, -1, 11, 23, -2, 12, 1, -12, 9, 23, -8, -1, 16, 39, 21, 39, -1, -8, 11, 24, -12, 25, 1, -39, 4, 1, -8, 17, 13, -9, 10, 24, -16, -1, -9, 11, 24, -38, 7, 1, -9, 10, 24, -5, 5, 1, -3, -34, 11, 24, -8, -13, 10, 24, -16, 12, 1, -3, -34, 8, 24, -34, 2, 1, 16, 39, 20, 39, 2, 1, -5, 10, 24, -34, -3, 3, 1, -34, 19, 24, -9, 3, 1, -8, -9, -15, 29, 24, -5, -1, -15, 10, 24, -34, 2, 1, 4, 39, 2, 1, -34, 10, 24, -8, -1, 3, 39, 2, 1, -37, 10, 24, -15, -1, -5, 10, 24, -5, 11, 1, -38, -16, 9, 24, -9, 2, 1, 16, 39, 20, 39, 2, 1, -34, 10, 24, -10, 3, 1, -38, 20, 24, -10, 2, 1, -37, 32, 24, 2, 8, 11, 24, -9, 2, 1, 4, 39, -1, -8, 10, 24, -15, 2, 1, 3, 39, 2, 1, -16, 10, 24, -9, -1, -34, 33, 24, -10, -1, 17, 39, 20, 39, -1, -38, 10, 25, -16, 2, 1, -39, -1, -10, 20, 25, -8, -1, -9, 32, 25, -15, -1, -10, 11, 25, -6, -1, 5, 39, -1, -10, 10, 25, -16, 2, 1, 3, 39, 2, 1, -15, 10, 25, -10, -3, 34, 25, -38, -1, 17, 39, 20, 39, -1, -10, 10, 25, -10, 4, 1, -9, 19, 25, -15, -1, -10, 33, 25, -16, -1, -16, 11, 25, -3, -1, 4, 39, 2, 1, -16, 10, 25, -10, -1, 4, 39, -1, -13, 11, 25, -38, -6, 33, 25, -34, 2, 1, 17, 39, 19, 39, 2, 1, -16, 9, 26, -15, -3, -1, -39, 2, 1, -15, 19, 26, -9, -1, -16, 33, 26, -5, -1, 11, 26, -34, 2, 1, 4, 39, 2, 1, -15, 10, 26, -38, -1, 3, 39, 2, 1, -37, 10, 26, -34, -1, -9, 33, 26, -37, 2, 1, 17, 39, 19, 39, 2, 1, -15, 9, 27, -16, 2, 1, -39, -1, -8, 20, 27, -10, -1, -15, 33, 27, -38, -13, 11, 27, -37, 2, 1, 4, 39, -1, -13, 10, 27, -34, 2, 1, 3, 39, 2, 1, -16, 10, 27, -37, -1, -34, 33, 27, -6, -1, 18, 39, 19, 39, -1, -8, 10, 27, -37, 2, 1, -39, -1, -5, 20, 27, -38, -13, 33, 27, -34, -1, -37, 11, 27, -13, -1, 4, 39, 2, 1, -37, 10, 27, -9, 2, 1, 3, 39, -1, -3, 11, 27, -6, -38, 33, 27, -16, 2, 1, 18, 39, 18, 39, 2, 1, -37, 10, 35, -37, 4, 1, -16, 19, 35, -34, -1, -37, 33, 35, -9, -1, -34, 11, 35, 2, 1, 4, 39, 2, 1, -34, 10, 35, -10, -1, 4, 39, -1, -6, 11, 35, -3, -10, 32, 35, -16, -3, 2, 1, 18, 39, 18, 39, 2, 1, -16, 10, 35, -37, 4, 1, 20, 35, -37, -1, -16, 9, 35, -34, -5, 11, 13, -34, 10, 35, -10, -3, 11, 35, -16, 2, 1, 4, 39, -1, -3, 11, 35, -3, -1, 3, 39, 2, 1, -37, 10, 35, -16, -1, -16, 30, 35, -36, -5, 3, 1, 19, 39, 18, 39, 2, 1, 11, 28, -9, 3, 1, -8, 9, 16, 11, 28, -6, -3, 9, 28, -34, -3, 12, 1, -36, 10, 28, -3, -6, 11, 28, -5, -1, 5, 39, -1, -6, 10, 28, -34, 2, 1, 3, 39, 2, 1, -34, 10, 28, -37, -1, -36, 10, 28, -16, 18, 37, -13, -3, 2, 1, 21, 39, 18, 39, 2, 1, 12, 28, -38, 11, 1, -38, 11, 28, -3, -6, 9, 28, -37, 12, 1, -8, 10, 28, -34, -1, -9, 11, 28, -8, -1, 4, 39, 2, 1, -37, 10, 28, -37, 2, 1, 3, 39, -1, -38, 11, 28, -13, -8, 10, 28, -36, 22, 1, 22, 39, 18, 39, 2, 1, 12, 28, -34, -37, 10, 13, -37, 10, 28, -34, -1, -37, 9, 28, -34, -6, 11, 13, -37, 10, 28, -37, -1, -34, 10, 28, -36, 2, 1, 4, 39, 2, 1, -34, 10, 28, -6, -1, 4, 39, -1, -10, 10, 28, -36, -1, -5, 11, 28, -8, 21, 1, 22, 39, 18, 39, 2, 1, 35, 29, -37, -1, -34, 33, 29, -6, -38, 11, 29, -9, 2, 1, 4, 39, -1, -38, 11, 29, 2, 1, 3, 39, 2, 1, -9, 10, 29, -16, -1, -16, 11, 29, -36, -9, 18, 37, -13, -1, 22, 39, 18, 39, 2, 1, -34, 34, 29, -13, -38, 34, 29, -1, -10, 11, 29, -10, -1, 5, 39, -1, -10, 10, 29, -16, 2, 1, 3, 39, 2, 1, -36, 10, 29, -5, -1, 32, 29, -6, -1, 22, 39, 18, 39, 2, 1, -16, 34, 30, -1, -10, 33, 30, -16, -1, -16, 11, 30, -38, -1, 4, 39, 2, 1, -9, 10, 30, -5, 2, 1, 3, 39, -1, -8, 11, 30, -38, -13, 32, 30, -3, -1, 22, 39, 18, 39, 2, 1, -37, 33, 30, -16, -1, -9, 33, 30, -10, -1, -36, 10, 30, -34, 2, 1, 4, 39, 2, 1, -36, 10, 30, -8, -1, 4, 39, -1, -5, 10, 30, -34, -1, -37, 31, 30, -34, 2, 1, 22, 39, 19, 39, -1, -13, 33, 31, -5, -1, -36, 32, 31, -36, -1, -8, 11, 31, -37, 2, 1, 4, 39, -1, -8, 10, 31, -36, 2, 1, 3, 39, 2, 1, -16, 10, 31, -9, -1, -16, 31, 31, -37, 2, 1, 22, 39, 19, 39, 2, 1, -34, 32, 14, -8, -1, 33, 14, -37, -1, -5, 11, 14, -6, -1, 5, 39, -1, -5, 10, 14, -16, 2, 1, 3, 39, 2, 1, 11, 14, -10, -1, -16, 31, 14, -13, -1, 23, 39, 19, 39, 2, 1, -10, 31, 32, -36, 2, 1, 32, 32, -34, 2, 1, -16, 11, 32, -3, -1, 4, 39, 2, 1, -16, 10, 32, -10, -1, 4, 39, -1, -13, 11, 32, -3, -1, -16, 30, 32, -36, 2, 1, 23, 39, 20, 39, 2, 1, -16, 30, 33, -9, 2, 1, -16, 30, 33, -16, -3, 2, 1, 11, 33, -34, 2, 1, 4, 39, 2, 1, 11, 33, -38, -1, 3, 39, 2, 1, -37, 10, 33, -34, 2, 1, -8, 30, 33, -16, 2, 1, 23, 39, 20, 39, 2, 1, -3, -16, 29, 33, -10, 2, 1, -3, -9, 28, 33, -37, 3, 1, -6, 11, 33, -37, 2, 1, 4, 39, -1, -13, 10, 33, -34, 2, 1, 3, 39, 2, 1, -34, 10, 33, -37, 3, 1, -8, -34, 28, 33, -5, -1, 24, 39, 21, 39, 3, 1, -8, -5, 27, 37, -38, 4, 1, -38, -13, 24, 37, -10, -38, 4, 1, -13, 11, 37, -38, -1, 5, 39, -1, -13, 10, 37, -10, 2, 1, 3, 39, 2, 1, 11, 37, -38, -1, -39, 3, 1, -38, -10, 26, 37, -38, -1, 24, 39, 23, 39, 32, 1, 2, 39, 30, 1, 2, 39, 15, 1, 5, 39, 14, 1, 5, 39, 14, 1, 2, 39, 32, 1, 24, 39, 26, 39, 27, 1, 7, 39, 24, 1, 7, 39, 11, 1, 9, 39, 10, 1, 8, 39, 11, 1, 8, 39, 26, 1, 26, 39, -120, 9}; 35 | 36 | const signed char compressed_ship[511] = {-120, 4, 17, 14, -2, 18, 14, 16, 14, -12, -13, -12, 17, 14, 15, 14, -2, -5, -12, -5, -2, 16, 14, 15, 14, -2, -5, -12, -5, -2, 16, 14, 14, 14, -2, -5, -3, -11, -3, -5, -2, 15, 14, 14, 14, -2, -5, -6, -11, -6, -5, -2, 15, 14, 14, 14, -2, -5, -6, -11, -6, -5, -2, 15, 14, 14, 14, -4, -3, -8, -11, -8, -3, -4, 15, 14, 14, 14, -4, -3, -6, -12, -6, -3, -4, 15, 14, 13, 14, -2, -5, -6, -12, -4, -12, -6, -5, -2, 14, 14, 13, 14, -2, -3, -6, -12, -3, -12, -6, -3, -2, 14, 14, 7, 14, 3, 12, 2, 14, -2, -5, -3, -12, -5, -7, -5, -12, -3, -5, -2, 2, 14, 3, 12, 8, 14, 6, 14, -12, 2, 11, -10, -12, -14, -2, -5, -3, -12, -5, -7, -5, -12, -3, -5, -2, -14, -12, -10, 2, 11, -12, 7, 14, 6, 14, -12, -10, -9, -12, -11, 2, 13, -2, -13, -12, -4, -6, -4, -12, -13, -2, 2, 13, -11, -12, -9, -10, -12, 7, 14, 6, 14, -12, -11, -10, -12, -11, -13, 2, 14, -2, -13, -2, -3, -2, -13, -2, 2, 14, -13, -11, -12, -10, -11, -12, 7, 14, 7, 14, 2, 12, -13, -12, 2, 14, -12, -11, -2, -12, -2, -12, -2, -11, -12, 2, 14, -12, -13, 2, 12, 8, 14, 6, 14, -12, -9, -7, -9, -11, -14, -12, -13, -10, -5, -6, -7, -6, -5, -10, -13, -12, -14, -11, -9, -7, -9, -12, 7, 14, 6, 14, -12, -11, -9, -10, -11, -12, 2, 13, -10, -5, -8, -7, -8, -5, -10, 2, 13, -12, -11, -10, -9, -11, -12, 7, 14, 6, 14, -12, -11, -10, -11, -2, -11, -10, 2, 9, -5, -3, -7, -3, -5, 2, 9, -10, -11, -2, -11, -10, -11, -12, 7, 14, 7, 14, -12, -11, -2, -3, -12, -11, 2, 10, -5, -6, -7, -6, -5, 2, 10, -11, -12, -5, -2, -11, -12, 8, 14, 7, 14, -12, -2, -5, -3, -12, -11, -10, -9, -10, -5, -6, -5, -10, -9, -10, -11, -12, -3, -5, -2, -12, 8, 14, 6, 14, 2, 2, -5, -3, -6, -12, -11, -9, -7, -9, -5, -3, -5, -9, -7, -9, -11, -12, -6, -3, -5, 2, 2, 7, 14, 5, 14, -2, -5, -3, 2, 4, -2, -12, -11, -10, -7, -9, -11, -5, -11, -9, -7, -10, -11, -12, -2, 2, 4, -3, -5, -2, 6, 14, 5, 14, -2, -3, -4, 2, 8, 2, 2, -12, -11, -10, 2, 11, -14, 2, 11, -10, -11, -12, 2, 2, 2, 8, -4, -3, -2, 6, 14, 5, 14, 5, 2, 2, 14, 2, 12, 2, 11, -12, -14, -12, 2, 11, 2, 12, 2, 14, 5, 2, 6, 14, 12, 14, -13, -4, -5, -2, 3, 14, -2, -5, -4, -13, 13, 14, 12, 14, 2, 2, -4, -2, 3, 14, -2, -4, 2, 2, 13, 14, -120, 5}; 37 | 38 | unsigned const char ship_palette[15][3] = { {0xFF, 0xFF, 0xFF}, { 0x89, 0x01, 0x1D}, { 0xFF, 0x94, 0x6A}, { 0xCC, 0x3E, 0x00}, { 0xD9, 0x67, 0x00}, { 0xFD, 0xCA, 0x31}, { 0xFF, 0xFA, 0xEA}, { 0x1C, 0x5B, 0xF0}, { 0xBE, 0xBE, 0xBE}, { 0x94, 0x94, 0x94}, { 0x6B, 0x6B, 0x6B}, { 0x40, 0x40, 0x40}, { 0x1F, 0x1F, 0x1F}, { 0xFF, 0xFF, 0xFF }, { 0x27, 0x27, 0x27 } }; 39 | 40 | const signed char compressed_enemy[206] = {-120, 3, 15, 9, 4, 0, 4, 9, 14, 9, 0, -8, -7, -8, 0, 4, 9, 13, 9, 0, -8, -6, -7, -6, 0, 4, 9, 12, 9, 0, -8, -6, -8, -7, 2, 0, 4, 9, 6, 9, 3, 0, 2, 9, 0, -8, -6, 5, 0, 4, 9, 4, 9, 2, 0, -8, -7, -8, 0, -8, -7, -6, 5, 0, 5, 9, 4, 9, 0, 2, 7, -6, 3, 0, -2, 5, 0, 6, 9, 4, 9, 2, 0, 4, 2, 0, 4, 2, 2, 0, 6, 9, 3, 9, -8, -3, -2, 4, 1, -5, 4, 1, -2, -6, -8, 5, 9, 3, 9, 0, -4, -2, -1, -5, -8, -1, -2, -1, -5, -8, -1, -2, -4, 0, 5, 9, 3, 9, -8, -3, -7, -1, -8, -7, -1, -2, -1, -8, -7, -1, -7, -3, -8, 5, 9, 4, 9, 0, -7, 4, 1, -6, 4, 1, -8, 0, 6, 9, 5, 9, 0, -8, 2, 2, -5, -4, -5, 2, 2, 2, 8, 7, 9, 6, 9, -8, -6, -4, -6, -7, -3, -5, -3, -8, 8, 9, 7, 9, 0, -8, -4, -5, -4, -8, 0, 9, 9, 9, 9, 0, -8, 0, 11, 9, -120, 4}; 41 | 42 | unsigned const char enemy_palette[10][3] = { { 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF }, { 0x87, 0x51, 0x53 }, { 0xC0, 0x85, 0x87 }, { 0xFF, 0xBE, 0xC0 }, { 0xC1, 0xC1, 0xC1 }, { 0x87, 0x87, 0x87 }, { 0x53, 0x53, 0x53 }, { 0x26, 0x26, 0x26 }, { 0x27, 0x27, 0x27 } }; 43 | 44 | const signed char compressed_ship2[452] = {-120, 2, 17, 5, 2, 4, 17, 5, 17, 5, 2, 4, 17, 5, 17, 5, 2, 4, 17, 5, 17, 5, 2, 4, 17, 5, 17, 5, 2, 4, 17, 5, 17, 5, 2, 4, 17, 5, 15, 5, 6, 4, 15, 5, 15, 5, 6, 4, 15, 5, 15, 5, 6, 4, 15, 5, 15, 5, 6, 4, 15, 5, 9, 5, 2, 3, 4, 5, 6, 4, 4, 5, 2, 3, 9, 5, 9, 5, 2, 3, 4, 5, 6, 4, 4, 5, 2, 3, 9, 5, 9, 5, 2, 3, 4, 5, 6, 4, 4, 5, 2, 3, 9, 5, 9, 5, 2, 3, 4, 5, 6, 4, 4, 5, 2, 3, 9, 5, 9, 5, 2, 4, 2, 5, 10, 4, 2, 5, 2, 4, 9, 5, 9, 5, 2, 4, 2, 5, 10, 4, 2, 5, 2, 4, 9, 5, 3, 5, 2, 3, 4, 5, 2, 4, 2, 2, 4, 4, 2, 3, 4, 4, 2, 2, 2, 4, 4, 5, 2, 3, 3, 5, 3, 5, 2, 3, 4, 5, 2, 4, 2, 2, 4, 4, 2, 3, 4, 4, 2, 2, 2, 4, 4, 5, 2, 3, 3, 5, 3, 5, 2, 3, 4, 5, 2, 2, 4, 4, 6, 3, 4, 4, 2, 2, 4, 5, 2, 3, 3, 5, 3, 5, 2, 3, 4, 5, 2, 2, 4, 4, 6, 3, 4, 4, 2, 2, 4, 5, 2, 3, 3, 5, 3, 5, 2, 4, 4, 5, 6, 4, 2, 3, 2, 4, 2, 3, 6, 4, 4, 5, 2, 4, 3, 5, 3, 5, 2, 4, 4, 5, 6, 4, 2, 3, 2, 4, 2, 3, 6, 4, 4, 5, 2, 4, 3, 5, 3, 5, 2, 4, 2, 5, 22, 4, 2, 5, 2, 4, 3, 5, 3, 5, 2, 4, 2, 5, 22, 4, 2, 5, 2, 4, 3, 5, 3, 5, 10, 4, 2, 3, 6, 4, 2, 3, 10, 4, 3, 5, 3, 5, 10, 4, 2, 3, 6, 4, 2, 3, 10, 4, 3, 5, 3, 5, 6, 4, 2, 5, 4, 3, 6, 4, 4, 3, 2, 5, 6, 4, 3, 5, 3, 5, 6, 4, 2, 5, 4, 3, 6, 4, 4, 3, 2, 5, 6, 4, 3, 5, 3, 5, 4, 4, 4, 5, 4, 3, 2, 5, 2, 4, 2, 5, 4, 3, 4, 5, 4, 4, 3, 5, 3, 5, 4, 4, 4, 5, 4, 3, 2, 5, 2, 4, 2, 5, 4, 3, 4, 5, 4, 4, 3, 5, 3, 5, 2, 4, 12, 5, 2, 4, 12, 5, 2, 4, 3, 5, 3, 5, 2, 4, 12, 5, 2, 4, 12, 5, 2, 4, 3, 5, -120, 2}; 45 | 46 | unsigned const char ship2_palette[6][3] = { { 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF }, { 0xCC, 0x66, 0x00 }, { 0x00, 0x00, 0xFF }, { 0xDD, 0xDD, 0xDD }, { 0x27, 0x27, 0x27 } }; 47 | 48 | const signed char compressed_boss[740] = {-120, 4, 16, 39, -33, 2, 20, -19, 2, 34, 14, 39, 14, 39, -34, -33, -20, 2, 21, 2, 33, -32, 2, 34, -28, -34, -25, 2, 3, -30, 6, 39, 11, 39, -33, -37, -34, -18, -33, 2, 21, -20, 3, 33, -37, 2, 29, -37, 3, 6, -33, -28, -3, -34, 3, 39, 3, 39, 3, 38, -5, 2, 32, -30, -33, -16, -37, -5, -37, -33, -21, -20, -14, 2, 33, -19, -37, 2, 35, -36, -3, 2, 34, -7, -33, -2, -33, -32, -26, 1, 39, -39, -38, 5, 11, -31, -34, -30, 2, 20, -28, -12, -32, -33, -16, -23, -22, -33, -21, -19, -3, 2, 9, -30, 2, 33, -4, -7, -33, -4, 2, 33, -37, 1, 39, -39, 3, 13, -11, -13, -31, -28, -19, -14, -21, 2, 20, -33, 2, 16, -21, -22, -20, -33, 2, 20, -28, -35, -36, -10, -6, -7, 2, 6, -33, -29, -20, -33, -3, 1, 39, -39, 4, 13, -26, -28, -15, -16, -33, -22, -23, -21, -16, 4, 20, -22, -21, 2, 22, -15, -24, -27, -10, -6, -7, 2, 6, -2, -30, -20, -33, -37, 1, 39, -39, 3, 13, -11, -3, -28, -19, -16, -20, -22, -25, -23, -21, 2, 20, 2, 16, -20, -19, -21, -22, -20, -15, -17, -2, -34, -6, -33, -2, -29, -24, -33, -28, -26, 1, 39, -39, 3, 13, -30, -18, -15, -16, -20, -21, -23, -25, -23, -21, 2, 16, 2, 20, -16, -21, -22, -21, 2, 20, 2, 16, 2, 19, -15, -18, -14, -18, -14, -37, -35, 1, 39, -39, 3, 13, -29, -28, -15, -16, -21, -22, -23, -25, -21, -22, -20, -16, 2, 21, -22, -23, -22, -21, 5, 20, -16, -19, -15, -18, -28, -17, -30, -36, 1, 39, -38, 3, 13, -37, -28, -15, -20, 3, 22, -23, 2, 20, -34, -33, -22, 3, 23, -22, -21, 3, 20, -16, 2, 19, -15, -28, -14, -17, -26, -27, 2, 39, -38, 2, 13, -11, -29, 2, 28, -20, -21, -22, -33, -22, -20, -28, -25, -3, -21, 2, 25, -23, -22, -21, -20, -21, -16, -15, 3, 18, -17, 2, 29, -30, -36, 2, 39, -11, 2, 13, -11, -26, -18, -28, 2, 20, -21, -34, 2, 22, -34, -38, -30, -21, -23, -25, -23, -22, 2, 21, -20, -15, -18, -14, -28, -14, -24, -17, -29, -35, 3, 39, -11, 2, 13, -11, -30, -17, -28, -33, -19, -20, -29, -21, -23, -34, -8, -31, -21, 2, 23, -22, 2, 21, -20, -19, 2, 18, -28, -18, 2, 17, -29, 2, 27, 3, 39, -11, 3, 13, -38, -29, -18, 2, 15, -19, -34, -33, -22, -15, -29, -8, -16, -20, 2, 22, -21, -20, -19, -15, -19, -15, -18, -17, -24, -26, 2, 27, 4, 39, -11, 3, 13, -38, -26, -17, -18, -28, 2, 19, -37, -21, -16, -14, -24, -19, -16, -20, -21, -20, 2, 19, 2, 15, -18, -17, -29, -26, -30, -27, 5, 39, -11, 2, 13, -9, -11, -30, -29, -14, -18, -28, 2, 18, -17, -16, -19, -15, -19, -16, 2, 19, -15, -17, -18, 2, 14, -17, -26, -30, -27, -30, 6, 39, -39, -13, 2, 9, -13, -38, -26, -17, -18, 2, 14, 2, 18, -24, 2, 15, 2, 19, -15, -28, 3, 14, -17, 2, 29, 3, 26, 7, 39, -39, 4, 9, -13, -30, -24, 5, 14, -18, 5, 15, -14, 2, 17, -29, -26, 2, 27, -26, -29, 8, 39, -39, -13, 4, 9, -35, -30, -24, 4, 17, 2, 18, 3, 15, -18, -29, -27, -35, 2, 38, -31, -34, -26, 9, 39, -39, -13, 5, 9, -36, -30, -26, 3, 29, -17, -14, 3, 17, -29, -35, 4, 11, -9, -31, 10, 39, -39, -11, 6, 9, -13, 2, 11, 2, 38, -30, 4, 26, -30, -38, -11, -1, -12, -8, -31, -38, 10, 39, -39, -11, -13, 8, 9, 2, 36, -11, 2, 38, -30, -26, -34, -11, 3, 8, -32, -31, -36, 10, 39, 2, 39, -13, 10, 9, -36, -11, 3, 38, -5, -12, -1, -12, -8, -31, -5, 11, 39, 2, 39, -13, 12, 9, -13, 3, 39, -38, -5, 2, 8, -32, 12, 39, 3, 39, 11, 9, -13, 21, 39, 3, 39, 11, 9, 22, 39, 5, 39, 7, 9, -36, 23, 39, 6, 39, 5, 9, -36, 24, 39, 8, 39, 3, 9, 25, 39, -120, 2}; 49 | 50 | unsigned const char boss_palette[40][3] = { { 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF }, { 0x2D, 0x29, 0x52 }, { 0x3D, 0x39, 0x57 }, { 0x36, 0x2D, 0x59 }, { 0x2E, 0x2D, 0x32 }, { 0x6C, 0x56, 0x96 }, { 0x83, 0x6B, 0xAA }, { 0x7A, 0x77, 0x7F }, { 0x0D, 0x0C, 0x0E }, { 0x2C, 0x14, 0x40 }, { 0x16, 0x13, 0x17 }, { 0xB7, 0xB1, 0xB8 }, { 0x13, 0x10, 0x13 }, { 0x29, 0x39, 0x59 }, { 0x35, 0x48, 0x6D }, { 0x43, 0x59, 0x84 }, { 0x26, 0x34, 0x51 }, { 0x2F, 0x3F, 0x60 }, { 0x3D, 0x50, 0x78 }, { 0x4E, 0x62, 0x8E }, { 0x59, 0x6C, 0x97 }, { 0x62, 0x75, 0x9F }, { 0x6D, 0x80, 0xA8 }, { 0x21, 0x2E, 0x4D }, { 0x7E, 0x8C, 0xAE }, { 0x1F, 0x26, 0x39 }, { 0x12, 0x18, 0x2A }, { 0x37, 0x42, 0x64 }, { 0x24, 0x2B, 0x43 }, { 0x1B, 0x1E, 0x30 }, { 0x37, 0x39, 0x44 }, { 0x56, 0x59, 0x6C }, { 0x51, 0x56, 0x7F }, { 0x47, 0x4A, 0x65 }, { 0x0F, 0x0F, 0x1E }, { 0x0C, 0x0C, 0x14 }, { 0x30, 0x30, 0x4C }, { 0x1A, 0x1A, 0x21 }, { 0x27, 0x27, 0x27 } }; 51 | 52 | const signed char compressed_boss2[662] = {-120, 7, 9, 39, -3, 2, 6, -9, -4, -5, 3, 11, -6, -3, 16, 39, 7, 39, 2, 5, -13, -4, -5, 2, 13, -9, -37, -17, -29, -26, -19, -24, -27, -33, -29, 12, 39, 4, 39, -9, -13, -17, 3, 11, -13, -10, -3, -24, -3, -31, -30, -20, -21, -20, -19, -24, -31, 2, 27, -29, -26, 9, 39, 3, 39, -4, -16, -15, -11, -15, 2, 17, -14, -7, -24, -12, -31, -23, -38, -19, -22, -20, -25, 5, 35, -31, -33, -29, -15, 6, 39, 2, 39, -6, -5, -15, 2, 11, -8, 2, 17, -13, -12, -20, -10, -29, 2, 26, -30, -20, -21, -25, 3, 35, 2, 31, -35, -23, -31, -33, 6, 39, -39, -32, -5, -17, 4, 11, 2, 17, -13, -12, -21, -6, -25, -36, -15, -34, -19, -20, 2, 19, -24, -25, -26, -25, 2, 33, -29, -27, -25, -37, 4, 39, -39, -5, 2, 13, 4, 11, 3, 17, -25, -18, -27, -30, -38, -14, -34, -20, 3, 19, -20, -30, -25, -33, 2, 36, -30, -31, 2, 30, 2, 29, 2, 39, -39, -5, -13, -17, -15, 3, 11, -13, -14, -13, -26, -22, -32, -24, -27, -16, -15, -19, -24, 3, 21, -24, -25, -27, 2, 36, -17, -36, -25, -35, -30, -33, -29, 1, 39, -3, -7, -4, -13, -11, 2, 17, 4, 13, -10, 2, 18, 2, 21, -37, -14, 4, 22, -21, -32, -31, -33, -37, -26, -37, -26, -38, 2, 30, -25, -30, 1, 39, -7, -6, -7, -13, -11, -17, -5, -13, -5, -4, -13, -36, -32, 2, 18, -21, -16, -8, -31, -18, 3, 21, -27, -33, -23, -29, -37, -29, -37, -38, -27, -30, 3, 25, 2, 7, -6, -7, -10, -13, -10, -9, -4, -13, -14, -13, -28, -21, -24, -33, -34, -23, -20, -36, 2, 32, -22, -27, -31, -32, -37, -29, -37, 2, 38, -35, -25, -38, 2, 25, -5, -10, -6, -12, -10, -7, 2, 10, -4, -14, -16, -13, -32, -20, -30, -23, 2, 37, -21, -33, -27, -24, -32, -31, -23, -32, -26, 2, 37, -36, -25, -35, -30, -25, -30, 1, 27, -5, -25, -3, -6, -7, 3, 10, -4, -14, -15, -36, -18, 2, 30, -26, -37, -29, -20, -21, 3, 24, -30, -35, -23, 2, 17, -36, -30, 2, 28, -31, -27, -28, 1, 39, -10, -6, -3, -12, 3, 10, -6, -14, 2, 16, -9, -22, -6, -23, -34, -16, -29, -20, -21, -20, -24, -32, -31, -30, -27, 4, 23, -33, -27, -31, 2, 23, 1, 39, -39, -19, -3, -7, 2, 6, -9, -10, 3, 16, -26, -22, -9, -28, -29, -37, -33, -22, -18, 3, 32, -28, -31, 2, 33, -31, -33, 2, 30, 2, 25, -26, 2, 39, -39, 2, 3, -10, 2, 26, -9, -5, 2, 16, -15, -10, -18, -25, -28, -30, -29, -28, -22, -21, 2, 28, -32, 4, 28, 3, 23, -33, 5, 39, -39, -3, -26, -6, 2, 9, -14, 3, 16, -15, -13, -28, -20, -27, -29, -28, -18, -22, -27, 2, 32, 4, 28, 3, 23, 7, 39, 2, 39, 2, 6, -9, -5, -4, 3, 16, 2, 11, -26, -30, -29, -33, -13, -23, -21, 3, 32, 2, 28, -23, 2, 33, 9, 39, 2, 39, -2, 2, 6, -5, -4, -16, -17, -16, 2, 15, 2, 16, -37, -34, -17, -32, -20, -32, 2, 28, -35, -31, 2, 33, 10, 39, 3, 39, -3, -9, -4, -16, -34, -14, -16, -15, -11, 4, 15, -34, -23, -24, -31, -35, 2, 31, 2, 33, 11, 39, 4, 39, 2, 6, -4, -9, -4, -14, -16, 2, 15, -11, -15, 2, 11, -13, -36, -6, -27, -31, -33, 13, 39, 5, 39, -3, -4, -6, 2, 4, -9, -14, -17, -11, -8, -11, -16, -33, -30, -25, -32, -28, 14, 39, 8, 39, -2, -3, -6, 2, 4, -5, -17, -36, 2, 38, -24, -32, 16, 39, -120, 6}; 53 | 54 | unsigned const char boss2_palette[40][3] = { { 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF }, { 0x4A, 0x6E, 0x81 }, { 0x35, 0x5B, 0x78 }, { 0x25, 0x3C, 0x4F }, { 0x19, 0x33, 0x4A }, { 0x2C, 0x4B, 0x68 }, { 0x18, 0x37, 0x57 }, { 0x0A, 0x13, 0x1D }, { 0x2D, 0x44, 0x5D }, { 0x24, 0x3F, 0x60 }, { 0x10, 0x1C, 0x2B }, { 0x1B, 0x3B, 0x67 }, { 0x18, 0x2A, 0x46 }, { 0x25, 0x32, 0x47 }, { 0x1B, 0x23, 0x30 }, { 0x21, 0x2B, 0x3C }, { 0x16, 0x23, 0x3D }, { 0x74, 0x8F, 0xC4 }, { 0x3A, 0x56, 0x92 }, { 0x5A, 0x77, 0xB4 }, { 0x65, 0x84, 0xC4 }, { 0x7B, 0x97, 0xD5 }, { 0x63, 0x72, 0x9B }, { 0x53, 0x67, 0xA4 }, { 0x42, 0x51, 0x80 }, { 0x3C, 0x49, 0x70 }, { 0x52, 0x62, 0x94 }, { 0x6B, 0x7A, 0xA7 }, { 0x57, 0x62, 0x85 },{ 0x4C, 0x5A, 0x8A }, { 0x5B, 0x69, 0x99 }, { 0x70, 0x7F, 0xB4 }, { 0x5C, 0x68, 0x92 }, { 0x3A, 0x41, 0x58 }, { 0x62, 0x6D, 0xA3 }, { 0x24, 0x2C, 0x56 }, { 0x4F, 0x54, 0x73 }, { 0x2B, 0x31, 0x6E }, { 0x27, 0x27, 0x27 } }; 55 | -------------------------------------------------------------------------------- /src/space.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "space.h" 3 | #include 4 | #include 5 | 6 | #if __WIIU__ 7 | // for __os_snprintf and OSFatal 8 | #include 9 | #include 10 | #else 11 | #include 12 | #include 13 | #include "switch/platform.h" 14 | #endif 15 | 16 | /** 17 | This class is a bit of a mess, but it basically does "everything else" in the game. 18 | The most interesting function is rotating the bitmap (makeRotationMatrix). 19 | 20 | Other things it handles: 21 | - Joystick input (p1Move) 22 | - Bullet firing (p1Shoot) 23 | - Star drawing (renderStars) 24 | - Status bar drawing (renderTexts) 25 | - Decompressing sprites (decompress_bitmap) 26 | - Handling the menu at the title screen (doMenuAction) 27 | 28 | It relies heavily on a SpaceGlobals struct defined in space.h. This is a carry over from the libwiiu 29 | pong example, but also I believe necesary since global variables don't seem to be able to be set(?) 30 | **/ 31 | 32 | #define xMinBoundry 0 33 | #define xMaxBoundry 427 34 | #define yMinBoundry 0 35 | #define yMaxBoundry 240 36 | 37 | void blackout() 38 | { 39 | fillScreen(0,0,0,0); 40 | } 41 | 42 | void increaseScore(struct SpaceGlobals* mySpaceGlobals, int inc) 43 | { 44 | // count the number of 5000s that fit into the score before adding 45 | int fiveThousandsBefore = mySpaceGlobals->score / 5000; 46 | 47 | // increase the score 48 | mySpaceGlobals->score += inc; 49 | 50 | // count them again 51 | int fiveThousandsAfter = mySpaceGlobals->score / 5000; 52 | 53 | // if it increased, levelup 54 | if (fiveThousandsAfter > fiveThousandsBefore) 55 | { 56 | mySpaceGlobals->level ++; 57 | } 58 | } 59 | 60 | void p1Shoot(struct SpaceGlobals * mySpaceGlobals) 61 | { 62 | if (mySpaceGlobals->playerExplodeFrame > 1) 63 | return; 64 | 65 | bool shoot = false; 66 | float sensitivity = 0.1f; 67 | 68 | float xdif = 0; 69 | float ydif = 0; 70 | 71 | if ((fabs(mySpaceGlobals->rstick.x) > sensitivity) || (fabs(mySpaceGlobals->rstick.y) > sensitivity)) 72 | { 73 | shoot = true; 74 | if (fabs(mySpaceGlobals->rstick.x) > sensitivity) 75 | xdif = mySpaceGlobals->p1X - (mySpaceGlobals->p1X + (mySpaceGlobals->rstick.x * 18)); 76 | if (fabs(mySpaceGlobals->rstick.y) > sensitivity) 77 | ydif = mySpaceGlobals->p1Y - (mySpaceGlobals->p1Y - (mySpaceGlobals->rstick.y * 18)); 78 | } 79 | else if (mySpaceGlobals->touched) { 80 | shoot = true; 81 | xdif = mySpaceGlobals->p1X - mySpaceGlobals->touchX + 18; 82 | ydif = mySpaceGlobals->p1Y - mySpaceGlobals->touchY + 18; 83 | } 84 | if(shoot) { 85 | mySpaceGlobals->angle = atan2(xdif, ydif); 86 | 87 | //activateBullet(mySpaceGlobals, mySpaceGlobals->angle - 3.14159265, mySpaceGlobals->p1X, mySpaceGlobals->p1Y); 88 | // shoot a bullet 89 | // find an inactive bullet 90 | float theta = mySpaceGlobals->angle - 3.14159265; 91 | int xx; 92 | for (xx=0; xx<20; xx++) 93 | { 94 | if (mySpaceGlobals->bullets[xx].active != 1) 95 | { 96 | mySpaceGlobals->bullets[xx].x = mySpaceGlobals->p1X + 18; 97 | mySpaceGlobals->bullets[xx].y = mySpaceGlobals->p1Y + 18; 98 | mySpaceGlobals->bullets[xx].m_x = 9*sin(theta); // 9 is the desired bullet speed 99 | mySpaceGlobals->bullets[xx].m_y = 9*cos(theta); // we have to solve for the hypotenuese 100 | mySpaceGlobals->bullets[xx].active = 1; 101 | mySpaceGlobals->firstShotFired = 1; 102 | if (mySpaceGlobals->score >= 1000) 103 | mySpaceGlobals->displayHowToPlay = 0; 104 | break; 105 | } 106 | } 107 | } 108 | 109 | moveBullets(mySpaceGlobals); 110 | } 111 | 112 | //Updates player1 location 113 | void p1Move(struct SpaceGlobals *mySpaceGlobals) { 114 | 115 | // can't move while exploding 116 | if (mySpaceGlobals->playerExplodeFrame > 1) 117 | return; 118 | 119 | // Handle analog stick movements 120 | VPADVec2D left = mySpaceGlobals->lstick; 121 | //Vec2D right = mySpaceGlobals->rstick; 122 | 123 | // get the differences 124 | //float xdif = left.x + right.x; 125 | //float ydif = left.y + right.y; 126 | // TODO: right handed controls 127 | float xdif = left.x; 128 | float ydif = left.y; 129 | 130 | // Handle D-pad movements as well 131 | // max out speed at 1 or -1 in both directions 132 | xdif = (xdif > 1 || mySpaceGlobals->button & VPAD_BUTTON_RIGHT)? 1 : xdif; 133 | xdif = (xdif < -1 || mySpaceGlobals->button & VPAD_BUTTON_LEFT)? -1 : xdif; 134 | ydif = (ydif > 1 || mySpaceGlobals->button & VPAD_BUTTON_UP)? 1 : ydif; 135 | ydif = (ydif < -1 || mySpaceGlobals->button & VPAD_BUTTON_DOWN)? -1 : ydif; 136 | 137 | // don't update angle if both are within -.1 < x < .1 138 | // (this is an expenesive check... 128 bytes compared to just ==0) 139 | if (xdif < 0.1 && xdif > -0.1 && ydif < 0.1 && ydif > -0.1) return; 140 | 141 | // invalid view 142 | mySpaceGlobals->invalid = 1; 143 | 144 | // accept x and y movement from either stick 145 | mySpaceGlobals->p1X += xdif*5; 146 | mySpaceGlobals->p1Y -= ydif*5; 147 | 148 | // calculate angle to face 149 | mySpaceGlobals->angle = atan2(ydif, xdif) - 3.14159265/2; 150 | 151 | // update score if on a frame divisible by 60 (gain 10 points every second) 152 | if (mySpaceGlobals->frame % 60 == 0) 153 | { 154 | increaseScore(mySpaceGlobals, 10); 155 | 156 | // if the score is at least 50 and a shot hasn't been fired yet, display a message about shooting 157 | if (mySpaceGlobals->score >= 50 && !mySpaceGlobals->firstShotFired) 158 | mySpaceGlobals->displayHowToPlay = 1; 159 | } 160 | 161 | }; 162 | 163 | void checkPause(struct SpaceGlobals * mySpaceGlobals) 164 | { 165 | if (mySpaceGlobals->button & VPAD_BUTTON_PLUS) 166 | { 167 | // switch to the pause state and mark view as invalid 168 | mySpaceGlobals->state = 3; 169 | mySpaceGlobals->invalid = 1; 170 | } 171 | } 172 | 173 | void handleCollisions(struct SpaceGlobals * mySpaceGlobals) 174 | { 175 | int playerLeft = mySpaceGlobals->p1X; 176 | int playerRight = playerLeft + 36; 177 | int playerUp = mySpaceGlobals->p1Y; 178 | int playerDown = playerUp + 36; 179 | 180 | // don't let the player go offscreen 181 | if (playerLeft < xMinBoundry) 182 | mySpaceGlobals->p1X = xMinBoundry; 183 | if (playerRight > xMaxBoundry) 184 | mySpaceGlobals->p1X = xMaxBoundry - 36; 185 | if (playerUp < yMinBoundry + 20) 186 | mySpaceGlobals->p1Y = yMinBoundry + 20; 187 | if (playerDown > yMaxBoundry) 188 | mySpaceGlobals->p1Y = yMaxBoundry - 36; 189 | 190 | // check enemies if they collide with the player or any of the 20 active bullets 191 | int x; 192 | for (x=0; x<100; x++) 193 | { 194 | if (mySpaceGlobals->enemies[x].position.active == 1) 195 | { 196 | // collision checkin from here: http://stackoverflow.com/a/1736741/1137828 197 | // check player 198 | 199 | int sqMe1 = ((mySpaceGlobals->enemies[x].position.x+7)-(mySpaceGlobals->p1X+9)); 200 | int sqMe2 = ((mySpaceGlobals->enemies[x].position.y+7)-(mySpaceGlobals->p1Y+9)); 201 | 202 | if (sqMe1*sqMe1 + sqMe2*sqMe2 <= (7+9)*(7+9)) 203 | { 204 | if (mySpaceGlobals->playerExplodeFrame < 1) 205 | { 206 | // player was hit 207 | mySpaceGlobals->playerExplodeFrame = 2; 208 | initGameState(mySpaceGlobals); 209 | } 210 | } 211 | 212 | int y; 213 | for (y=0; y<20; y++) 214 | { 215 | if (mySpaceGlobals->bullets[y].active == 1) 216 | { 217 | // check player's bullets 218 | sqMe1 = ((mySpaceGlobals->enemies[x].position.x+7)-(mySpaceGlobals->bullets[y].x+1)); 219 | sqMe2 = ((mySpaceGlobals->enemies[x].position.y+7)-(mySpaceGlobals->bullets[y].y+1)); 220 | 221 | if (sqMe1*sqMe1 + sqMe2*sqMe2 <= (7+1)*(7+1)) 222 | { 223 | // enemy was hit, active = 2 is explode 224 | increaseScore(mySpaceGlobals, 100); // 100 points for killing enemy 225 | mySpaceGlobals->enemies[x].position.active = 2; 226 | 227 | // bullet is destroyed with enemy 228 | mySpaceGlobals->bullets[y].active = 0; 229 | 230 | break; 231 | } 232 | } 233 | } 234 | } 235 | } 236 | 237 | } 238 | 239 | void makeScaleMatrix(int frame, int width, void *orig, void *targ, int transIndex) 240 | { 241 | unsigned char (*original)[width] = (unsigned char (*)[width])(orig); 242 | unsigned char (*target)[width] = (unsigned char (*)[width])(targ); 243 | int x; 244 | for (x=0; x= width) continue; 266 | if (newy < 0 || newy >= width) continue; 267 | 268 | target[newx][newy] = original[x][y]; 269 | } 270 | } 271 | 272 | } 273 | 274 | void handleExplosions(struct SpaceGlobals* mySpaceGlobals) 275 | { 276 | int x; 277 | for (x=0; x<100; x++) 278 | { 279 | if (mySpaceGlobals->enemies[x].position.active > 1) 280 | { 281 | makeScaleMatrix(mySpaceGlobals->enemies[x].position.active/2.0, 23, mySpaceGlobals->enemy, mySpaceGlobals->enemies[x].rotated_sprite, 9); 282 | mySpaceGlobals->enemies[x].position.active ++; 283 | 284 | if (mySpaceGlobals->enemies[x].position.active > 20) 285 | mySpaceGlobals->enemies[x].position.active = 0; 286 | } 287 | } 288 | 289 | if (mySpaceGlobals->playerExplodeFrame > 1) 290 | { 291 | makeScaleMatrix(mySpaceGlobals->playerExplodeFrame, 36, mySpaceGlobals->orig_ship, mySpaceGlobals->rotated_ship, mySpaceGlobals->transIndex); 292 | mySpaceGlobals->playerExplodeFrame ++; 293 | mySpaceGlobals->invalid = 1; 294 | 295 | if (mySpaceGlobals->playerExplodeFrame > 20) 296 | { 297 | mySpaceGlobals->playerExplodeFrame = 0; 298 | mySpaceGlobals->lives --; 299 | if (mySpaceGlobals->lives <= 0) 300 | { 301 | // game over! 302 | mySpaceGlobals->state = 4; 303 | mySpaceGlobals->invalid = 1; 304 | } 305 | else 306 | mySpaceGlobals->renderResetFlag = 1; 307 | } 308 | } 309 | } 310 | 311 | void makeRotationMatrix(float angle, int width, void *orig, void *targ, int transIndex) 312 | { 313 | unsigned char (*original)[width] = (unsigned char (*)[width])(orig); 314 | unsigned char (*target)[width] = (unsigned char (*)[width])(targ); 315 | 316 | int x; 317 | for (x=0; x= width) continue; 346 | if (oldy < 0 || oldy >= width) continue; 347 | 348 | // TODO: crashes with this below line! When trying to assign to target, but only after doing the above math 349 | target[ix][iy] = original[oldx][oldy]; 350 | } 351 | } 352 | } 353 | 354 | void renderEnemies(struct SpaceGlobals *mySpaceGlobals) 355 | { 356 | // for all active bullets, advance them 357 | int x=0; 358 | for (x=0; x<20; x++) 359 | { 360 | if (mySpaceGlobals->bullets[x].active == 1) 361 | { 362 | 363 | int z, za; 364 | for (z=0; z<4; z++) 365 | for (za=0; za<2; za++) 366 | drawPixel(mySpaceGlobals->bullets[x].x + z, mySpaceGlobals->bullets[x].y + za, 255, 0, 0); 367 | } 368 | } 369 | 370 | // for all active enemies, advance them 371 | for (x=0; x<100; x++) // up to 100 enemies at once 372 | { 373 | if (mySpaceGlobals->enemies[x].position.active >= 1) 374 | { 375 | drawBitmap(mySpaceGlobals->enemies[x].position.x, mySpaceGlobals->enemies[x].position.y, 23, 23, mySpaceGlobals->enemies[x].rotated_sprite, enemy_palette); 376 | } 377 | } 378 | } 379 | 380 | void render(struct SpaceGlobals *mySpaceGlobals) 381 | { 382 | if (mySpaceGlobals->invalid == 1) 383 | { 384 | blackout(); 385 | 386 | mySpaceGlobals->frame++; 387 | 388 | if (mySpaceGlobals->renderResetFlag) 389 | { 390 | renderReset(mySpaceGlobals); 391 | } 392 | 393 | renderStars(mySpaceGlobals); 394 | renderEnemies(mySpaceGlobals); 395 | renderShip(mySpaceGlobals); 396 | renderTexts(mySpaceGlobals); 397 | 398 | flipBuffers(); 399 | mySpaceGlobals->invalid = 0; 400 | } 401 | } 402 | 403 | // see the notes in images.c for more info on how this works 404 | void decompress_sprite(int arraysize, int width, int height, const signed char* input, void *targ, char transIndex) 405 | { 406 | unsigned char (*target)[width] = (unsigned char (*)[width])(targ); 407 | int cx = 0, cy = 0; 408 | int x; 409 | int posinrow = 0; 410 | // go through input array 411 | for (x=0; x= width) 447 | { 448 | posinrow = 0; 449 | cx = 0; 450 | cy++; 451 | } 452 | } 453 | } 454 | 455 | void moveBullets(struct SpaceGlobals *mySpaceGlobals) 456 | { 457 | // for all active bullets, advance them 458 | int x=0; 459 | for (x=0; x<20; x++) 460 | { 461 | if (mySpaceGlobals->bullets[x].active == 1) 462 | { 463 | mySpaceGlobals->bullets[x].x += mySpaceGlobals->bullets[x].m_x; 464 | mySpaceGlobals->bullets[x].y += mySpaceGlobals->bullets[x].m_y; 465 | 466 | if (mySpaceGlobals->bullets[x].x > xMaxBoundry || 467 | mySpaceGlobals->bullets[x].x < xMinBoundry || 468 | mySpaceGlobals->bullets[x].y > yMaxBoundry || 469 | mySpaceGlobals->bullets[x].y < yMinBoundry + 20) 470 | mySpaceGlobals->bullets[x].active = 0; 471 | 472 | mySpaceGlobals->invalid = 1; 473 | } 474 | 475 | } 476 | 477 | for (x=0; x<100; x++) 478 | { 479 | if (mySpaceGlobals->enemies[x].position.active == 1) 480 | { 481 | mySpaceGlobals->enemies[x].position.x += mySpaceGlobals->enemies[x].position.m_x; 482 | mySpaceGlobals->enemies[x].position.y += mySpaceGlobals->enemies[x].position.m_y; 483 | 484 | if (mySpaceGlobals->enemies[x].position.x > xMaxBoundry || 485 | mySpaceGlobals->enemies[x].position.x < xMinBoundry || 486 | mySpaceGlobals->enemies[x].position.y > yMaxBoundry || 487 | mySpaceGlobals->enemies[x].position.y < yMinBoundry + 20) 488 | mySpaceGlobals->enemies[x].position.active = 0; 489 | 490 | // rotate the enemy slowly 491 | mySpaceGlobals->enemies[x].angle += 0.02f; 492 | if (mySpaceGlobals->enemies[x].angle > 6.28318530f) 493 | mySpaceGlobals->enemies[x].angle = 0.0f; 494 | 495 | // int targetAngle = mySpaceGlobals->enemies[x].angle; 496 | 497 | // TODO: the below crashes... with angle instead of 0 498 | makeRotationMatrix(mySpaceGlobals->enemies[x].angle, 23, mySpaceGlobals->enemy, mySpaceGlobals->enemies[x].rotated_sprite, 9); 499 | // makeScaleMatrix(3, 23, mySpaceGlobals->enemy, mySpaceGlobals->enemies[x].rotated_sprite, 9); 500 | 501 | mySpaceGlobals->invalid = 1; 502 | } 503 | } 504 | } 505 | 506 | void renderTexts(struct SpaceGlobals *mySpaceGlobals) 507 | { 508 | fillRect(0, 0, xMaxBoundry, 20, 0, 0, 0); 509 | 510 | char score[255]; 511 | if (mySpaceGlobals->dontKeepTrackOfScore == 1) 512 | __os_snprintf(score, 255, "Score: N/A"); 513 | else 514 | __os_snprintf(score, 255, "Score: %09d", mySpaceGlobals->score); 515 | drawString(0, -1, score); 516 | drawStringTv(0, -1, score); 517 | 518 | char level[255]; 519 | __os_snprintf(level, 255, "Lv %d", mySpaceGlobals->level+1); 520 | drawString(30, -1, level); 521 | drawStringTv(51, -1, level); 522 | 523 | char lives[255]; 524 | __os_snprintf(lives, 255, "Lives: %d", mySpaceGlobals->lives); 525 | drawString(55, -1, lives); 526 | drawStringTv(90, -1, lives); 527 | 528 | if (mySpaceGlobals->displayHowToPlay) 529 | { 530 | char nag[255]; 531 | __os_snprintf(nag, 255, "Touch and hold on the screen to rapid fire!"); 532 | drawString(20, 17, nag); 533 | drawStringTv(56, 27, nag); 534 | } 535 | 536 | } 537 | 538 | void renderShip(struct SpaceGlobals *mySpaceGlobals) 539 | { 540 | const int posx = (int)mySpaceGlobals->p1X; 541 | const int posy = (int)mySpaceGlobals->p1Y; 542 | 543 | if (mySpaceGlobals->playerExplodeFrame < 2) 544 | makeRotationMatrix(mySpaceGlobals->angle, 36, mySpaceGlobals->orig_ship, mySpaceGlobals->rotated_ship, mySpaceGlobals->transIndex); 545 | 546 | drawBitmap(posx, posy, 36, 36, mySpaceGlobals->rotated_ship, mySpaceGlobals->curPalette); 547 | 548 | } 549 | 550 | void renderStars(struct SpaceGlobals *mySpaceGlobals) 551 | { 552 | // don't draw stars if the player is on their last life and died 553 | if (mySpaceGlobals->lives == 1 && mySpaceGlobals->playerExplodeFrame > 1) 554 | return; 555 | 556 | drawPixels(mySpaceGlobals->stars); 557 | } 558 | 559 | //Reset the game 560 | void reset(struct SpaceGlobals *mySpaceGlobals) { 561 | mySpaceGlobals->button = 0; 562 | 563 | //Set flag to render reset screen; 564 | mySpaceGlobals->renderResetFlag = 1; 565 | 566 | }; 567 | 568 | void initGameState(struct SpaceGlobals *mySpaceGlobals) 569 | { 570 | // init bullets 571 | int x; 572 | for (x=0; x<20; x++) 573 | { 574 | mySpaceGlobals->bullets[x].active = 0; 575 | } 576 | 577 | // init x and y pos of player 578 | // mySpaceGlobals->p1X = 40; 579 | // mySpaceGlobals->p1Y = 150; 580 | 581 | // init enemies 582 | for (x=0; x<100; x++) 583 | { 584 | mySpaceGlobals->enemies[x].position.active = 0; 585 | mySpaceGlobals->enemies[x].angle = 3.14f; 586 | makeRotationMatrix(0, 23, mySpaceGlobals->enemy, mySpaceGlobals->enemies[x].rotated_sprite, 9); 587 | } 588 | 589 | } 590 | 591 | void initStars(struct SpaceGlobals *mySpaceGlobals) 592 | { 593 | // create the stars randomly 594 | int x; 595 | for (x=0; x<200; x++) 596 | { 597 | mySpaceGlobals->stars[x].x = (int)(rand()*xMaxBoundry); 598 | mySpaceGlobals->stars[x].y = (int)(rand()*yMaxBoundry); 599 | int randomNum = (int)(rand()*4); 600 | 601 | // half of the time make them white, 1/4 yellow, 1/4 blue 602 | mySpaceGlobals->stars[x].r = (randomNum <= 2)? 255 : 0; 603 | mySpaceGlobals->stars[x].g = (randomNum <= 2)? 255 : 0; 604 | mySpaceGlobals->stars[x].b = (randomNum != 2)? 255 : 0; 605 | } 606 | } 607 | 608 | void displayTitle(struct SpaceGlobals * mySpaceGlobals) 609 | { 610 | if (mySpaceGlobals->invalid == 1) 611 | { 612 | blackout(); 613 | 614 | // draw some stars 615 | renderStars(mySpaceGlobals); 616 | 617 | // display the bitmap in upper center screen 618 | drawBitmap(107, 30, 200, 100, mySpaceGlobals->title, title_palette); 619 | 620 | char credits[255]; 621 | __os_snprintf(credits, 255, "by vgmoose"); 622 | 623 | char musiccredits[255]; 624 | __os_snprintf(musiccredits, 255, "~*cruise*~ by (T-T)b"); 625 | 626 | char license[255]; 627 | __os_snprintf(license, 255, "MIT License"); 628 | 629 | char play[255]; 630 | __os_snprintf(play, 255, "Start Game"); 631 | char password[255]; 632 | __os_snprintf(password, 255, "Password"); 633 | 634 | //display the menu under it 635 | drawString(37, 9, credits); 636 | drawStringTv(62, 14, credits); 637 | drawString(25, 12, play); 638 | drawStringTv(44, 17, play); 639 | drawString(26, 13, password); 640 | drawStringTv(45, 18, password); 641 | 642 | drawString(45, 17, musiccredits); 643 | drawStringTv(80, 27, musiccredits); 644 | drawString(-2, 17, license); 645 | drawStringTv(-2, 27, license); 646 | 647 | drawMenuCursor(mySpaceGlobals); 648 | 649 | flipBuffers(); 650 | mySpaceGlobals->invalid = 0; 651 | } 652 | 653 | } 654 | 655 | void drawMenuCursor(struct SpaceGlobals *mySpaceGlobals) 656 | { 657 | // cover up any old cursors (used to be needed before changing to draw everything mode) 658 | // fillRect(155, 155, 16, 30, 0, 0, 0); 659 | // fillRect(240, 155, 16, 30, 0, 0, 0); 660 | 661 | // display the cursor on the correct item 662 | char cursor[255]; 663 | __os_snprintf(cursor, 255, ">> <<"); 664 | drawString(22, 12 + mySpaceGlobals->menuChoice, cursor); 665 | drawStringTv(41, 17 + mySpaceGlobals->menuChoice, cursor); 666 | } 667 | 668 | void doMenuAction(struct SpaceGlobals *mySpaceGlobals) 669 | { 670 | // if we've seen the A button not being pressed 671 | if (!(mySpaceGlobals->button & VPAD_BUTTON_A)) 672 | { 673 | mySpaceGlobals->allowInput = 1; 674 | } 675 | 676 | if (mySpaceGlobals->button & VPAD_BUTTON_A && mySpaceGlobals->allowInput) 677 | { 678 | // if we're on the title menu 679 | if (mySpaceGlobals->state == 1) 680 | { 681 | if (mySpaceGlobals->menuChoice == 0) 682 | { 683 | totallyRefreshState(mySpaceGlobals); 684 | 685 | // start game chosen 686 | mySpaceGlobals->state = 7; // switch to game state 687 | mySpaceGlobals->renderResetFlag = 1; // redraw screen 688 | } 689 | else if (mySpaceGlobals->menuChoice == 1) 690 | { 691 | // password screen chosen 692 | mySpaceGlobals->state = 2; 693 | } 694 | } 695 | // password screen 696 | // else if (mySpaceGlobals->state == 2) 697 | // { 698 | // // this is handled by the password menu action function 699 | // } 700 | // pause screen 701 | else if (mySpaceGlobals->state == 3) 702 | { 703 | if (mySpaceGlobals->menuChoice == 0) 704 | { 705 | // resume chosen 706 | mySpaceGlobals->state = 7; // switch to game state 707 | 708 | } 709 | else if (mySpaceGlobals->menuChoice == 1) 710 | { 711 | // quit chosen 712 | totallyRefreshState(mySpaceGlobals); 713 | mySpaceGlobals->state = 1; 714 | } 715 | } 716 | // game over screen 717 | else if (mySpaceGlobals->state == 4) 718 | { 719 | totallyRefreshState(mySpaceGlobals); 720 | 721 | if (mySpaceGlobals->menuChoice == 0) 722 | { 723 | // try again chosen 724 | 725 | //player stays on the same level 726 | mySpaceGlobals->state = 7; // switch to game state 727 | 728 | } 729 | else if (mySpaceGlobals->menuChoice == 1) 730 | { 731 | // quit chosen 732 | mySpaceGlobals->state = 1; 733 | } 734 | } 735 | 736 | // reset the choice 737 | mySpaceGlobals->menuChoice = 0; 738 | 739 | // disable menu input after selecting to prevent double selects 740 | mySpaceGlobals->allowInput = 0; 741 | 742 | // mark view invalid to redraw 743 | mySpaceGlobals->invalid = 1; 744 | } 745 | 746 | float stickY = mySpaceGlobals->lstick.y + mySpaceGlobals->rstick.y; 747 | 748 | if (mySpaceGlobals->button & VPAD_BUTTON_DOWN || stickY < -0.3) 749 | { 750 | mySpaceGlobals->menuChoice = 1; 751 | mySpaceGlobals->invalid = 1; 752 | } 753 | 754 | if (mySpaceGlobals->button & VPAD_BUTTON_UP || stickY > 0.3) 755 | { 756 | mySpaceGlobals->menuChoice = 0; 757 | mySpaceGlobals->invalid = 1; 758 | } 759 | } 760 | 761 | void displayPause(struct SpaceGlobals * mySpaceGlobals) 762 | { 763 | if (mySpaceGlobals->invalid == 1) 764 | { 765 | blackout(); 766 | 767 | // display the password here 768 | char resume[255]; 769 | __os_snprintf(resume, 255, "Resume"); 770 | char quit[255]; 771 | __os_snprintf(quit, 255, "Quit"); 772 | 773 | drawString(27, 12, resume); 774 | drawStringTv(46, 17, resume); 775 | drawString(28, 13, quit); 776 | drawStringTv(47, 18, quit); 777 | 778 | drawMenuCursor(mySpaceGlobals); 779 | 780 | flipBuffers(); 781 | mySpaceGlobals->invalid = 0; 782 | } 783 | } 784 | 785 | void doPasswordMenuAction(struct SpaceGlobals * mySpaceGlobals) 786 | { 787 | // if we've seen up, down, left, right, and a buttons not being pressed 788 | if (!(mySpaceGlobals->button & VPAD_BUTTON_A || 789 | mySpaceGlobals->button & VPAD_BUTTON_UP || 790 | mySpaceGlobals->button & VPAD_BUTTON_DOWN || 791 | mySpaceGlobals->button & VPAD_BUTTON_LEFT || 792 | mySpaceGlobals->button & VPAD_BUTTON_RIGHT )) 793 | { 794 | mySpaceGlobals->allowInput = 1; 795 | } 796 | if (mySpaceGlobals->allowInput) 797 | { 798 | if (mySpaceGlobals->button & VPAD_BUTTON_B) 799 | { 800 | // go back to title screen 801 | mySpaceGlobals->state = 1; 802 | 803 | // update the menu choice 804 | mySpaceGlobals->menuChoice = 0; 805 | 806 | // disable menu input after selecting to prevent double selects 807 | mySpaceGlobals->allowInput = 0; 808 | 809 | // mark view invalid to redraw 810 | mySpaceGlobals->invalid = 1; 811 | } 812 | if (mySpaceGlobals->button & VPAD_BUTTON_A) 813 | { 814 | // try the password 815 | tryPassword(mySpaceGlobals); 816 | 817 | // disable menu input after selecting to prevent double selects 818 | mySpaceGlobals->allowInput = 0; 819 | 820 | // update the menu choice 821 | mySpaceGlobals->menuChoice = 0; 822 | 823 | // mark view invalid to redraw 824 | mySpaceGlobals->invalid = 1; 825 | } 826 | 827 | float stickY = mySpaceGlobals->lstick.y + mySpaceGlobals->rstick.y; 828 | float stickX = mySpaceGlobals->lstick.x + mySpaceGlobals->rstick.x; 829 | int down = (mySpaceGlobals->button & VPAD_BUTTON_DOWN || stickY < -0.3); 830 | int up = (mySpaceGlobals->button & VPAD_BUTTON_UP || stickY > 0.3); 831 | int left = (mySpaceGlobals->button & VPAD_BUTTON_LEFT || stickX < -0.3); 832 | int right = (mySpaceGlobals->button & VPAD_BUTTON_RIGHT || stickX > 0.3); 833 | 834 | if (up || down) 835 | { 836 | int offset = 1, x; 837 | // keep going up in the 10s place to match current choice 838 | for (x=0; x<(4 - mySpaceGlobals->menuChoice); x++) 839 | offset *= 10; 840 | 841 | if (up) 842 | mySpaceGlobals->passwordEntered += offset; 843 | if (down) 844 | mySpaceGlobals->passwordEntered -= offset; 845 | 846 | mySpaceGlobals->invalid = 1; 847 | mySpaceGlobals->allowInput = 0; 848 | } 849 | 850 | if (left || right) 851 | { 852 | if (right) 853 | mySpaceGlobals->menuChoice ++; 854 | if (left) 855 | mySpaceGlobals->menuChoice --;; 856 | 857 | // bound the menu choices 858 | if (mySpaceGlobals->menuChoice < 0) 859 | mySpaceGlobals->menuChoice = 0; 860 | if (mySpaceGlobals->menuChoice > 4) 861 | mySpaceGlobals->menuChoice = 4; 862 | 863 | mySpaceGlobals->invalid = 1; 864 | mySpaceGlobals->allowInput = 0; 865 | } 866 | 867 | // bound the password 868 | if (mySpaceGlobals->passwordEntered < 0) 869 | mySpaceGlobals->passwordEntered = 0; 870 | if (mySpaceGlobals->passwordEntered > 99999) 871 | mySpaceGlobals->passwordEntered = 99999; 872 | } 873 | 874 | 875 | } 876 | 877 | void displayPasswordScreen(struct SpaceGlobals * mySpaceGlobals) 878 | { 879 | if (mySpaceGlobals->invalid == 1) 880 | { 881 | blackout(); 882 | 883 | // drawPasswordMenuCursor(mySpaceGlobals); 884 | char password[255]; 885 | __os_snprintf(password, 255, "Password:"); 886 | char up_cur[255]; 887 | __os_snprintf(up_cur, 255, "v"); 888 | char cur_pw[255]; 889 | __os_snprintf(cur_pw, 255, "%05d", mySpaceGlobals->passwordEntered); 890 | char down_cur[255]; 891 | __os_snprintf(down_cur, 255, "^"); 892 | 893 | drawString(22, 8, password); 894 | drawStringTv(41, 14, password); 895 | 896 | drawString(32 + mySpaceGlobals->menuChoice, 7, up_cur); 897 | drawStringTv(51 + mySpaceGlobals->menuChoice, 13, up_cur); 898 | drawString(32, 8, cur_pw); 899 | drawStringTv(51, 14, cur_pw); 900 | drawString(32 + mySpaceGlobals->menuChoice, 9, down_cur); 901 | drawStringTv(51 + mySpaceGlobals->menuChoice, 15, down_cur); 902 | 903 | flipBuffers(); 904 | mySpaceGlobals->invalid = 0; 905 | } 906 | } 907 | 908 | void addNewEnemies(struct SpaceGlobals *mySpaceGlobals) 909 | { 910 | if (mySpaceGlobals->noEnemies || mySpaceGlobals->playerExplodeFrame > 1) 911 | return; 912 | 913 | // here we make a new enemy with a certain speed based on the level 914 | 915 | // get a random position from one of the sides with a random int 0-3 916 | int side = (int)(rand()*4); 917 | 918 | // // randomly decide to set starting angle right for the player 919 | // float seekPlayer = prand(&mySpaceGlobals->seed)*2; 920 | 921 | float difficulty = mySpaceGlobals->level/100.0; 922 | 923 | float randVal = rand(); 924 | 925 | // set the enemy count (max enemies on screen at once) based on level 926 | int enemyCount = 10 + difficulty*90*randVal; 927 | 928 | if (enemyCount > 100) enemyCount = 100; 929 | 930 | // set speed randomly within difficulty range 931 | int speed = 3 + (difficulty)*12*randVal; 932 | 933 | int startx, starty; 934 | 935 | float theta = rand()*3.14159265; 936 | randVal = rand(); 937 | 938 | // horiz size 939 | if (side < 2) 940 | { 941 | startx = (side == 0)? 0 : xMaxBoundry; 942 | starty = randVal*yMaxBoundry; 943 | 944 | if (startx != 0) 945 | theta -= 3.14159265; 946 | } 947 | else 948 | { 949 | starty = (side == 2)? 20 : yMaxBoundry; 950 | startx = randVal*xMaxBoundry; 951 | 952 | if (starty == 20) 953 | theta -= 3.14159265/2; 954 | else 955 | theta += 3.14159265/2; 956 | } 957 | 958 | // seek directly to the player 959 | if (mySpaceGlobals->enemiesSeekPlayer == 1) 960 | { 961 | float xdif = startx + 11 - (mySpaceGlobals->p1X + 18); 962 | float ydif = starty + 11 - (mySpaceGlobals->p1Y + 18); 963 | 964 | theta = atan2(xdif, ydif) - 3.14159265; 965 | } 966 | 967 | int xx; 968 | for (xx=0; xxenemies[xx].position.active == 0) 971 | { 972 | mySpaceGlobals->enemies[xx].position.x = startx; 973 | mySpaceGlobals->enemies[xx].position.y = starty; 974 | mySpaceGlobals->enemies[xx].position.m_x = speed*sin(theta); // speed is the desired enemy speed 975 | mySpaceGlobals->enemies[xx].position.m_y = speed*cos(theta); // we have to solve for the hypotenuese 976 | mySpaceGlobals->enemies[xx].position.active = 1; 977 | break; 978 | } 979 | } 980 | } 981 | 982 | void totallyRefreshState(struct SpaceGlobals *mySpaceGlobals) 983 | { 984 | initGameState(mySpaceGlobals); 985 | mySpaceGlobals->displayHowToPlay = 0; 986 | mySpaceGlobals->firstShotFired = 0; 987 | mySpaceGlobals->lives = 3; 988 | mySpaceGlobals->playerExplodeFrame = 0; 989 | mySpaceGlobals->score = 0; 990 | mySpaceGlobals->level = 0; 991 | mySpaceGlobals->dontKeepTrackOfScore = 0; 992 | mySpaceGlobals->noEnemies = 0; 993 | mySpaceGlobals->enemiesSeekPlayer = 0; 994 | } 995 | 996 | void displayGameOver(struct SpaceGlobals *mySpaceGlobals) 997 | { 998 | if (mySpaceGlobals->invalid == 1) 999 | { 1000 | blackout(); 1001 | 1002 | char gameover[255]; 1003 | __os_snprintf(gameover, 255, "Game Over!"); 1004 | drawString(25, 5, gameover); 1005 | drawStringTv(44, 10, gameover); 1006 | 1007 | // only display score + pw if the player didn't use cheats 1008 | if (mySpaceGlobals->dontKeepTrackOfScore != 1) 1009 | { 1010 | char finalscore[255]; 1011 | __os_snprintf(finalscore, 255, "Score: %08d", mySpaceGlobals->score); 1012 | char pass[255]; 1013 | __os_snprintf(pass, 255, "Lv %d Password: %05d", mySpaceGlobals->level+1, mySpaceGlobals->passwordList[mySpaceGlobals->level]); 1014 | 1015 | drawString(23, 7, finalscore); 1016 | drawStringTv(42, 12, finalscore); 1017 | drawString(21, 8, pass); 1018 | drawStringTv(40, 13, pass); 1019 | } 1020 | 1021 | 1022 | char resume[255]; 1023 | __os_snprintf(resume, 255, "Try Again"); 1024 | char quit[255]; 1025 | __os_snprintf(quit, 255, "Quit"); 1026 | 1027 | drawString(25, 12, resume); 1028 | drawStringTv(44, 17, resume); 1029 | drawString(28, 13, quit); 1030 | drawStringTv(47, 18, quit); 1031 | 1032 | drawMenuCursor(mySpaceGlobals); 1033 | 1034 | flipBuffers(); 1035 | mySpaceGlobals->invalid = 0; 1036 | } 1037 | blackout(); 1038 | 1039 | 1040 | 1041 | } 1042 | 1043 | void tryPassword(struct SpaceGlobals *mySpaceGlobals) 1044 | { 1045 | // Dear Github Viewer, 1046 | // 1047 | // Well, here's where you see the passwords I guess! 1048 | // With the exception of a few hardcoded ones, the 1049 | // level passwords are generated and checked against 1050 | // a seeded random list from program.c 1051 | // 1052 | // Enjoy! 1053 | 1054 | // Invincibility 1055 | if (mySpaceGlobals->passwordEntered == 55225) 1056 | { 1057 | mySpaceGlobals->playerExplodeFrame = 1; 1058 | mySpaceGlobals->dontKeepTrackOfScore = 1; 1059 | mySpaceGlobals->state = 7; 1060 | } 1061 | 1062 | // 99 Lives 1063 | if (mySpaceGlobals->passwordEntered == 99499) 1064 | { 1065 | mySpaceGlobals->lives = 99; 1066 | mySpaceGlobals->dontKeepTrackOfScore = 1; 1067 | mySpaceGlobals->state = 7; 1068 | } 1069 | 1070 | // No Enemies (loner mode) 1071 | if (mySpaceGlobals->passwordEntered == 82571) 1072 | { 1073 | mySpaceGlobals->noEnemies = 1; 1074 | mySpaceGlobals->dontKeepTrackOfScore = 1; 1075 | mySpaceGlobals->state = 7; 1076 | } 1077 | 1078 | // Play as original spaceship (only if changed) 1079 | if (mySpaceGlobals->passwordEntered == 00000 && mySpaceGlobals->playerChoice != 0) 1080 | { 1081 | mySpaceGlobals->playerChoice = 0; 1082 | decompress_sprite(511, 36, 36, compressed_ship, mySpaceGlobals->orig_ship, 14); 1083 | mySpaceGlobals->curPalette = ship_palette; 1084 | mySpaceGlobals->transIndex = 14; 1085 | mySpaceGlobals->state = 7; 1086 | } 1087 | 1088 | // Play as galaga ship 1089 | if (mySpaceGlobals->passwordEntered == 12345) 1090 | { 1091 | mySpaceGlobals->playerChoice = 3; 1092 | decompress_sprite(452, 36, 36, compressed_ship2, mySpaceGlobals->orig_ship, 5); 1093 | mySpaceGlobals->curPalette = ship2_palette; 1094 | mySpaceGlobals->transIndex = 5; 1095 | mySpaceGlobals->state = 7; 1096 | } 1097 | 1098 | // Play as JWittz 1099 | if (mySpaceGlobals->passwordEntered == 24177) 1100 | { 1101 | mySpaceGlobals->playerChoice = 1; 1102 | decompress_sprite(662, 36, 36, compressed_boss2, mySpaceGlobals->orig_ship, 39); 1103 | mySpaceGlobals->curPalette = boss2_palette; 1104 | mySpaceGlobals->transIndex = 39; 1105 | mySpaceGlobals->state = 7; 1106 | } 1107 | 1108 | // Play as Etika 1109 | if (mySpaceGlobals->passwordEntered == 37124) 1110 | { 1111 | mySpaceGlobals->playerChoice = 2; 1112 | decompress_sprite(740, 36, 36, compressed_boss, mySpaceGlobals->orig_ship, 39); 1113 | mySpaceGlobals->curPalette = boss_palette; 1114 | mySpaceGlobals->transIndex = 39; 1115 | mySpaceGlobals->state = 7; 1116 | } 1117 | 1118 | // Enemies come right for you (kamikaze mode) 1119 | if (mySpaceGlobals->passwordEntered == 30236) 1120 | { 1121 | mySpaceGlobals->enemiesSeekPlayer = 1; 1122 | mySpaceGlobals->dontKeepTrackOfScore = 1; 1123 | mySpaceGlobals->state = 7; 1124 | } 1125 | 1126 | // start installer for Hykem's IOSU Exploit 1127 | // Commented out due to a lack of OSFatal in WUT 1128 | if (mySpaceGlobals->passwordEntered == 41666) 1129 | { 1130 | blackout(); 1131 | OSFatal("Installing IOSU Exploit... This may take a while."); 1132 | } 1133 | 1134 | // 100 passwords, one for each level 1135 | int x; 1136 | for (x=0; x<100; x++) 1137 | { 1138 | if (mySpaceGlobals->passwordEntered == mySpaceGlobals->passwordList[x]) 1139 | { 1140 | mySpaceGlobals->level = x; 1141 | break; 1142 | } 1143 | 1144 | if (x==99) // no password was right 1145 | return; 1146 | } 1147 | 1148 | // switch to the game state 1149 | mySpaceGlobals->state = 7; 1150 | 1151 | // They are generated 1152 | } 1153 | 1154 | void renderReset(struct SpaceGlobals *mySpaceGlobals) 1155 | { 1156 | initGameState(mySpaceGlobals); 1157 | mySpaceGlobals->p1X = 200; 1158 | mySpaceGlobals->p1Y = 100; 1159 | mySpaceGlobals->renderResetFlag = 0; 1160 | mySpaceGlobals->invalid = 1; 1161 | } 1162 | 1163 | void drawControllerSelectScreen(struct SpaceGlobals *mySpaceGlobals) { 1164 | fillScreen(0, 0, 0, 255); 1165 | renderStars(mySpaceGlobals); 1166 | drawString(5, 7, "Press the A button on the controller you want to use"); 1167 | drawString(8, 10, "You can use the Wii U GamePad or any connected"); 1168 | drawString(21, 11, "Wii U Pro Controller"); 1169 | drawStringTv(23, 11, "Press the A button on the controller you want to use"); 1170 | drawStringTv(26, 14, "You can use the Wii U GamePad or any connected"); 1171 | drawStringTv(39, 15, "Wii U Pro Controller"); 1172 | flipBuffers(); 1173 | } 1174 | --------------------------------------------------------------------------------