aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNguyễn Gia Phong <mcsinyx@disroot.org>2021-10-20 23:19:17 +0700
committerNguyễn Gia Phong <mcsinyx@disroot.org>2021-10-20 23:19:17 +0700
commitbd321d051ca8c827a5c8a490afc33812e76abba7 (patch)
treede88e5b28345672d952c5cf988dd05b4339aaa74 /src
parent446f5c5fd7cd977f096cd2d6256d829a765467c9 (diff)
downloadblackshades-bd321d051ca8c827a5c8a490afc33812e76abba7.tar.gz
Move scores tracking to user data
Diffstat (limited to 'src')
-rw-r--r--src/Game.h5
-rw-r--r--src/GameInitDispose.cpp27
-rw-r--r--src/GameLoop.cpp1
-rw-r--r--src/GameTick.cpp17
-rw-r--r--src/main.zig9
-rw-r--r--src/misc.h13
-rw-r--r--src/misc.zig66
7 files changed, 90 insertions, 48 deletions
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);
+}