Split play into body, items, interactions, autofeed and camera, with events, commands and literal strings
This commit is contained in:
1 parent
167f1a5ddd
commit
3e9a0cbd34
21 files changed
+2504
-2431
No files matched your search
+108
-22
@@ -1,9 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <SDL3/SDL_iostream.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
// Text files of key=value lines. A struct names the fields it keeps with visit(visitor), calling visitor(key, field)
|
||||
// for each, and reads and writes them through fields_read and fields_write.
|
||||
|
||||
enum Measurement
|
||||
{
|
||||
@@ -11,6 +16,76 @@ enum Measurement
|
||||
MEASUREMENT_IMPERIAL
|
||||
};
|
||||
|
||||
void file_write(const std::string& path, const std::string& text);
|
||||
|
||||
// Calls line with each key and value of a file. Returns whether it was there.
|
||||
template <class Line> bool is_file_read(const std::string& path, Line&& line)
|
||||
{
|
||||
char* text = (char*)SDL_LoadFile(path.c_str(), nullptr);
|
||||
if (!text)
|
||||
return false;
|
||||
char* rest = nullptr;
|
||||
for (char* entry = SDL_strtok_r(text, "\r\n", &rest); entry; entry = SDL_strtok_r(nullptr, "\r\n", &rest))
|
||||
{
|
||||
char* value = SDL_strchr(entry, '=');
|
||||
if (!value)
|
||||
continue;
|
||||
*value++ = '\0';
|
||||
line(std::string(entry), (const char*)value);
|
||||
}
|
||||
SDL_free(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Field> void field_read(const char* text, Field& field)
|
||||
{
|
||||
if constexpr (std::is_same_v<Field, std::string>)
|
||||
field = text;
|
||||
else if constexpr (std::is_same_v<Field, Vec2>)
|
||||
std::sscanf(text, "%f %f", &field.x, &field.y);
|
||||
else if constexpr (std::is_same_v<Field, Color>)
|
||||
std::sscanf(text, "%f %f %f", &field.r, &field.g, &field.b);
|
||||
else if constexpr (std::is_floating_point_v<Field>)
|
||||
field = (Field)SDL_atof(text);
|
||||
else
|
||||
field = (Field)SDL_atoi(text);
|
||||
}
|
||||
|
||||
template <class Field> std::string field_write(const Field& field)
|
||||
{
|
||||
if constexpr (std::is_same_v<Field, std::string>)
|
||||
return field;
|
||||
else if constexpr (std::is_same_v<Field, Vec2>)
|
||||
return field_write(field.x) + " " + field_write(field.y);
|
||||
else if constexpr (std::is_same_v<Field, Color>)
|
||||
return field_write(field.r) + " " + field_write(field.g) + " " + field_write(field.b);
|
||||
else if constexpr (std::is_floating_point_v<Field>)
|
||||
return std::to_string(field);
|
||||
else
|
||||
return std::to_string((int)field);
|
||||
}
|
||||
|
||||
// Sets whichever of a struct's fields a line names.
|
||||
template <class Fields> void field_line_read(Fields& fields, const std::string& key, const char* value)
|
||||
{
|
||||
fields.visit([&](const char* name, auto& field) {
|
||||
if (key == name)
|
||||
field_read(value, field);
|
||||
});
|
||||
}
|
||||
|
||||
template <class Fields> bool is_fields_read(const std::string& path, Fields& fields)
|
||||
{
|
||||
return is_file_read(path, [&](const std::string& key, const char* value) { field_line_read(fields, key, value); });
|
||||
}
|
||||
|
||||
template <class Fields> std::string fields_write(Fields& fields)
|
||||
{
|
||||
std::string text;
|
||||
fields.visit([&](const char* name, auto& field) { text += std::string(name) + "=" + field_write(field) + "\n"; });
|
||||
return text;
|
||||
}
|
||||
|
||||
// The game's preferences, kept in settings.txt.
|
||||
struct Settings
|
||||
{
|
||||
@@ -29,23 +104,26 @@ struct Settings
|
||||
void load();
|
||||
void save();
|
||||
void reset();
|
||||
template <class Visitor> void visit(Visitor&& visitor);
|
||||
|
||||
template <class Visitor> void visit(Visitor&& visitor)
|
||||
{
|
||||
visitor("character_color", isCharacterColor);
|
||||
visitor("color", color);
|
||||
visitor("console", isConsole);
|
||||
visitor("height", height);
|
||||
visitor("last_character", lastCharacter);
|
||||
visitor("measurement", measurement);
|
||||
visitor("mute", isMuted);
|
||||
visitor("volume", volume);
|
||||
visitor("width", width);
|
||||
visitor("x", x);
|
||||
visitor("y", y);
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedItem
|
||||
// A character's body as it is now: what's in it, how it digests, what it's eaten. Rates are percent per tick.
|
||||
struct Stats
|
||||
{
|
||||
std::string name;
|
||||
Vec2 position;
|
||||
Vec2 velocity;
|
||||
float rotation = 0;
|
||||
};
|
||||
|
||||
// A character's progress, kept in saves/<character>.txt, and the live state of one being played.
|
||||
struct Progress
|
||||
{
|
||||
std::vector<std::string> discovered;
|
||||
std::vector<SavedItem> items;
|
||||
Vec2 pan;
|
||||
float calories = 0;
|
||||
float capacity = 0;
|
||||
float digestionProgress = 0;
|
||||
@@ -53,17 +131,25 @@ struct Progress
|
||||
float playtime = 0;
|
||||
float totalCalories = 0;
|
||||
float weight = 0;
|
||||
float zoom = 0;
|
||||
int digestionTimer = 0;
|
||||
int spawnDelay = 0;
|
||||
int totalConsumed = 0;
|
||||
int totalSpawned = 0;
|
||||
bool isAlternate = false;
|
||||
bool isDigesting = false;
|
||||
bool isPostgame = false;
|
||||
bool isValid = false;
|
||||
|
||||
void load(const std::string& path);
|
||||
void save(const std::string& path);
|
||||
template <class Visitor> void visit(Visitor&& visitor);
|
||||
template <class Visitor> void visit(Visitor&& visitor)
|
||||
{
|
||||
visitor("alternate", isAlternate);
|
||||
visitor("calories", calories);
|
||||
visitor("capacity", capacity);
|
||||
visitor("digesting", isDigesting);
|
||||
visitor("digestion_progress", digestionProgress);
|
||||
visitor("digestion_rate", digestionRate);
|
||||
visitor("digestion_timer", digestionTimer);
|
||||
visitor("playtime", playtime);
|
||||
visitor("total_calories", totalCalories);
|
||||
visitor("total_consumed", totalConsumed);
|
||||
visitor("total_spawned", totalSpawned);
|
||||
visitor("weight", weight);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user