M README => README +30 -17
@@ 7,6 7,7 @@ the GNU General Public License.
Note: I might choose to relicense the project as GPLv2 in the future. If you
submit any patches, you're agreeing that your code can be relicensed as GPLv2.
See the libremo-devel mailing list for development discussion and patch submission.
+https://lists.sr.ht/~ndiddy/libremo-devel
How to use:
1. Follow the instructions in the moexconv repository to extract all the graphics
@@ 27,24 28,16 @@ Controls are WSAD for movmement and J, K, Enter, and Esc for buttons. Note that
of the time, I hardcode the game to start in the game playing state, so if you want it to
boot from the start you can change the state variable in main.cpp to STATE_LOGO.
-Current status:
-General: Sound effects aren't implemented. X68000 sound isn't implemented. Eventually
-I would like to run Z-Music, the sound engine from the original game, in some
-sort of headless emulator in order to get accurate X68000 sound effects and music.
+Compilation note: Because Windows and Linux have different feature sets (Linux has better
+C language debugging software, and Windows has X68000 emulators with debugging support),
+I will flip-flop between them depending on what I'm doing. This might mean that at some
+points, the Makefile will not have some files, and at other points the Visual Studio project
+won't have some files. It should be easy enough to add the missing files to either of these
+depending on what platform you use.
-Intro: Mostly done, I need to implement the palette changing animation on the credits
-and figure out where the "Cyberblock" and "EX" graphics are stored in the executable.
-
-Menu: Very simplistic compared to the X68000 version, I need to make it data-driven.
-
-Tutorial screens: Mostly implemented.
-
-Cutscenes: Show background but not animation or text.
-
-Game: Hud needs work (specifically with representing powerup state). Chip doesn't move her
-mouth when the player collects a powerup. Game over and continue states aren't implemented.
-Scoring isn't accurate. The "guns" on the walls that change based on what powerup you have
-aren't implemented. The ship doesn't extend its guns when the player gets the laser powerup.
+Status:
+For current stuff to work on, look at the libremo issues tracker.
+https://todo.sr.ht/~ndiddy/libremo
Used software:
@@ 68,6 61,26 @@ freely, subject to the following restrictions:
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+sdl2_image
+----------
+Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
stb_vorbis
----------
Copyright (c) 2017 Sean Barrett
M VisualStudio/VisualStudio.vcxproj => VisualStudio/VisualStudio.vcxproj +2 -0
@@ 159,6 159,7 @@
<ClCompile Include="..\block_shine.cpp" />
<ClCompile Include="..\block_shrink.cpp" />
<ClCompile Include="..\block_stretch.cpp" />
+ <ClCompile Include="..\bonus.cpp" />
<ClCompile Include="..\capsule.cpp" />
<ClCompile Include="..\chip.cpp" />
<ClCompile Include="..\cutscene.cpp" />
@@ 203,6 204,7 @@
<ClInclude Include="..\block_shine.h" />
<ClInclude Include="..\block_shrink.h" />
<ClInclude Include="..\block_stretch.h" />
+ <ClInclude Include="..\bonus.h" />
<ClInclude Include="..\capsule.h" />
<ClInclude Include="..\chip.h" />
<ClInclude Include="..\cutscene.h" />
M VisualStudio/VisualStudio.vcxproj.filters => VisualStudio/VisualStudio.vcxproj.filters +6 -0
@@ 141,6 141,9 @@
<ClCompile Include="..\speed.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\bonus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\anim.h">
@@ 290,5 293,8 @@
<ClInclude Include="..\cutscene.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\bonus.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
</Project>=
\ No newline at end of file
M ball.cpp => ball.cpp +6 -6
@@ 153,8 153,8 @@ void Ball::move() {
texture = ballTextures[ballMode - POWER_BALL]->texture;
if (state == BALL_STATE_INIT) {
- x = shipSprite.x + BALL_SPAWN_XOFFSET;
- y = shipSprite.y + BALL_SPAWN_YOFFSET;
+ x = shipLeft + ((shipRight - shipLeft) / 2) - (BALL_WIDTH / 2);
+ y = SHIP_YPOS;
//don't allow ball launch until level is done loading and ship is done
if ((padData & PAD_LASER) && (gameLevel->doneLoad()) && (shipState == SHIP_STATE_NORM)) {
@@ 220,11 220,11 @@ void Ball::move() {
//bottom
if (((x + BALL_WIDTH) >= shipLeft) &&
(x <= shipRight) &&
- ((y + BALL_HEIGHT) >= (shipSprite.y + SHIP_YMARGIN)) &&
- (y < (shipSprite.y + SHIP_HEIGHT))) {
+ ((y + BALL_HEIGHT) >= (SHIP_YPOS + SHIP_YMARGIN)) &&
+ (y < (SHIP_YPOS + SHIP_HEIGHT))) {
// calculate ball's offset from paddle center
- float ballOffset = (shipSprite.x + (SHIP_WIDTH / 2)) - (x + (BALL_WIDTH / 2));
+ float ballOffset = shipLeft + ((shipRight - shipLeft) / 2) - (x + (BALL_WIDTH / 2));
// fraction from -1 to 1
float normalizedOffset = ballOffset / (SHIP_WIDTH / 2);
@@ 240,7 240,7 @@ void Ball::move() {
}
// eject the ball if it's inside the paddle
- if (y >= (shipSprite.y + SHIP_YMARGIN)) {
+ if (y >= (SHIP_YPOS + SHIP_YMARGIN)) {
// left hit
if ((x - shipLeft) < (shipRight - shipLeft) / 2) {
x = shipLeft - BALL_WIDTH;
M capsule.cpp => capsule.cpp +2 -2
@@ 92,8 92,8 @@ void Capsule::move() {
int collision = 0;
if ((x + CAPSULE_WIDTH >= shipLeft) &&
(x <= shipRight) &&
- (y + CAPSULE_HEIGHT >= shipSprite.y + SHIP_YMARGIN) &&
- (y < shipSprite.y + SHIP_HEIGHT)) {
+ (y + CAPSULE_HEIGHT >= SHIP_YPOS + SHIP_YMARGIN) &&
+ (y < SHIP_YPOS + SHIP_HEIGHT)) {
collision = 1;
switch (type) {
case TYPE_POWERUP:
M game.cpp => game.cpp +57 -8
@@ 46,6 46,7 @@ typedef enum {
STATE_GAME_FADELEVEL,
STATE_GAME_LOSS,
STATE_GAME_CENTERSHIP,
+ STATE_GAME_RETRACTLASER,
STATE_GAME_SHIPDOOROPEN,
STATE_GAME_FLYUP,
STATE_GAME_FLYDOWN,
@@ 122,7 123,7 @@ std::unique_ptr<Level> gameLevel;
//start of ship's idle animation
#define SHIP_IDLE (ship_charno + 13)
-SpriteInfo shipSprite;
+static SpriteInfo shipSprite;
#define SHIP_SPRITE_WIDTH (32)
#define SHIP_SPRITE_HEIGHT (32)
//ship's leftmost pixel
@@ 130,10 131,17 @@ float shipLeft;
//ship's rightmost pixel
float shipRight;
+// gets overlaid over the ship sprite when the player has the laser powerup
+static SpriteInfo laserShipSprite;
+#define LASER_SHIP_SPRITE_HEIGHT (24)
+#define LASER_SHIP_SPRITE_XOFFSET (8)
+#define LASER_SHIP_SPRITESHEET_LAST (96)
+
+#define LASER_SHIP_TIMING (6)
+static float laserShipTimer;
+
int shipState;
-//ship's y pos during normal gameplay
-#define SHIP_POS (220)
#define SHIP_SPEED (4)
//all the ship's animations take 6 frames
#define SHIP_TIMING (6)
@@ 206,6 214,9 @@ void Game_Init(int level, int numLevels, int isStageClear, int bonusPoints) {
shipSprite = SpriteInfo("ship.png");
shipSprite.source.h = SHIP_SPRITE_HEIGHT;
+ laserShipSprite = SpriteInfo("gameship.png");
+ laserShipSprite.source.h = LASER_SHIP_SPRITE_HEIGHT;
+
barrelSprite = SpriteInfo("barrel.png");
barrelSprite.source.w = BARREL_SIZE;
barrelSprite.source.h = BARREL_SIZE;
@@ 355,6 366,7 @@ void Game_Loss() {
Laser_RemoveAll();
shipSprite.x = SHIP_STARTX;
shipSprite.y = SHIP_STARTY;
+ laserShipSprite.source.y = 0;
}
int Game_Playing() {
@@ 396,12 408,36 @@ void Game_DrawShip() {
if (bitShip) {
Game_BitAnim();
bitSprite.x = bitLeft;
- bitSprite.y = SHIP_POS + SHIP_YMARGIN;
+ bitSprite.y = SHIP_YPOS + SHIP_YMARGIN;
bitSprite.draw();
bitSprite.x = bitRight;
bitSprite.draw();
}
+ if (laserMax) {
+ if (state >= STATE_GAME_RETRACTLASER) {
+ if (laserShipSprite.source.y > 0) {
+ laserShipTimer += Speed_Multiplier();
+ if (laserShipTimer >= LASER_SHIP_TIMING) {
+ laserShipTimer = 0;
+ laserShipSprite.source.y -= LASER_SHIP_SPRITE_HEIGHT;
+ }
+ }
+ }
+ else {
+ if (laserShipSprite.source.y < LASER_SHIP_SPRITESHEET_LAST) {
+ laserShipTimer += Speed_Multiplier();
+ if (laserShipTimer >= LASER_SHIP_TIMING) {
+ laserShipTimer = 0;
+ laserShipSprite.source.y += LASER_SHIP_SPRITE_HEIGHT;
+ }
+ }
+ }
+ laserShipSprite.x = shipSprite.x + LASER_SHIP_SPRITE_XOFFSET;
+ laserShipSprite.y = shipSprite.y;
+ laserShipSprite.draw();
+ }
+
// draw barrels if ship is done animating in
if (shipSprite.source.y == SHIP_SPRITESHEET_LAST){
barrelSprite.x = shipSprite.x;
@@ 429,8 465,8 @@ int Game_Run() {
case STATE_SHIP_SPAWN:
shipSprite.y -= (3 * Speed_Multiplier());
- if (shipSprite.y <= SHIP_POS) {
- shipSprite.y = SHIP_POS;
+ if (shipSprite.y <= SHIP_YPOS) {
+ shipSprite.y = SHIP_YPOS;
}
if (Game_ShipAnim()) {
state = STATE_GAME_PLAY;
@@ 615,11 651,24 @@ int Game_Run() {
}
if (shipSprite.x == SHIP_STARTX) {
- state = STATE_GAME_SHIPDOOROPEN;
+ if (laserMax) {
+ state = STATE_GAME_RETRACTLASER;
+ }
+ else {
+ state = STATE_GAME_SHIPDOOROPEN;
+ }
}
+ break;
+ // retract the laser sprite if it's being displayed. actual retraction code
+ // is in Game_DrawShip
+ case STATE_GAME_RETRACTLASER:
+ if (laserShipSprite.source.y == 0) {
+ state = STATE_GAME_SHIPDOOROPEN;
+ }
break;
+
// door at the top opens to allow the ship to pass through
case STATE_GAME_SHIPDOOROPEN:
Bonus_Display(bonus, stageClear);
@@ 806,9 855,9 @@ int Game_Run() {
Enemy_Run();
Capsule_Draw();
}
+ Laser_Draw();
Game_DrawShip();
Ball_Draw(); // draw balls
- Laser_Draw();
Capsule_FlushRemoveQueue();
Enemy_FlushRemoveQueue();
M game.h => game.h +6 -3
@@ 29,11 29,14 @@
#define LEFT_WALL (8)
#define RIGHT_WALL (218)
#define TOP_WALL (8)
-//leftmost x pos the ship can go
+// leftmost x pos the ship can go
#define LEFT_BOUND (LEFT_WALL)
-//rightmost x pos the ship can go
+// rightmost x pos the ship can go
#define RIGHT_BOUND (RIGHT_WALL - SHIP_WIDTH)
+// where the ship is at during gameplay
+#define SHIP_YPOS (220)
+
//the area between where the sprite is and where the actual pixel graphics start
#define SHIP_YMARGIN (8)
#define SHIP_WIDTH (32)
@@ 56,7 59,7 @@ typedef enum {
P_BARRIER
} POWERUP;
-extern SpriteInfo shipSprite;
+// extern SpriteInfo shipSprite;
// left & right pixel of ship
extern float shipLeft;
extern float shipRight;
M main.cpp => main.cpp +0 -2
@@ 138,8 138,6 @@ int main(int argc, char **argv) {
int quit = 0;
int state = STATE_STAGE;
Stage_Init();
-
-
try {
while (!quit) {
M palette.cpp => palette.cpp +1 -3
@@ 88,9 88,7 @@ void Palette::update(std::vector<uint32_t> &newColors) {
ERR_PRINTF("Error locking texture: %s\n", SDL_GetError());
}
- for (int i = 0; i < (original->w * original->h); i++) {
- pixels[i] = ((uint32_t *)original->pixels)[i];
- }
+ memcpy(pixels, (uint32_t *)original->pixels, original->w * original->h);
for (COLOR_VAL &color : colors) {
pixels[color.offset] = newColors[color.colorIndex];