diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/Game.h | 5 | ||||
-rw-r--r-- | src/GameInitDispose.cpp | 27 | ||||
-rw-r--r-- | src/GameLoop.cpp | 1 | ||||
-rw-r--r-- | src/GameTick.cpp | 17 | ||||
-rw-r--r-- | src/main.zig | 9 | ||||
-rw-r--r-- | src/misc.h | 13 | ||||
-rw-r--r-- | src/misc.zig | 66 |
8 files changed, 90 insertions, 49 deletions
diff --git a/.gitignore b/.gitignore index 21f8acc..e73c965 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ zig-cache/ zig-out/ -highscore.txt diff --git a/src/Game.h b/src/Game.h index f6400d9..f10c136 100644 --- a/src/Game.h +++ b/src/Game.h @@ -25,6 +25,7 @@ #include <GLFW/glfw3.h> #include "config.h" +#include "misc.h" #ifdef __cplusplus #include <stdlib.h> @@ -165,7 +166,6 @@ public: // Game functions void Tick(); void Splat(int k); - void saveHighScore(); }; #else // __cplusplus #include <stdbool.h> @@ -176,7 +176,7 @@ typedef struct Game Game; #ifdef __cplusplus extern "C" { #endif // __cplusplus - Game* makeGame(struct Config config); + Game* makeGame(struct Config config, struct Scores scores); void initGl(Game* game); void initGame(Game* game); void resizeWindow(Game* game, int width, int height); @@ -185,6 +185,7 @@ extern "C" { void handleKey(Game* game, int key, int action, int mods); void setMenu(Game* game, bool value); void eventLoop(Game* game); + struct Scores getScores(Game* game); void closeGame(Game* game); #ifdef __cplusplus } // extern "C" diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp index 9700e25..2928d5f 100644 --- a/src/GameInitDispose.cpp +++ b/src/GameInitDispose.cpp @@ -27,7 +27,6 @@ #include <AL/alc.h> #include <GL/glu.h> -#include "misc.h" #include "Game.h" #include "Support.h" @@ -70,7 +69,7 @@ void resizeWindow(Game* game, int width, int height) glViewport(0, 0, width, height); } -Game* makeGame(Config config) +Game* makeGame(Config config, Scores scores) { auto game = new Game(); game->screenwidth = config.width; @@ -93,20 +92,8 @@ Game* makeGame(Config config) game->nummissions = config.levels.len; game->debug = config.debug; - // TODO: Read high score - std::ifstream ipstream2 {"highscore.txt"}; - if (!ipstream2) { - std::ofstream opstream("highscore.txt"); - opstream << (game->highscore = 0) << std::endl; - opstream << (game->beatgame = 0) << std::endl; - opstream.close(); - } else { - ipstream2 >> game->highscore; - ipstream2.ignore(256,'\n'); - ipstream2 >> game->beatgame; - ipstream2.close(); - } - + game->highscore = scores.high_score; + game->beatgame = scores.completed; game->disttest = true; game->cubetest = true; setMenu(game, true); @@ -1092,6 +1079,14 @@ GLvoid Game::ReSizeGLScene(float fov, float near) glLoadIdentity(); } +struct Scores getScores(Game* game) +{ + return { + .high_score = (size_t) game->highscore, + .completed = game->beatgame, + }; +} + void closeGame(Game* game) { const GLuint textures[] { diff --git a/src/GameLoop.cpp b/src/GameLoop.cpp index 2cd0c5c..06d4e90 100644 --- a/src/GameLoop.cpp +++ b/src/GameLoop.cpp @@ -19,7 +19,6 @@ // You should have received a copy of the GNU General Public License // along with Black Shades. If not, see <https://www.gnu.org/licenses/>. -#include "misc.h" #include "Game.h" #include "Support.h" diff --git a/src/GameTick.cpp b/src/GameTick.cpp index fd9dad5..42af2a6 100644 --- a/src/GameTick.cpp +++ b/src/GameTick.cpp @@ -25,7 +25,6 @@ #include <algorithm> #include <fstream> -#include "misc.h" #include "Game.h" #include "Support.h" @@ -89,19 +88,6 @@ void Game::Splat(int k) alSourcePlay(gSourceID[headwhacksound]); } -void Game::saveHighScore() -{ - if (score > highscore) { - highscore = score; - /* TODO */ - std::ofstream opstream("highscore.txt"); - opstream << highscore; - opstream << "\n"; - opstream << beatgame; - opstream.close(); - } -} - void Game::updateSong() { if (environment == rainy_environment) @@ -175,7 +161,6 @@ void click(Game* game, int button, int action, int mods) } alSourcePlay(gSourceID[losesound]); - game->saveHighScore(); break; } return; @@ -457,6 +442,7 @@ void Game::Tick() if (timeremaining <= 0) { score += ++mission * 50 + 100; + highscore = max(score, highscore); flashamount = flashg = 1; flashr = flashb = 0; @@ -477,7 +463,6 @@ void Game::Tick() setMenu(this, beatgame = true); gameinprogress = 0; - saveHighScore(); } else { updateSong(); initGame(this); diff --git a/src/main.zig b/src/main.zig index 57ac609..4e93a8a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -23,6 +23,7 @@ pub const c = @cImport({ const Loca = @import("loca").Loca; const Window = gf.Window; +const Scores = misc.Scores; const al = @import("zeal"); const allocator = std.heap.c_allocator; const configuration = @import("config.zig"); @@ -30,6 +31,8 @@ const free = std.c.free; const gf = @import("gfz"); const gl = @import("zgl"); const misc = @import("misc.zig"); +const loadScores = misc.loadScores; +const saveScores = misc.saveScores; const std = @import("std"); var game: *c.Game = undefined; @@ -63,7 +66,11 @@ pub fn main() !void { "Black Shades", .{}, .{}); try window.makeCurrent(); - game = c.makeGame(@bitCast(c.Config, config)).?; + game = c.makeGame(@bitCast(c.Config, config), + @bitCast(c.Scores, try loadScores(loca.user_data))).?; + defer saveScores(loca.user_data, @bitCast(Scores, c.getScores(game))) + catch unreachable; + try window.setSizeCallback(resizeWindow); try gf.swapInterval(@boolToInt(config.vsync)); c.initGl(game); diff --git a/src/misc.h b/src/misc.h index fbd70cd..be5570a 100644 --- a/src/misc.h +++ b/src/misc.h @@ -47,13 +47,18 @@ struct MuscleData { signed char parent2; }; +struct Scores { + size_t high_score; + bool completed; +}; + #ifdef __cplusplus extern "C" { #endif // __cplusplus - AnimationData loadAnimation(const char*); - void loadJoints(JointData*); - ModelData loadModel(const char*); - void loadMuscles(MuscleData*); + struct AnimationData loadAnimation(const char*); + void loadJoints(struct JointData*); + struct ModelData loadModel(const char*); + void loadMuscles(struct MuscleData*); ALuint loadSound(const char*); GLuint loadTexture(const char*); void playSound(ALuint source, ALfloat x, ALfloat y, ALfloat z); diff --git a/src/misc.zig b/src/misc.zig index 2e54416..e30c154 100644 --- a/src/misc.zig +++ b/src/misc.zig @@ -35,7 +35,9 @@ const data_dir = @import("build_options").data_dir ++ [_]u8{ sep }; const endsWith = std.mem.endsWith; const eql = std.mem.eql; const free = std.c.free; +const ini = @import("ini"); const join = std.fs.path.joinZ; +const hash = std.crypto.hash.Blake3.hash; const maxInt = std.math.maxInt; const parseFloat = std.fmt.parseFloat; const parseInt = std.fmt.parseInt; @@ -45,14 +47,12 @@ const startsWith = std.mem.startsWith; const std = @import("std"); const tokenize = std.mem.tokenize; -// Don't judge me, take care of me! -const max_size = maxInt(usize); - /// Read given file to heap, allocated by C allocator. fn readFile(dir: Dir, comptime fmt: []const u8, args: anytype) ![]const u8 { const filename = try allocPrint(allocator, fmt, args); defer allocator.free(filename); - return dir.readFileAlloc(allocator, filename, max_size); + // Don't judge me, take care of me! + return dir.readFileAlloc(allocator, filename, maxInt(usize)); } const Frame = extern struct { @@ -268,6 +268,36 @@ export fn loadMuscles(muscles: [*]Muscle) void { muscles[i].load(row) catch unreachable; } +pub const Scores = extern struct { + // Don't underestimate players! + high_score: usize = 0, + completed: bool = false, +}; + +/// Read scores from user data directory and return it. +pub fn loadScores(base_dir: []const u8) !Scores { + var dir = try cwd().openDir(base_dir, .{}); + defer dir.close(); + var scores = Scores{}; + const path = "blackshades" ++ [_]u8{ sep } ++ "scores.ini"; + const input = dir.openFile(path, .{}) catch return scores; + defer input.close(); + var parser = ini.parse(allocator, input.reader()); + defer parser.deinit(); + + while (try parser.next()) |record| + switch (record) { + .section => {}, + .property => |kv| if (eql(u8, kv.key, "high score")) { + scores.high_score = try parseInt(usize, kv.value, 10); + } else if (eql(u8, kv.key, "completed")) { + scores.completed = try parseBool(kv.value); + } else return error.InvalidData, + else => return error.InvalidData, + }; + return scores; +} + /// Load audio file into an OpenAL buffer and return it. export fn loadSound(filename: [*:0]const u8) u32 { const path = join(allocator, &.{ data_dir ++ "sounds", span(filename) }) @@ -287,10 +317,9 @@ fn check(errorString: fn (c_uint) callconv(.C) [*c]const u8, /// Load PNG file into an OpenGL buffer and return it. export fn loadTexture(filename: [*:0]const u8) GLuint { - var dir = cwd().openDir(data_dir ++ "textures", .{}) catch unreachable; - defer dir.close(); - const file = dir.readFileAlloc(allocator, span(filename), max_size) - catch unreachable; + const file = readFile(cwd(), data_dir ++ "textures{c}{s}", .{ + sep, filename, + }) catch unreachable; defer allocator.free(file); var data: [*c]u8 = undefined; @@ -325,3 +354,24 @@ export fn playSound(source: u32, x: f32, y: f32, z: f32) void { src.setPosition(.{ x / 32, y / 32, z / 32 }) catch unreachable; src.play() catch unreachable; } + +// TODO: replace with @maximum from Zig 0.9+ +fn maximum(a: anytype, b: @TypeOf(a)) @TypeOf(a) { + return if (a > b) a else b; +} + +/// Write scores to user data directory. +pub fn saveScores(base_dir: []const u8, current: Scores) !void { + const previous = try loadScores(base_dir); + const dir_path = try join(allocator, &.{ base_dir, "blackshades" }); + defer allocator.free(dir_path); + var dir = try cwd().openDir(dir_path, .{}); + defer dir.close(); + const format = "[scores]\nhigh score = {}\ncompleted = {}\n"; + const data = try allocPrint(allocator, format, .{ + maximum(previous.high_score, current.high_score), + previous.completed or current.completed, + }); + defer allocator.free(data); + try dir.writeFile("scores.ini", data); +} |