Initial commit of Let's Make Dangerous Dave. Utility finished. Initial game code.
This commit is contained in:
commit
619aa4ba82
|
@ -0,0 +1,82 @@
|
|||
# Detect OS
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ISWIN := 1
|
||||
endif
|
||||
|
||||
ifdef ISWIN
|
||||
CC := i686-w64-mingw32-gcc
|
||||
else
|
||||
CC := gcc
|
||||
endif
|
||||
|
||||
RM ?= rm -f
|
||||
RMDIR ?= rm -rf
|
||||
MKDIR ?= mkdir -p
|
||||
|
||||
WARFLAGS := -Wall #-Wextra -pedantic
|
||||
|
||||
CFLAGS_g := $(WARFLAGS) -std=gnu11 -O2 -msse2 -ffast-math -mfpmath=sse -DNDEBUG \
|
||||
-MMD
|
||||
|
||||
LDFLAGS_g := -s
|
||||
|
||||
# object output dir
|
||||
OBJDIR_g := obj
|
||||
|
||||
SRCS := $(wildcard *.c)
|
||||
OBJS_t := $(SRCS:.c=.o)
|
||||
|
||||
# include dirs
|
||||
CFLAGS_g +=
|
||||
|
||||
# libs
|
||||
ifdef ISWIN
|
||||
LDFLAGS_g +=
|
||||
else
|
||||
CFLAGS_g += -I/usr/include/SDL2
|
||||
LDFLAGS_g += -lSDL2
|
||||
endif
|
||||
|
||||
# binary target
|
||||
ifdef ISWIN
|
||||
TARG_t := lmdave.exe
|
||||
else
|
||||
TARG_t := lmdave
|
||||
endif
|
||||
|
||||
game: $(TARG_t)
|
||||
@echo "*** Target '$@': '$^' is up to date!"
|
||||
|
||||
default: game
|
||||
|
||||
.PHONY: default clean game
|
||||
|
||||
# rewrite OBJS so it outputs object files to seperate dir
|
||||
|
||||
OBJS_t := $(patsubst %,$(OBJDIR_g)/%,$(OBJS_t))
|
||||
|
||||
# include the dependency rules generated by -MMD
|
||||
|
||||
-include $(OBJS_t:.o=.d)
|
||||
|
||||
clean:
|
||||
@echo "*** Removing target binary and object directory..."
|
||||
@$(RM) $(TARG_t)
|
||||
@$(RMDIR) $(OBJDIR_g)
|
||||
@echo "*** Done."
|
||||
|
||||
# Compile
|
||||
|
||||
$(OBJDIR_g)/%.o: %.c
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "*** Compiling '$<' ..."
|
||||
@$(CC) $(CFLAGS_g) -c $< -o $@
|
||||
|
||||
# Link
|
||||
|
||||
$(TARG_t): $(OBJS_t)
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "\n*** Linking binary target '$@' ...\n"
|
||||
@$(CC) $(OBJS_t) -o $@ $(LDFLAGS_g)
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#include "lmdave.h"
|
||||
|
||||
// global game state
|
||||
game_state_t* gs = NULL;
|
||||
// global game assets
|
||||
game_assets_t* g_assets = NULL;
|
||||
|
||||
// initialize a new game state
|
||||
void init_game() {
|
||||
gs->quit = 1;
|
||||
gs->current_level = 1;
|
||||
}
|
||||
|
||||
// initialize assets
|
||||
void init_assets( SDL_Renderer* r ) {
|
||||
}
|
||||
|
||||
// poll input
|
||||
void check_input() {
|
||||
}
|
||||
|
||||
// update game logic
|
||||
void update_game() {
|
||||
}
|
||||
|
||||
// draw to renderer
|
||||
void render( SDL_Renderer* r ) {
|
||||
}
|
||||
|
||||
// rendering scale
|
||||
const uint8_t R_SCALE = 3;
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
gs = malloc( sizeof(game_state_t) );
|
||||
init_game();
|
||||
|
||||
SDL_Window* window = NULL;
|
||||
SDL_Renderer* renderer = NULL;
|
||||
SDL_CreateWindowAndRenderer( 320 * R_SCALE, 200 * R_SCALE, 0, &window, &renderer );
|
||||
|
||||
g_assets = malloc( sizeof(game_assets_t) );
|
||||
init_assets( renderer );
|
||||
|
||||
// main loop
|
||||
while ( !gs->quit ) {
|
||||
check_input();
|
||||
update_game();
|
||||
render( renderer );
|
||||
}
|
||||
|
||||
free( g_assets );
|
||||
free( gs );
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _LMDAVE_H
|
||||
#define _LMDAVE_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
// level structure
|
||||
// byte[256] path, two signed 8bit relative movement, 0xea 0xea for end
|
||||
// byte[100x10] tile index data, 100 by 10, so more than one level could fit in a chunk
|
||||
// byte[24] unsed padding
|
||||
// note: player start and monster starts are hardcoded
|
||||
typedef struct {
|
||||
int8_t path[256];
|
||||
uint8_t tiles[1000];
|
||||
uint8_t pad[24];
|
||||
} level_t;
|
||||
|
||||
// global game state
|
||||
typedef struct {
|
||||
uint8_t quit;
|
||||
uint8_t current_level;
|
||||
uint8_t view_x, view_y;
|
||||
|
||||
level_t levels[10];
|
||||
} game_state_t;
|
||||
|
||||
// game assets
|
||||
typedef struct {
|
||||
SDL_Texture* tile_tx[158];
|
||||
} game_assets_t;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
# Detect OS
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ISWIN := 1
|
||||
endif
|
||||
|
||||
ifdef ISWIN
|
||||
CC := i686-w64-mingw32-gcc
|
||||
else
|
||||
CC := gcc
|
||||
endif
|
||||
|
||||
RM ?= rm -f
|
||||
RMDIR ?= rm -rf
|
||||
MKDIR ?= mkdir -p
|
||||
|
||||
WARFLAGS := -Wall #-Wextra -pedantic
|
||||
|
||||
CFLAGS_g := $(WARFLAGS) -std=gnu11 -O2 -msse2 -ffast-math -mfpmath=sse -DNDEBUG \
|
||||
-MMD
|
||||
|
||||
LDFLAGS_g := -s
|
||||
|
||||
# object output dir
|
||||
OBJDIR_g := obj
|
||||
|
||||
#SRCS := $(wildcard *.c)
|
||||
OBJS_t := tiles.o levels.o
|
||||
|
||||
# include dirs
|
||||
CFLAGS_g +=
|
||||
|
||||
# libs
|
||||
ifdef ISWIN
|
||||
LDFLAGS_g +=
|
||||
else
|
||||
CFLAGS_g += -I/usr/include/SDL2
|
||||
LDFLAGS_g += -lSDL2
|
||||
endif
|
||||
|
||||
# binary target
|
||||
ifdef ISWIN
|
||||
TARG_t := tiles.exe
|
||||
else
|
||||
TARG_t := tiles
|
||||
endif
|
||||
|
||||
utils: $(TARG_t)
|
||||
@echo "*** Target '$@': '$^' is up to date!"
|
||||
|
||||
default: utils
|
||||
|
||||
.PHONY: default clean utils
|
||||
|
||||
# rewrite OBJS so it outputs object files to seperate dir
|
||||
|
||||
OBJS_t := $(patsubst %,$(OBJDIR_g)/%,$(OBJS_t))
|
||||
|
||||
# include the dependency rules generated by -MMD
|
||||
|
||||
-include $(OBJS_t:.o=.d)
|
||||
|
||||
clean:
|
||||
@echo "*** Removing target binary and object directory..."
|
||||
@$(RM) $(TARG_t)
|
||||
@$(RMDIR) $(OBJDIR_g)
|
||||
@echo "*** Done."
|
||||
|
||||
# Compile
|
||||
|
||||
$(OBJDIR_g)/%.o: %.c
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "*** Compiling '$<' ..."
|
||||
@$(CC) $(CFLAGS_g) -c $< -o $@
|
||||
|
||||
# Link
|
||||
|
||||
$(TARG_t): $(OBJS_t)
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "\n*** Linking binary target '$@' ...\n"
|
||||
@$(CC) $(OBJS_t) -o $@ $(LDFLAGS_g)
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// extract level data from uncompressed dave.exe
|
||||
// named as levelxx.dat
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
|
||||
//extern SDL_RWops* ddexe;
|
||||
extern SDL_Surface* tile_sfc[];
|
||||
|
||||
// level structure
|
||||
// byte[256] path, two signed 8bit relative movement, 0xea 0xea for end
|
||||
// byte[100x10] tile index data, 100 by 10, so more than one level could fit in a chunk
|
||||
// byte[24] unsed padding
|
||||
// note: player start and monster starts are hardcoded
|
||||
typedef struct {
|
||||
int8_t path[256];
|
||||
uint8_t tiles[1000];
|
||||
uint8_t pad[24];
|
||||
} level_t;
|
||||
|
||||
// all levels in the exe
|
||||
level_t levels[10];
|
||||
|
||||
// export all levels to seperate .dat file
|
||||
void SaveLevels() {
|
||||
for ( int l = 0; l < 10; ++l ) {
|
||||
char fname[1024];
|
||||
snprintf( fname, 1024, "../levels/level%02u.dat", l );
|
||||
printf( "Saving level %u to '%s'\n", l, fname );
|
||||
|
||||
SDL_RWops* lvlfile = SDL_RWFromFile( fname, "wb" );
|
||||
|
||||
// write path data
|
||||
for ( int p = 0; p < 256; ++p ) {
|
||||
SDL_RWwrite( lvlfile, &levels[l].path[p], 1, 1 );
|
||||
}
|
||||
// write tile data
|
||||
for ( int t = 0; t < 1000; ++t ) {
|
||||
SDL_RWwrite( lvlfile, &levels[l].tiles[t], 1, 1 );
|
||||
}
|
||||
// padding
|
||||
SDL_RWwrite( lvlfile, levels[l].pad, 24, 1 );
|
||||
|
||||
SDL_RWclose( lvlfile );
|
||||
}
|
||||
}
|
||||
|
||||
// fill global level array with dat from exe
|
||||
void LoadLevels() {
|
||||
const uint32_t lvl_dat_addr = 0x26e0a;
|
||||
|
||||
SDL_RWops* ddexe = SDL_RWFromFile( "../DAVE.EXE", "rb" );
|
||||
if ( ddexe == NULL ) { fprintf( stderr, "Error opening DAVE.EXE for levels.\n" ); return; }
|
||||
|
||||
// 10 levels @ 1280 bytes each
|
||||
// 16x16 tiles, 320x160px (20x10 tiles) view
|
||||
// off edges will wrap
|
||||
|
||||
// seek to start of data
|
||||
SDL_RWseek( ddexe, lvl_dat_addr, RW_SEEK_SET );
|
||||
|
||||
memset( levels, 0, sizeof(levels) );
|
||||
|
||||
// read each level into array
|
||||
for ( int l = 0; l < 10; ++l ) {
|
||||
// read path data
|
||||
for ( int p = 0; p < 256; ++p ) {
|
||||
SDL_RWread( ddexe, &levels[l].path[p], 1, 1 );
|
||||
}
|
||||
// read tile data
|
||||
for ( int t = 0; t < 1000; ++t ) {
|
||||
SDL_RWread( ddexe, &levels[l].tiles[t], 1, 1 );
|
||||
}
|
||||
// padding
|
||||
SDL_RWread( ddexe, levels[l].pad, 24, 1 );
|
||||
}
|
||||
|
||||
// close exe
|
||||
SDL_RWclose( ddexe );
|
||||
}
|
||||
|
||||
// create a large world map image with all levels
|
||||
void CreateWorldMap() {
|
||||
// create big empty surface for containing entire world map
|
||||
SDL_Surface* map = SDL_CreateRGBSurface( 0, 1600, 1600, 32, 0, 0, 0, 0 );
|
||||
// level, row, column
|
||||
for ( int l = 0; l < 10; ++l ) {
|
||||
for ( int y = 0; y < 10; ++y ) {
|
||||
for ( int x = 0; x < 100; ++x ) {
|
||||
uint8_t til = levels[l].tiles[y * 100 + x];
|
||||
SDL_Rect dst;
|
||||
dst.x = x * 16;
|
||||
dst.y = l * 160 + y * 16;
|
||||
dst.w = 16; dst.h = 16;
|
||||
SDL_BlitSurface( tile_sfc[til], NULL, map, &dst );
|
||||
|
||||
// hardcoded player and monster starts
|
||||
if ( (l == 0) && ((x == 2 && y == 8) || (x == 20 && y == 0)) ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( (l == 1) && ((x == 1 && y == 8) || (x == 51 && y == 0)) ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( l == 2 && x == 2 && y == 5 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
// l2 monsters
|
||||
if ( l == 2 )
|
||||
if ( (x == 44 || x == 59) && y == 4 ) {
|
||||
SDL_BlitSurface( tile_sfc[89], NULL, map, &dst );
|
||||
}
|
||||
if ( l == 3 && x == 1 && y == 5 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( l == 4 && x == 2 && y == 8 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( (l == 5) && ((x == 2 && y == 8) || (x == 71 && y == 0)) ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( (l == 6) && ((x == 1 && y == 2) || (x == 80 && y == 0)) ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( l == 7 && x == 2 && y == 8 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( l == 8 && x == 6 && y == 1 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
if ( l == 9 && x == 2 && y == 8 ) { SDL_BlitSurface( tile_sfc[53], NULL, map, &dst ); }
|
||||
}
|
||||
}
|
||||
}
|
||||
// save map file
|
||||
SDL_SaveBMP( map, "./map.bmp" );
|
||||
|
||||
// free world map
|
||||
SDL_FreeSurface( map );
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
// extract tilesxxx.bmp from uncompressed DAVE.EXE
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
// all tiles in the exe
|
||||
SDL_Surface* tile_sfc[158];
|
||||
//SDL_Texture* tile_tx[158];
|
||||
|
||||
// level info
|
||||
void LoadLevels();
|
||||
void SaveLevels();
|
||||
void CreateWorldMap();
|
||||
|
||||
// export all tiles to bmp
|
||||
void SaveTiles() {
|
||||
// Save out the all tile surfaces
|
||||
for ( int curtil = 0; curtil < 158; ++curtil ) {
|
||||
SDL_Surface* sfc = tile_sfc[curtil];
|
||||
printf( "Saving tile%03d.bmp (%ux%u)...\n", curtil, sfc->w, sfc->h );
|
||||
char fname[1024];
|
||||
snprintf( fname, 1024, "../tiles/tile%03d.bmp", curtil );
|
||||
SDL_SaveBMP( sfc, fname );
|
||||
}
|
||||
}
|
||||
|
||||
// convert all loaded tile surfaces to textures
|
||||
/*void ConvertTiles( SDL_Renderer* r ) {
|
||||
for ( int i = 0; i < 158; ++i ) {
|
||||
tile_tx[i] = SDL_CreateTextureFromSurface( r, tile_sfc[i] );
|
||||
SDL_FreeSurface( tile_sfc[i] );
|
||||
}
|
||||
}*/
|
||||
|
||||
// fill global tile array with tiles from exe
|
||||
void LoadTiles() {
|
||||
const uint32_t vga_data_addr = 0x120f0;
|
||||
const uint32_t vga_pal_addr = 0x26b0a;
|
||||
// exe assumed uncompressed
|
||||
SDL_RWops* ddexe = SDL_RWFromFile( "../DAVE.EXE", "rb" );
|
||||
if ( ddexe != NULL ) printf( "SUCCESS! (%"PRIi64" bytes)\n", SDL_RWsize( ddexe ) );
|
||||
|
||||
// tileset
|
||||
SDL_RWseek( ddexe, vga_data_addr, RW_SEEK_SET );
|
||||
uint32_t tssz;
|
||||
SDL_RWread( ddexe, &tssz, 4, 1 );
|
||||
printf( "Uncompressed tileset size: %u\n", tssz );
|
||||
uint8_t* tsdat = malloc( tssz );
|
||||
memset( tsdat, 0, tssz );
|
||||
uint8_t bytebuf = 0;
|
||||
uint8_t* tsbyte = tsdat; // current output byte to be written to
|
||||
// uncompress RLE
|
||||
while ( (tsbyte - tsdat) < tssz ) {
|
||||
SDL_RWread( ddexe, &bytebuf, 1, 1 );
|
||||
|
||||
if ( bytebuf & 0x80 ) { // unchanged
|
||||
uint32_t cnt = ((bytebuf & 0x7f) + 1);
|
||||
|
||||
while ( cnt-- ) {
|
||||
SDL_RWread( ddexe, &bytebuf, 1, 1 );
|
||||
*tsbyte = bytebuf; tsbyte++;
|
||||
}
|
||||
} else { // repeated
|
||||
uint32_t cnt = bytebuf + 3;
|
||||
SDL_RWread( ddexe, &bytebuf, 1, 1 ); // byte to be repeated
|
||||
while ( cnt-- ) {
|
||||
*tsbyte = bytebuf; tsbyte++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// palette
|
||||
SDL_RWseek( ddexe, vga_pal_addr, RW_SEEK_SET );
|
||||
uint8_t paldat[768];
|
||||
memset( paldat, 0, 768 );
|
||||
// reach each color and convert from 6bit to 8bit
|
||||
for ( int i = 0; i < 256; ++i ) {
|
||||
SDL_RWread( ddexe, paldat + (i * 3), 3, 1 );
|
||||
paldat[i*3] <<= 2;
|
||||
paldat[i*3+1] <<= 2;
|
||||
paldat[i*3+2] <<= 2;
|
||||
}
|
||||
|
||||
// note: extra byte every 65536 bytes
|
||||
// total tile count
|
||||
SDL_RWops* tsfil = SDL_RWFromMem( tsdat, tssz );
|
||||
uint32_t tscnt;
|
||||
SDL_RWread( tsfil, &tscnt, 4, 1 );
|
||||
printf( "Tile count: %u\n", tscnt );
|
||||
|
||||
// tile offsets
|
||||
uint32_t tsoffs[tscnt+1];
|
||||
for ( int i = 0; i < tscnt; ++i ) {
|
||||
SDL_RWread( tsfil, &tsoffs[i], 4, 1 );
|
||||
//printf( "ts%u: %u -- ", i, tsoffs[i] );
|
||||
}
|
||||
// last tile ends at EOF
|
||||
tsoffs[tscnt] = tssz;
|
||||
|
||||
uint16_t tw, th;
|
||||
uint32_t curbyte;
|
||||
uint8_t curtil;
|
||||
// read each tile
|
||||
for ( curtil = 0; curtil < tscnt; curtil++ ) {
|
||||
//curtilbyte = 0;
|
||||
curbyte = tsoffs[curtil];
|
||||
tw = 16; th = 16;
|
||||
// skip extra byte
|
||||
if ( curbyte > 65280 )
|
||||
curbyte++;
|
||||
// curbyte is now actual offset to raw image data
|
||||
SDL_RWseek( tsfil, curbyte, RW_SEEK_SET );
|
||||
|
||||
// check if dimension thats not 16x16, assumed if current chunk size is not 256
|
||||
if ( tsoffs[curtil+1] - tsoffs[curtil] != 256 ) {
|
||||
SDL_RWread( tsfil, &tw, 2, 1 );
|
||||
SDL_RWread( tsfil, &th, 2, 1 );
|
||||
curbyte += 4;
|
||||
}
|
||||
|
||||
// fill a new 32bpp surface using palette
|
||||
SDL_Surface* tilsfc = SDL_CreateRGBSurface( 0, tw, th, 32, 0,0,0,0 );//SDL_PIXELFORMAT_RGBA32 );
|
||||
SDL_LockSurface( tilsfc );
|
||||
uint8_t* pxp = (uint8_t*)(tilsfc->pixels);
|
||||
|
||||
for ( int p = 0; p < tw * th; ++p ) {
|
||||
uint8_t ix;
|
||||
SDL_RWread( tsfil, &ix, 1, 1 );
|
||||
size_t pos = p * 4;
|
||||
// bgra
|
||||
pxp[pos] = paldat[ix*3+2];
|
||||
pxp[pos+1] = paldat[ix*3+1];
|
||||
pxp[pos+2] = paldat[ix*3];
|
||||
pxp[pos+3] = 255;//(ix == 0) ? 0 : 255;
|
||||
}
|
||||
SDL_UnlockSurface( tilsfc );
|
||||
// store surface in global tile array
|
||||
tile_sfc[curtil] = tilsfc;
|
||||
|
||||
//SDL_FreeSurface( tilsfc );
|
||||
|
||||
//printf( "ts%u (%ux%u) @ %u -- ", curtil, tw, th, curbyte );
|
||||
}
|
||||
|
||||
SDL_RWclose( tsfil );
|
||||
free( tsdat );
|
||||
|
||||
// done with exe
|
||||
SDL_RWclose( ddexe );
|
||||
}
|
||||
|
||||
// free all loaded exe's tile surfaces
|
||||
void FreeTileSurfaces() {
|
||||
for ( int i = 0; i < 158; ++i ) {
|
||||
SDL_FreeSurface( tile_sfc[i] );
|
||||
}
|
||||
}
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
// high scores
|
||||
SDL_RWops* dscor = SDL_RWFromFile( "../DSCORES.DAV", "rb" );
|
||||
uint8_t lscor[9];
|
||||
while ( SDL_RWread( dscor, lscor, 9, 1 ) ) {
|
||||
printf( "LVL %u - SCORE: %u%u%u%u%u - NAM: %.3s\n", lscor[0],
|
||||
lscor[1], lscor[2], lscor[3], lscor[4], lscor[5], (char*)&lscor[6] );
|
||||
}
|
||||
SDL_RWclose( dscor );
|
||||
|
||||
LoadTiles();
|
||||
//SaveTiles();
|
||||
//ConvertTiles();
|
||||
|
||||
// LEVELS
|
||||
LoadLevels();
|
||||
//SaveLevels();
|
||||
CreateWorldMap();
|
||||
|
||||
FreeTileSurfaces();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue