Compare commits
No commits in common. "master" and "version-0.1" have entirely different histories.
master
...
version-0.
2
.gitignore
vendored
|
@ -27,5 +27,3 @@ backup
|
||||||
*.dll
|
*.dll
|
||||||
*.world
|
*.world
|
||||||
coverage
|
coverage
|
||||||
coverage/*
|
|
||||||
.venv
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
set makeprg=make\ -f\ ../Makefile\ build
|
set makeprg=meson\ compile\ -C\ .
|
||||||
|
|
49
Makefile
|
@ -1,72 +1,47 @@
|
||||||
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
|
||||||
|
|
||||||
all: build test
|
all: build test
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
ifeq '$(OS)' 'Windows_NT'
|
|
||||||
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
||||||
else
|
|
||||||
sh -x ./scripts/reset_build.sh
|
|
||||||
endif
|
|
||||||
|
|
||||||
%.cpp : %.rl
|
%.cpp : %.rl
|
||||||
ragel -I $(ROOT_DIR) -G1 -o $@ $<
|
ragel -o $@ $<
|
||||||
|
|
||||||
%.dot: %.rl
|
build: ansi_parser.cpp lel_parser.cpp
|
||||||
ragel -Vp -I $(ROOT_DIR) -o $@ $<
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
%.png: %.dot
|
|
||||||
dot -Tpng $< -o $@
|
|
||||||
|
|
||||||
build:
|
|
||||||
meson compile -j 10 -C $(ROOT_DIR)/builddir
|
|
||||||
|
|
||||||
asset_build:
|
|
||||||
./builddir/icongen
|
|
||||||
|
|
||||||
release_build:
|
release_build:
|
||||||
meson --wipe builddir -Db_ndebug=true --buildtype release
|
meson --wipe builddir -Db_ndebug=true --buildtype release
|
||||||
meson compile -j 10 -C builddir
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
debug_build:
|
debug_build:
|
||||||
meson setup --wipe builddir -Db_ndebug=true --buildtype debugoptimized
|
meson setup --wipe builddir --buildtype debug
|
||||||
meson compile -j 10 -C builddir
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
tracy_build:
|
tracy_build:
|
||||||
meson setup --wipe builddir --buildtype debugoptimized -Dtracy_enable=true -Dtracy:on_demand=true
|
meson setup --wipe builddir --buildtype debugoptimized -Dtracy_enable=true -Dtracy:on_demand=true
|
||||||
meson compile -j 10 -C builddir
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
test:
|
test: build
|
||||||
./builddir/runtests -d yes
|
./builddir/runtests
|
||||||
|
|
||||||
run: build test
|
run: build test
|
||||||
ifeq '$(OS)' 'Windows_NT'
|
|
||||||
powershell "cp ./builddir/zedcaster.exe ."
|
powershell "cp ./builddir/zedcaster.exe ."
|
||||||
./zedcaster
|
./zedcaster
|
||||||
else
|
|
||||||
./builddir/zedcaster
|
|
||||||
endif
|
|
||||||
|
|
||||||
debug: build
|
debug: build
|
||||||
gdb --nx -x .gdbinit --ex run --args builddir/zedcaster
|
gdb --nx -x .gdbinit --ex run --args builddir/zedcaster.exe
|
||||||
|
|
||||||
debug_run: build
|
debug_run: build
|
||||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster
|
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe
|
||||||
|
|
||||||
debug_walk: build test
|
debug_walk: build
|
||||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster t
|
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe t
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
meson compile --clean -C builddir
|
meson compile --clean -C builddir
|
||||||
|
|
||||||
debug_test: build
|
debug_test: build
|
||||||
gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e
|
gdb --nx -x .gdbinit --ex run --args builddir/runtests.exe -e
|
||||||
|
|
||||||
win_installer:
|
win_installer:
|
||||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" win_installer.ifp'
|
||||||
|
|
||||||
coverage_report:
|
|
||||||
powershell 'scripts/coverage_report.ps1'
|
|
||||||
|
|
||||||
money:
|
|
||||||
scc --exclude-dir subprojects
|
|
||||||
|
|
17
README.md
|
@ -42,9 +42,8 @@ See? That's how Free Speech works. You don't need a LICENSE.
|
||||||
On all platforms you'll need these components:
|
On all platforms you'll need these components:
|
||||||
|
|
||||||
* [Meson](https://mesonbuild.com/) -- which needs Python.
|
* [Meson](https://mesonbuild.com/) -- which needs Python.
|
||||||
* C++ Compiler -- Tested with Clang and GCC 14.2.0. You can use my [Windows C++ Setup Guide](https://git.learnjsthehardway.com/learn-code-the-hard-way/lcthw-windows-installers) which features an automated installer for Windows.
|
* C++ Compiler -- Tested with Clang and G++. You can use my [Windows C++ Setup Guide](https://git.learnjsthehardway.com/learn-code-the-hard-way/lcthw-windows-installers) which features an automated installer for Windows.
|
||||||
* [GNU make](https://www.gnu.org/software/make/) -- For the convenience Makefile. On Windows you should have this if you used my setup scripts. Otherwise `winget install ezwinports.make` will set you up.
|
* [GNU make](https://www.gnu.org/software/make/) -- For the convenience Makefile. On Windows you should have this if you used my setup scripts. Otherwise `winget install ezwinports.make` will set you up.
|
||||||
* [Ninja](https://ninja-build.org/) -- Meson uses this to do builds on most systems.
|
|
||||||
* [git](https://git-scm.com/) -- Which should be on almost every platform, and is installed by default with my Windows setup scripts.
|
* [git](https://git-scm.com/) -- Which should be on almost every platform, and is installed by default with my Windows setup scripts.
|
||||||
|
|
||||||
### Windows Instructions
|
### Windows Instructions
|
||||||
|
@ -89,7 +88,7 @@ cd raycaster
|
||||||
# first compile takes a while
|
# first compile takes a while
|
||||||
make
|
make
|
||||||
|
|
||||||
./builddir/zedcaster
|
./builddir/raycaster
|
||||||
```
|
```
|
||||||
|
|
||||||
You don't need `make run` because Linux and OSX are sane operating systems that don't lock every
|
You don't need `make run` because Linux and OSX are sane operating systems that don't lock every
|
||||||
|
@ -128,18 +127,6 @@ I would also like statistics that show it's better, not just your word.
|
||||||
|
|
||||||
It's early so probably a bunch of bugs.
|
It's early so probably a bunch of bugs.
|
||||||
|
|
||||||
## Linux Build Notes
|
|
||||||
|
|
||||||
Libraries Needed:
|
|
||||||
|
|
||||||
* libxi-dev
|
|
||||||
* libfreetype-dev
|
|
||||||
|
|
||||||
It uses c++ so you may need to install a libg++ or libc++ for your system. Usually this is all you
|
|
||||||
need:
|
|
||||||
|
|
||||||
apt install build-essential
|
|
||||||
|
|
||||||
## OSX Build Notes
|
## OSX Build Notes
|
||||||
|
|
||||||
* Quite a bad experience. Need to install Python, cmake, meson, and ninja all which are in homebrew but if you don't use homebrew then this is a problem.
|
* Quite a bad experience. Need to install Python, cmake, meson, and ninja all which are in homebrew but if you don't use homebrew then this is a problem.
|
||||||
|
|
212
ai.cpp
|
@ -1,212 +0,0 @@
|
||||||
#include "dbc.hpp"
|
|
||||||
#include "ai.hpp"
|
|
||||||
|
|
||||||
namespace ai {
|
|
||||||
using namespace nlohmann;
|
|
||||||
using namespace dbc;
|
|
||||||
|
|
||||||
static AIManager AIMGR;
|
|
||||||
static bool initialized = false;
|
|
||||||
|
|
||||||
inline void validate_profile(nlohmann::json& profile) {
|
|
||||||
for(auto& [name_key, value] : profile.items()) {
|
|
||||||
check(value < STATE_MAX,
|
|
||||||
fmt::format("profile field {} has value {} greater than STATE_MAX {}", (std::string)name_key, (int)value, STATE_MAX));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Action config_action(AIProfile& profile, nlohmann::json& config) {
|
|
||||||
check(config.contains("name"), "config_action: action config missing name");
|
|
||||||
check(config.contains("cost"), "config_action: action config missing cost");
|
|
||||||
|
|
||||||
Action result(config["name"], config["cost"]);
|
|
||||||
|
|
||||||
check(config.contains("needs"),
|
|
||||||
fmt::format("config_action: no 'needs' field", result.name));
|
|
||||||
check(config.contains("effects"),
|
|
||||||
fmt::format("config_action: no 'effects' field", result.name));
|
|
||||||
|
|
||||||
for(auto& [name_key, value] : config["needs"].items()) {
|
|
||||||
check(profile.contains(name_key), fmt::format("config_action({}): profile does not have need named {}", result.name, name_key));
|
|
||||||
result.needs(profile.at(name_key), bool(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& [name_key, value] : config["effects"].items()) {
|
|
||||||
check(profile.contains(name_key), fmt::format("config_action({}): profile does not have effect named {}", result.name, name_key));
|
|
||||||
|
|
||||||
result.effect(profile.at(name_key), bool(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
State config_state(AIProfile& profile, nlohmann::json& config) {
|
|
||||||
State result;
|
|
||||||
|
|
||||||
for(auto& [name_key, value] : config.items()) {
|
|
||||||
check(profile.contains(name_key), fmt::format("config_state: profile does not have name {}", name_key));
|
|
||||||
|
|
||||||
int name_id = profile.at(name_key);
|
|
||||||
result[name_id] = bool(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is only used in tests so I can load different fixtures.
|
|
||||||
*/
|
|
||||||
void reset() {
|
|
||||||
initialized = false;
|
|
||||||
AIMGR.actions.clear();
|
|
||||||
AIMGR.states.clear();
|
|
||||||
AIMGR.scripts.clear();
|
|
||||||
AIMGR.profile = json({});
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(std::string config_path) {
|
|
||||||
if(!initialized) {
|
|
||||||
Config config(config_path);
|
|
||||||
|
|
||||||
// profile specifies what keys (bitset indexes) are allowed
|
|
||||||
// and how they map to the bitset of State
|
|
||||||
validate_profile(config["profile"]);
|
|
||||||
|
|
||||||
// relies on json conversion?
|
|
||||||
AIMGR.profile = config["profile"];
|
|
||||||
|
|
||||||
// load all actions
|
|
||||||
auto& actions = config["actions"];
|
|
||||||
for(auto& action_vars : actions) {
|
|
||||||
auto the_action = config_action(AIMGR.profile, action_vars);
|
|
||||||
AIMGR.actions.insert_or_assign(the_action.name, the_action);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load all states
|
|
||||||
auto& states = config["states"];
|
|
||||||
for(auto& [name, state_vars] : states.items()) {
|
|
||||||
auto the_state = config_state(AIMGR.profile, state_vars);
|
|
||||||
AIMGR.states.insert_or_assign(name, the_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& scripts = config["scripts"];
|
|
||||||
for(auto& [script_name, action_names] : scripts.items()) {
|
|
||||||
std::vector<Action> the_script;
|
|
||||||
|
|
||||||
for(auto name : action_names) {
|
|
||||||
check(AIMGR.actions.contains(name),
|
|
||||||
fmt::format("ai::init(): script {} uses action {} that doesn't exist",
|
|
||||||
(std::string)script_name, (std::string)name));
|
|
||||||
|
|
||||||
the_script.push_back(AIMGR.actions.at(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
AIMGR.scripts.insert_or_assign(script_name, the_script);
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
} else {
|
|
||||||
dbc::sentinel("DOUBLE INIT: AI manager should only be intialized once if not in tests.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_valid_action(std::string name, std::string msg) {
|
|
||||||
dbc::check(AIMGR.actions.contains(name),
|
|
||||||
fmt::format("{} tried to access action that doesn't exist {}",
|
|
||||||
msg, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
State load_state(std::string state_name) {
|
|
||||||
check(initialized, "you forgot to initialize the AI first.");
|
|
||||||
check(AIMGR.states.contains(state_name), fmt::format(
|
|
||||||
"ai::load_state({}): state does not exist in config",
|
|
||||||
state_name));
|
|
||||||
|
|
||||||
return AIMGR.states.at(state_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action load_action(std::string action_name) {
|
|
||||||
check(initialized, "you forgot to initialize the AI first.");
|
|
||||||
check(AIMGR.states.contains(action_name), fmt::format(
|
|
||||||
"ai::load_action({}): action does not exist in config",
|
|
||||||
action_name));
|
|
||||||
return AIMGR.actions.at(action_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Action> load_script(std::string script_name) {
|
|
||||||
check(AIMGR.scripts.contains(script_name), fmt::format(
|
|
||||||
"ai::load_script(): no script named {} configured", script_name));
|
|
||||||
return AIMGR.scripts.at(script_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPlan plan(std::string script_name, State start, State goal) {
|
|
||||||
// BUG: could probably memoize here, since:
|
|
||||||
// same script+same start+same goal will/should produce the same results
|
|
||||||
|
|
||||||
check(initialized, "you forgot to initialize the AI first.");
|
|
||||||
auto script = load_script(script_name);
|
|
||||||
return plan_actions(script, start, goal);
|
|
||||||
}
|
|
||||||
|
|
||||||
int state_id(std::string name) {
|
|
||||||
check(AIMGR.profile.contains(name), fmt::format(
|
|
||||||
"ai::state_id({}): id is not configured in profile",
|
|
||||||
name));
|
|
||||||
return AIMGR.profile.at(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(State& state, std::string name, bool value) {
|
|
||||||
// resort by best fit
|
|
||||||
state.set(state_id(name), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool test(State state, std::string name) {
|
|
||||||
return state.test(state_id(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityAI::fit_sort() {
|
|
||||||
if(active()) {
|
|
||||||
std::sort(plan.script.begin(), plan.script.end(),
|
|
||||||
[&](auto& l, auto& r) {
|
|
||||||
int l_cost = l.cost + ai::distance_to_goal(start, goal);
|
|
||||||
int r_cost = r.cost + ai::distance_to_goal(start, goal);
|
|
||||||
return l_cost < r_cost;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string& EntityAI::wants_to() {
|
|
||||||
return plan.script[0].name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityAI::wants_to(std::string name) {
|
|
||||||
ai::check_valid_action(name, "EntityAI::wants_to");
|
|
||||||
return plan.script.size() > 0 && plan.script[0].name == name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityAI::active() {
|
|
||||||
if(plan.script.size() == 1) {
|
|
||||||
return plan.script[0] != FINAL_ACTION;
|
|
||||||
} else {
|
|
||||||
return plan.script.size() != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityAI::set_state(std::string name, bool setting) {
|
|
||||||
fit_sort();
|
|
||||||
ai::set(start, name, setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityAI::get_state(std::string name) {
|
|
||||||
return ai::test(start, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityAI::update() {
|
|
||||||
plan = ai::plan(script, start, goal);
|
|
||||||
fit_sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
AIProfile* profile() {
|
|
||||||
return &AIMGR.profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
65
ai.hpp
|
@ -1,65 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include "matrix.hpp"
|
|
||||||
#include <bitset>
|
|
||||||
#include <limits>
|
|
||||||
#include <optional>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include "config.hpp"
|
|
||||||
#include "goap.hpp"
|
|
||||||
|
|
||||||
namespace ai {
|
|
||||||
struct EntityAI {
|
|
||||||
std::string script;
|
|
||||||
ai::State start;
|
|
||||||
ai::State goal;
|
|
||||||
ai::ActionPlan plan;
|
|
||||||
|
|
||||||
EntityAI(std::string script, ai::State start, ai::State goal) :
|
|
||||||
script(script), start(start), goal(goal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityAI() {};
|
|
||||||
|
|
||||||
bool wants_to(std::string name);
|
|
||||||
std::string& wants_to();
|
|
||||||
void fit_sort();
|
|
||||||
|
|
||||||
bool active();
|
|
||||||
|
|
||||||
void set_state(std::string name, bool setting);
|
|
||||||
bool get_state(std::string name);
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
void dump();
|
|
||||||
std::string to_string();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AIManager {
|
|
||||||
AIProfile profile;
|
|
||||||
std::unordered_map<std::string, Action> actions;
|
|
||||||
std::unordered_map<std::string, State> states;
|
|
||||||
std::unordered_map<std::string, std::vector<Action>> scripts;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This is really only used in test to load different fixtures. */
|
|
||||||
void reset();
|
|
||||||
void init(std::string config_path);
|
|
||||||
|
|
||||||
Action config_action(AIProfile& profile, nlohmann::json& config);
|
|
||||||
State config_state(AIProfile& profile, nlohmann::json& config);
|
|
||||||
|
|
||||||
int state_id(std::string name);
|
|
||||||
State load_state(std::string state_name);
|
|
||||||
Action load_action(std::string action_name);
|
|
||||||
std::vector<Action> load_script(std::string script_name);
|
|
||||||
|
|
||||||
void set(State& state, std::string name, bool value=true);
|
|
||||||
bool test(State state, std::string name);
|
|
||||||
ActionPlan plan(std::string script_name, State start, State goal);
|
|
||||||
|
|
||||||
/* Mostly used for debugging and validation. */
|
|
||||||
void check_valid_action(std::string name, std::string msg);
|
|
||||||
}
|
|
74
ai_debug.cpp
|
@ -1,74 +0,0 @@
|
||||||
#include "ai.hpp"
|
|
||||||
#include "ai_debug.hpp"
|
|
||||||
|
|
||||||
namespace ai {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Yeah this is weird but it's only to debug things like
|
|
||||||
* the preconditions which are weirdly done.
|
|
||||||
*/
|
|
||||||
void dump_only(State state, bool matching, bool show_as) {
|
|
||||||
AIProfile* profile = ai::profile();
|
|
||||||
for(auto& [name, name_id] : *profile) {
|
|
||||||
if(state.test(name_id) == matching) {
|
|
||||||
fmt::println("\t{}={}", name, show_as);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump_state(State state) {
|
|
||||||
AIProfile* profile = ai::profile();
|
|
||||||
for(auto& [name, name_id] : *profile) {
|
|
||||||
fmt::println("\t{}={}", name,
|
|
||||||
state.test(name_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump_action(Action& action) {
|
|
||||||
fmt::println(" --ACTION: {}, cost={}", action.name, action.cost);
|
|
||||||
|
|
||||||
fmt::println(" PRECONDS:");
|
|
||||||
dump_only(action.$positive_preconds, true, true);
|
|
||||||
dump_only(action.$negative_preconds, true, false);
|
|
||||||
|
|
||||||
fmt::println(" EFFECTS:");
|
|
||||||
dump_only(action.$positive_effects, true, true);
|
|
||||||
dump_only(action.$negative_effects, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
State dump_script(std::string msg, State start, Script& script) {
|
|
||||||
fmt::println("--SCRIPT DUMP: {}", msg);
|
|
||||||
fmt::println("# STATE BEFORE:");
|
|
||||||
dump_state(start);
|
|
||||||
fmt::print("% ACTIONS PLANNED:");
|
|
||||||
for(auto& action : script) {
|
|
||||||
fmt::print("{} ", action.name);
|
|
||||||
}
|
|
||||||
fmt::print("\n");
|
|
||||||
|
|
||||||
for(auto& action : script) {
|
|
||||||
dump_action(action);
|
|
||||||
|
|
||||||
start = action.apply_effect(start);
|
|
||||||
fmt::println(" ## STATE AFTER:");
|
|
||||||
dump_state(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityAI::dump() {
|
|
||||||
dump_script(script, start, plan.script);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EntityAI::to_string() {
|
|
||||||
AIProfile* profile = ai::profile();
|
|
||||||
std::string result = wants_to();
|
|
||||||
|
|
||||||
for(auto& [name, name_id] : *profile) {
|
|
||||||
result += fmt::format("\n{}={}", name, start.test(name_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
10
ai_debug.hpp
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "goap.hpp"
|
|
||||||
|
|
||||||
namespace ai {
|
|
||||||
AIProfile* profile();
|
|
||||||
void dump_only(State state, bool matching, bool show_as);
|
|
||||||
void dump_state(State state);
|
|
||||||
void dump_action(Action& action);
|
|
||||||
State dump_script(std::string msg, State start, Script& script);
|
|
||||||
}
|
|
|
@ -68,6 +68,7 @@ void Raycaster::position_camera(float player_x, float player_y) {
|
||||||
|
|
||||||
void Raycaster::draw_pixel_buffer() {
|
void Raycaster::draw_pixel_buffer() {
|
||||||
view_texture.update(pixels.to_raw_buf(), {(unsigned int)$width, (unsigned int)$height}, {0, 0});
|
view_texture.update(pixels.to_raw_buf(), {(unsigned int)$width, (unsigned int)$height}, {0, 0});
|
||||||
|
// BUG: can I do this once and just update it?
|
||||||
$window.draw(view_sprite);
|
$window.draw(view_sprite);
|
||||||
}
|
}
|
||||||
|
|
117
animation.cpp
|
@ -1,117 +0,0 @@
|
||||||
#include "animation.hpp"
|
|
||||||
|
|
||||||
namespace components {
|
|
||||||
void Animation::play() {
|
|
||||||
if(!playing) {
|
|
||||||
current = 0;
|
|
||||||
subframe = 0.0f;
|
|
||||||
playing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float Animation::twitching() {
|
|
||||||
float tick = ease::sine(float(frames) / subframe * ease_rate);
|
|
||||||
|
|
||||||
switch(easing) {
|
|
||||||
case ease::NONE:
|
|
||||||
return 0.0;
|
|
||||||
case ease::SINE:
|
|
||||||
return tick;
|
|
||||||
case ease::OUT_CIRC:
|
|
||||||
return ease::out_circ(tick);
|
|
||||||
case ease::OUT_BOUNCE:
|
|
||||||
return ease::sine(ease::out_bounce(tick));
|
|
||||||
case ease::IN_OUT_BACK:
|
|
||||||
return ease::sine(ease::in_out_back(tick));
|
|
||||||
default:
|
|
||||||
dbc::sentinel(
|
|
||||||
fmt::format("Invalid easing {} given to animation",
|
|
||||||
int(easing)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Animation::step(sf::Vector2f& scale_out, sf::Vector2f& pos_out, sf::IntRect& rect_out) {
|
|
||||||
if(playing && current < frames) {
|
|
||||||
float tick = twitching();
|
|
||||||
scale_out.x = std::lerp(scale_out.x, scale_out.x + scale, tick);
|
|
||||||
scale_out.y = std::lerp(scale_out.y, scale_out.y + scale, tick);
|
|
||||||
|
|
||||||
if(stationary) {
|
|
||||||
pos_out.y = pos_out.y - (pos_out.y * scale_out.y - pos_out.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!simple) {
|
|
||||||
rect_out.position.x += current * frame_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
subframe += speed;
|
|
||||||
current = int(subframe);
|
|
||||||
} else if(!looped) {
|
|
||||||
playing = false;
|
|
||||||
current = frames - 1;
|
|
||||||
subframe = float(frames - 1);
|
|
||||||
|
|
||||||
if(!simple) {
|
|
||||||
rect_out.position.x += current * frame_width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
playing = false;
|
|
||||||
current = 0;
|
|
||||||
subframe = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace animation {
|
|
||||||
using namespace components;
|
|
||||||
using namespace textures;
|
|
||||||
|
|
||||||
static AnimationManager MGR;
|
|
||||||
static bool initialized = false;
|
|
||||||
|
|
||||||
bool apply(Animation& anim, SpriteTexture& target) {
|
|
||||||
auto size = target.texture->getSize();
|
|
||||||
anim.frame_width = int(size.x) / (unsigned int)anim.frames;
|
|
||||||
sf::IntRect rect{{0,0}, {anim.frame_width, int(size.y)}};
|
|
||||||
sf::Vector2f scale{1.0, 1.0};
|
|
||||||
sf::Vector2f pos{0, 0};
|
|
||||||
|
|
||||||
anim.step(scale, pos, rect);
|
|
||||||
|
|
||||||
target.sprite->setTextureRect(rect);
|
|
||||||
target.sprite->setPosition(pos);
|
|
||||||
target.sprite->setScale(scale);
|
|
||||||
|
|
||||||
return anim.playing;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rotate(sf::Sprite& target, float degrees) {
|
|
||||||
target.rotate(sf::degrees(degrees));
|
|
||||||
}
|
|
||||||
|
|
||||||
void center(sf::Sprite& target, sf::Vector2f pos) {
|
|
||||||
auto bounds = target.getLocalBounds();
|
|
||||||
target.setPosition({pos.x + bounds.size.x / 2,
|
|
||||||
pos.y + bounds.size.y / 2});
|
|
||||||
target.setOrigin({bounds.size.x / 2, bounds.size.y / 2});
|
|
||||||
}
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
if(!initialized) {
|
|
||||||
Config config("assets/animations.json");
|
|
||||||
|
|
||||||
for(auto& [name, data] : config.json().items()) {
|
|
||||||
auto anim = components::convert<Animation>(data);
|
|
||||||
MGR.animations.insert_or_assign(name, anim);
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Animation load(std::string name) {
|
|
||||||
dbc::check(initialized, "You forgot to initialize animation.");
|
|
||||||
return MGR.animations.at(name);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "components.hpp"
|
|
||||||
#include "textures.hpp"
|
|
||||||
#include "easings.hpp"
|
|
||||||
|
|
||||||
namespace animation {
|
|
||||||
struct AnimationManager {
|
|
||||||
std::unordered_map<std::string, components::Animation> animations;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool apply(components::Animation& anim, textures::SpriteTexture& target);
|
|
||||||
void rotate(sf::Sprite& target, float degrees);
|
|
||||||
void center(sf::Sprite& target, sf::Vector2f pos);
|
|
||||||
|
|
||||||
void init();
|
|
||||||
components::Animation load(std::string name);
|
|
||||||
}
|
|
376
ansi_parser.cpp
Normal file
|
@ -0,0 +1,376 @@
|
||||||
|
|
||||||
|
#line 1 "ansi_parser.rl"
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include "dbc.hpp"
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include "ansi_parser.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace fmt;
|
||||||
|
|
||||||
|
|
||||||
|
#line 122 "ansi_parser.rl"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#line 13 "ansi_parser.cpp"
|
||||||
|
static const char _ansi_parser_actions[] = {
|
||||||
|
0, 1, 0, 1, 3, 1, 4, 1,
|
||||||
|
5, 1, 6, 1, 7, 1, 8, 1,
|
||||||
|
9, 1, 10, 1, 11, 1, 15, 1,
|
||||||
|
16, 2, 1, 12, 2, 1, 13, 2,
|
||||||
|
6, 7, 2, 16, 5, 3, 1, 14,
|
||||||
|
2
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_key_offsets[] = {
|
||||||
|
0, 0, 1, 2, 11, 12, 14, 17,
|
||||||
|
18, 22, 23, 27, 28, 29, 30, 31,
|
||||||
|
33, 36, 38, 41, 43, 46, 47, 50,
|
||||||
|
51, 52, 53, 54, 55
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int _ansi_parser_trans_keys[] = {
|
||||||
|
27, 91, 48, 49, 50, 51, 52, 55,
|
||||||
|
57, 53, 54, 109, 48, 109, 34, 48,
|
||||||
|
55, 109, 50, 52, 55, 109, 109, 49,
|
||||||
|
56, 57, 109, 109, 59, 50, 59, 48,
|
||||||
|
57, 59, 48, 57, 48, 57, 59, 48,
|
||||||
|
57, 48, 57, 109, 48, 57, 109, 56,
|
||||||
|
57, 109, 59, 50, 109, 109, 27, 27,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_single_lengths[] = {
|
||||||
|
0, 1, 1, 7, 1, 2, 3, 1,
|
||||||
|
4, 1, 4, 1, 1, 1, 1, 0,
|
||||||
|
1, 0, 1, 0, 1, 1, 3, 1,
|
||||||
|
1, 1, 1, 1, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_range_lengths[] = {
|
||||||
|
0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_index_offsets[] = {
|
||||||
|
0, 0, 2, 4, 13, 15, 18, 22,
|
||||||
|
24, 29, 31, 36, 38, 40, 42, 44,
|
||||||
|
46, 49, 51, 54, 56, 59, 61, 65,
|
||||||
|
67, 69, 71, 73, 75
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_trans_targs[] = {
|
||||||
|
2, 1, 3, 0, 4, 5, 8, 10,
|
||||||
|
22, 26, 6, 7, 0, 28, 0, 6,
|
||||||
|
28, 0, 7, 7, 7, 0, 28, 0,
|
||||||
|
7, 7, 9, 28, 0, 28, 0, 11,
|
||||||
|
12, 21, 28, 0, 28, 0, 13, 0,
|
||||||
|
14, 0, 15, 0, 16, 0, 17, 16,
|
||||||
|
0, 18, 0, 19, 18, 0, 20, 0,
|
||||||
|
28, 20, 0, 28, 0, 23, 25, 28,
|
||||||
|
0, 24, 0, 14, 0, 28, 0, 28,
|
||||||
|
0, 2, 1, 2, 1, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_trans_actions[] = {
|
||||||
|
0, 7, 0, 0, 21, 21, 21, 21,
|
||||||
|
21, 21, 21, 21, 0, 31, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 17, 0, 15, 0, 0,
|
||||||
|
0, 0, 0, 0, 19, 0, 0, 0,
|
||||||
|
3, 0, 0, 0, 1, 0, 25, 0,
|
||||||
|
0, 1, 0, 28, 0, 0, 1, 0,
|
||||||
|
37, 0, 0, 9, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 5, 0, 11, 0, 13,
|
||||||
|
0, 0, 7, 23, 34, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _ansi_parser_eof_actions[] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 23
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int ansi_parser_start = 27;
|
||||||
|
static const int ansi_parser_first_final = 27;
|
||||||
|
static const int ansi_parser_error = 0;
|
||||||
|
|
||||||
|
static const int ansi_parser_en_main = 27;
|
||||||
|
|
||||||
|
|
||||||
|
#line 125 "ansi_parser.rl"
|
||||||
|
|
||||||
|
#include <ftxui/screen/terminal.hpp>
|
||||||
|
|
||||||
|
ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) :
|
||||||
|
$default_fg(default_fg),
|
||||||
|
$default_bg(default_bg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) {
|
||||||
|
const wchar_t *start = nullptr;
|
||||||
|
int cs = 0;
|
||||||
|
unsigned int value = 0;
|
||||||
|
const wchar_t *p = codes.data();
|
||||||
|
const wchar_t *pe = p + codes.size();
|
||||||
|
const wchar_t *eof = pe;
|
||||||
|
sf::Color bgcolor($default_bg);
|
||||||
|
sf::Color color($default_fg);
|
||||||
|
sf::Color* target = &color;
|
||||||
|
|
||||||
|
|
||||||
|
#line 120 "ansi_parser.cpp"
|
||||||
|
{
|
||||||
|
cs = ansi_parser_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#line 146 "ansi_parser.rl"
|
||||||
|
|
||||||
|
#line 123 "ansi_parser.cpp"
|
||||||
|
{
|
||||||
|
int _klen;
|
||||||
|
unsigned int _trans;
|
||||||
|
const char *_acts;
|
||||||
|
unsigned int _nacts;
|
||||||
|
const int *_keys;
|
||||||
|
|
||||||
|
if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
if ( cs == 0 )
|
||||||
|
goto _out;
|
||||||
|
_resume:
|
||||||
|
_keys = _ansi_parser_trans_keys + _ansi_parser_key_offsets[cs];
|
||||||
|
_trans = _ansi_parser_index_offsets[cs];
|
||||||
|
|
||||||
|
_klen = _ansi_parser_single_lengths[cs];
|
||||||
|
if ( _klen > 0 ) {
|
||||||
|
const int *_lower = _keys;
|
||||||
|
const int *_mid;
|
||||||
|
const int *_upper = _keys + _klen - 1;
|
||||||
|
while (1) {
|
||||||
|
if ( _upper < _lower )
|
||||||
|
break;
|
||||||
|
|
||||||
|
_mid = _lower + ((_upper-_lower) >> 1);
|
||||||
|
if ( (*p) < *_mid )
|
||||||
|
_upper = _mid - 1;
|
||||||
|
else if ( (*p) > *_mid )
|
||||||
|
_lower = _mid + 1;
|
||||||
|
else {
|
||||||
|
_trans += (unsigned int)(_mid - _keys);
|
||||||
|
goto _match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_keys += _klen;
|
||||||
|
_trans += _klen;
|
||||||
|
}
|
||||||
|
|
||||||
|
_klen = _ansi_parser_range_lengths[cs];
|
||||||
|
if ( _klen > 0 ) {
|
||||||
|
const int *_lower = _keys;
|
||||||
|
const int *_mid;
|
||||||
|
const int *_upper = _keys + (_klen<<1) - 2;
|
||||||
|
while (1) {
|
||||||
|
if ( _upper < _lower )
|
||||||
|
break;
|
||||||
|
|
||||||
|
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
|
||||||
|
if ( (*p) < _mid[0] )
|
||||||
|
_upper = _mid - 2;
|
||||||
|
else if ( (*p) > _mid[1] )
|
||||||
|
_lower = _mid + 2;
|
||||||
|
else {
|
||||||
|
_trans += (unsigned int)((_mid - _keys)>>1);
|
||||||
|
goto _match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_trans += _klen;
|
||||||
|
}
|
||||||
|
|
||||||
|
_match:
|
||||||
|
cs = _ansi_parser_trans_targs[_trans];
|
||||||
|
|
||||||
|
if ( _ansi_parser_trans_actions[_trans] == 0 )
|
||||||
|
goto _again;
|
||||||
|
|
||||||
|
_acts = _ansi_parser_actions + _ansi_parser_trans_actions[_trans];
|
||||||
|
_nacts = (unsigned int) *_acts++;
|
||||||
|
while ( _nacts-- > 0 )
|
||||||
|
{
|
||||||
|
switch ( *_acts++ )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
#line 14 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
start = p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
#line 18 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
size_t len = p - start;
|
||||||
|
dbc::check(start[0] != '-', "negative numbers not supported");
|
||||||
|
|
||||||
|
switch(len) {
|
||||||
|
case 10: value += (start[len-10] - '0') * 1000000000; [[fallthrough]];
|
||||||
|
case 9: value += (start[len- 9] - '0') * 100000000; [[fallthrough]];
|
||||||
|
case 8: value += (start[len- 8] - '0') * 10000000; [[fallthrough]];
|
||||||
|
case 7: value += (start[len- 7] - '0') * 1000000; [[fallthrough]];
|
||||||
|
case 6: value += (start[len- 6] - '0') * 100000; [[fallthrough]];
|
||||||
|
case 5: value += (start[len- 5] - '0') * 10000; [[fallthrough]];
|
||||||
|
case 4: value += (start[len- 4] - '0') * 1000; [[fallthrough]];
|
||||||
|
case 3: value += (start[len- 3] - '0') * 100; [[fallthrough]];
|
||||||
|
case 2: value += (start[len- 2] - '0') * 10; [[fallthrough]];
|
||||||
|
case 1: value += (start[len- 1] - '0');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dbc::sentinel("can't process > 10 digits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
#line 40 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
#line 43 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
target = &color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
#line 46 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
target = &bgcolor;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
#line 50 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
write_cb((*p));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
#line 54 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color = $default_fg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
#line 58 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
bgcolor = $default_bg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
#line 62 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color = $default_bg;
|
||||||
|
bgcolor = $default_fg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
#line 67 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color = $default_fg;
|
||||||
|
bgcolor = $default_bg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
#line 72 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color = sf::Color(100,100,100);
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
#line 76 "ansi_parser.rl"
|
||||||
|
{
|
||||||
|
color = sf::Color::Red;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
#line 81 "ansi_parser.rl"
|
||||||
|
{ target->r = value; }
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
#line 82 "ansi_parser.rl"
|
||||||
|
{ target->g = value; }
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
#line 83 "ansi_parser.rl"
|
||||||
|
{ target->b = value; }
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
#line 84 "ansi_parser.rl"
|
||||||
|
{ value = 0; }
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
#line 85 "ansi_parser.rl"
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
#line 296 "ansi_parser.cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_again:
|
||||||
|
if ( cs == 0 )
|
||||||
|
goto _out;
|
||||||
|
if ( ++p != pe )
|
||||||
|
goto _resume;
|
||||||
|
_test_eof: {}
|
||||||
|
if ( p == eof )
|
||||||
|
{
|
||||||
|
const char *__acts = _ansi_parser_actions + _ansi_parser_eof_actions[cs];
|
||||||
|
unsigned int __nacts = (unsigned int) *__acts++;
|
||||||
|
while ( __nacts-- > 0 ) {
|
||||||
|
switch ( *__acts++ ) {
|
||||||
|
case 16:
|
||||||
|
#line 85 "ansi_parser.rl"
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
#line 314 "ansi_parser.cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_out: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#line 147 "ansi_parser.rl"
|
||||||
|
|
||||||
|
bool good = pe - p == 0;
|
||||||
|
|
||||||
|
if(!good) {
|
||||||
|
p -= 10;
|
||||||
|
// dear cthuhlu, save me from the pain that is wstring
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
try {
|
||||||
|
print("{}", p[i] == 0x1B ? '^' : char(p[i]));
|
||||||
|
} catch(...) {
|
||||||
|
print("?=", int(p[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)ansi_parser_first_final;
|
||||||
|
(void)ansi_parser_error;
|
||||||
|
(void)ansi_parser_en_main;
|
||||||
|
|
||||||
|
|
||||||
|
return good;
|
||||||
|
}
|
23
ansi_parser.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string_view>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
typedef std::function<void(sf::Color bgcolor, sf::Color color)> ColorCB;
|
||||||
|
|
||||||
|
typedef std::function<void(wchar_t ch)> WriteCB;
|
||||||
|
|
||||||
|
class ANSIParser {
|
||||||
|
sf::Color $default_fg;
|
||||||
|
sf::Color $default_bg;
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ANSIParser(sf::Color default_fg, sf::Color default_bg);
|
||||||
|
|
||||||
|
// disable copying
|
||||||
|
ANSIParser(ANSIParser& ap) = delete;
|
||||||
|
|
||||||
|
bool parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb);
|
||||||
|
};
|
167
ansi_parser.rl
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include "dbc.hpp"
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include "ansi_parser.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace fmt;
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine ansi_parser;
|
||||||
|
alphtype int;
|
||||||
|
|
||||||
|
action tstart {
|
||||||
|
start = fpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
action number {
|
||||||
|
value = 0;
|
||||||
|
size_t len = fpc - start;
|
||||||
|
dbc::check(start[0] != '-', "negative numbers not supported");
|
||||||
|
|
||||||
|
switch(len) {
|
||||||
|
case 10: value += (start[len-10] - '0') * 1000000000; [[fallthrough]];
|
||||||
|
case 9: value += (start[len- 9] - '0') * 100000000; [[fallthrough]];
|
||||||
|
case 8: value += (start[len- 8] - '0') * 10000000; [[fallthrough]];
|
||||||
|
case 7: value += (start[len- 7] - '0') * 1000000; [[fallthrough]];
|
||||||
|
case 6: value += (start[len- 6] - '0') * 100000; [[fallthrough]];
|
||||||
|
case 5: value += (start[len- 5] - '0') * 10000; [[fallthrough]];
|
||||||
|
case 4: value += (start[len- 4] - '0') * 1000; [[fallthrough]];
|
||||||
|
case 3: value += (start[len- 3] - '0') * 100; [[fallthrough]];
|
||||||
|
case 2: value += (start[len- 2] - '0') * 10; [[fallthrough]];
|
||||||
|
case 1: value += (start[len- 1] - '0');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dbc::sentinel("can't process > 10 digits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action color_out {
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action is_fg {
|
||||||
|
target = &color;
|
||||||
|
}
|
||||||
|
action is_bg {
|
||||||
|
target = &bgcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
action out {
|
||||||
|
write_cb(fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
action reset_fg {
|
||||||
|
color = $default_fg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action reset_bg {
|
||||||
|
bgcolor = $default_bg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action invert {
|
||||||
|
color = $default_bg;
|
||||||
|
bgcolor = $default_fg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action reset_invert {
|
||||||
|
color = $default_fg;
|
||||||
|
bgcolor = $default_bg;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action half_bright {
|
||||||
|
color = sf::Color(100,100,100);
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
action red_text {
|
||||||
|
color = sf::Color::Red;
|
||||||
|
color_cb(color, bgcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
action red { target->r = value; }
|
||||||
|
action blue { target->g = value; }
|
||||||
|
action green { target->b = value; }
|
||||||
|
action start { value = 0; }
|
||||||
|
action end {}
|
||||||
|
action log { println("command {}", (char)fc); }
|
||||||
|
|
||||||
|
ESC = 0x1B;
|
||||||
|
start = ESC "[";
|
||||||
|
fg = "38;" %is_fg;
|
||||||
|
bg = "48;" %is_bg;
|
||||||
|
reset = ("39" %reset_fg | "49" %reset_bg);
|
||||||
|
num = digit+ >tstart %number;
|
||||||
|
color256 = "5;";
|
||||||
|
color24b = "2;";
|
||||||
|
|
||||||
|
ansi = (
|
||||||
|
start %start
|
||||||
|
(
|
||||||
|
reset |
|
||||||
|
"0" %reset_fg %reset_bg |
|
||||||
|
"1" |
|
||||||
|
"2" %half_bright |
|
||||||
|
"3" |
|
||||||
|
"4" |
|
||||||
|
"5" |
|
||||||
|
"6" |
|
||||||
|
"7" %invert |
|
||||||
|
"31" %red_text |
|
||||||
|
"22" |
|
||||||
|
"24" |
|
||||||
|
"27" %reset_invert |
|
||||||
|
"9" ["0"-"7"] |
|
||||||
|
"10" ["0"-"7"] |
|
||||||
|
(fg|bg) (color24b num %red ";" num %blue ";" num %green ) %color_out
|
||||||
|
) "m" %end
|
||||||
|
);
|
||||||
|
|
||||||
|
other = (any+ @out -- ESC)*;
|
||||||
|
|
||||||
|
main := (other :> ansi)**;
|
||||||
|
}%%
|
||||||
|
|
||||||
|
%% write data;
|
||||||
|
|
||||||
|
#include <ftxui/screen/terminal.hpp>
|
||||||
|
|
||||||
|
ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) :
|
||||||
|
$default_fg(default_fg),
|
||||||
|
$default_bg(default_bg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) {
|
||||||
|
const wchar_t *start = nullptr;
|
||||||
|
int cs = 0;
|
||||||
|
unsigned int value = 0;
|
||||||
|
const wchar_t *p = codes.data();
|
||||||
|
const wchar_t *pe = p + codes.size();
|
||||||
|
const wchar_t *eof = pe;
|
||||||
|
sf::Color bgcolor($default_bg);
|
||||||
|
sf::Color color($default_fg);
|
||||||
|
sf::Color* target = &color;
|
||||||
|
|
||||||
|
%% write init;
|
||||||
|
%% write exec;
|
||||||
|
|
||||||
|
bool good = pe - p == 0;
|
||||||
|
|
||||||
|
if(!good) {
|
||||||
|
p -= 10;
|
||||||
|
// dear cthuhlu, save me from the pain that is wstring
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
try {
|
||||||
|
print("{}", p[i] == 0x1B ? '^' : char(p[i]));
|
||||||
|
} catch(...) {
|
||||||
|
print("?=", int(p[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)ansi_parser_first_final;
|
||||||
|
(void)ansi_parser_error;
|
||||||
|
(void)ansi_parser_en_main;
|
||||||
|
|
||||||
|
return good;
|
||||||
|
}
|
140
assets/ai.json
|
@ -1,140 +0,0 @@
|
||||||
{
|
|
||||||
"profile": {
|
|
||||||
"enemy_found": 0,
|
|
||||||
"enemy_dead": 1,
|
|
||||||
"health_good": 2,
|
|
||||||
"no_more_items": 3,
|
|
||||||
"no_more_enemies": 4,
|
|
||||||
"in_combat": 5,
|
|
||||||
"have_item": 6,
|
|
||||||
"have_healing": 7,
|
|
||||||
"detect_enemy": 8,
|
|
||||||
"tough_personality": 9,
|
|
||||||
"cant_move": 10
|
|
||||||
},
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"name": "find_enemy",
|
|
||||||
"cost": 5,
|
|
||||||
"needs": {
|
|
||||||
"detect_enemy": true,
|
|
||||||
"in_combat": false,
|
|
||||||
"no_more_enemies": false,
|
|
||||||
"enemy_found": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"in_combat": true,
|
|
||||||
"enemy_found": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "run_away",
|
|
||||||
"cost": 0,
|
|
||||||
"needs": {
|
|
||||||
"tough_personality": false,
|
|
||||||
"in_combat": true,
|
|
||||||
"have_healing": false,
|
|
||||||
"health_good": false,
|
|
||||||
"cant_move": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"in_combat": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kill_enemy",
|
|
||||||
"cost": 10,
|
|
||||||
"needs": {
|
|
||||||
"no_more_enemies": false,
|
|
||||||
"in_combat": true,
|
|
||||||
"enemy_found": true,
|
|
||||||
"enemy_dead": false
|
|
||||||
},
|
|
||||||
|
|
||||||
"effects": {
|
|
||||||
"enemy_dead": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "collect_items",
|
|
||||||
"cost": 5,
|
|
||||||
"needs": {
|
|
||||||
"no_more_enemies": true,
|
|
||||||
"no_more_items": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"no_more_items": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "find_healing",
|
|
||||||
"cost": 2,
|
|
||||||
"needs": {
|
|
||||||
"have_healing": false,
|
|
||||||
"in_combat": false,
|
|
||||||
"health_good": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"health_good": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "use_healing",
|
|
||||||
"cost": 1,
|
|
||||||
"needs": {
|
|
||||||
"have_item": true,
|
|
||||||
"have_healing": true,
|
|
||||||
"health_good": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"health_good": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"states": {
|
|
||||||
"Host::initial_state": {
|
|
||||||
"enemy_found": false,
|
|
||||||
"enemy_dead": false,
|
|
||||||
"health_good": true,
|
|
||||||
"no_more_items": false,
|
|
||||||
"no_more_enemies": false,
|
|
||||||
"in_combat": false,
|
|
||||||
"have_item": false,
|
|
||||||
"have_healing": false,
|
|
||||||
"detect_enemy": true,
|
|
||||||
"tough_personality": true
|
|
||||||
},
|
|
||||||
"Host::final_state": {
|
|
||||||
"enemy_found": true,
|
|
||||||
"enemy_dead": true,
|
|
||||||
"health_good": true,
|
|
||||||
"no_more_items": true,
|
|
||||||
"in_combat": false,
|
|
||||||
"no_more_enemies": true
|
|
||||||
},
|
|
||||||
"Enemy::initial_state": {
|
|
||||||
"detect_enemy": false,
|
|
||||||
"tough_personality": true,
|
|
||||||
"enemy_found": false,
|
|
||||||
"enemy_dead": false,
|
|
||||||
"health_good": true,
|
|
||||||
"in_combat": false
|
|
||||||
},
|
|
||||||
"Enemy::final_state": {
|
|
||||||
"detect_enemy": true,
|
|
||||||
"enemy_found": true,
|
|
||||||
"enemy_dead": true,
|
|
||||||
"health_good": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"Host::actions":
|
|
||||||
["find_enemy",
|
|
||||||
"kill_enemy",
|
|
||||||
"collect_items",
|
|
||||||
"find_healing",
|
|
||||||
"use_healing"],
|
|
||||||
"Enemy::actions":
|
|
||||||
["find_enemy", "run_away", "kill_enemy", "use_healing"]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"ritual_blanket": {
|
|
||||||
"_type": "Animation",
|
|
||||||
"easing": 0,
|
|
||||||
"ease_rate": 0.5,
|
|
||||||
"scale": 1.0,
|
|
||||||
"simple": false,
|
|
||||||
"frames": 3,
|
|
||||||
"speed": 0.2,
|
|
||||||
"stationary": true
|
|
||||||
}
|
|
||||||
}
|
|
BIN
assets/armored_knight_1-256.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
assets/armored_knight_1-512.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
assets/axe_ranger-256.png
Normal file
After Width: | Height: | Size: 107 KiB |
BIN
assets/blood_splatter-256.png
Normal file
After Width: | Height: | Size: 82 KiB |
|
@ -3,7 +3,7 @@
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "BossFight",
|
{"_type": "BossFight",
|
||||||
"background": "boss_fight_background",
|
"background": "boss_fight_background",
|
||||||
"stage": null,
|
"stage": false,
|
||||||
"weapon_sound": "Sword_Hit_2"
|
"weapon_sound": "Sword_Hit_2"
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "BossFight",
|
{"_type": "BossFight",
|
||||||
"background": "devils_fingers_background",
|
"background": "devils_fingers_background",
|
||||||
"stage": "devils_fingers_stage",
|
"stage": false,
|
||||||
"weapon_sound": "Sword_Hit_2"
|
"weapon_sound": "Sword_Hit_2"
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
||||||
|
|
BIN
assets/ceiling_test-256.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
assets/ceiling_test-512.png
Normal file
After Width: | Height: | Size: 249 KiB |
BIN
assets/ceiling_worm-256.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
assets/cinqueda_1-256.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
assets/cinqueda_1-512.png
Normal file
After Width: | Height: | Size: 75 KiB |
|
@ -17,233 +17,45 @@
|
||||||
"Marmot_Scream_1": "assets/sounds/Creature_Sounds-Marmot_Scream_1.ogg",
|
"Marmot_Scream_1": "assets/sounds/Creature_Sounds-Marmot_Scream_1.ogg",
|
||||||
"blank": "assets/sounds/blank.ogg",
|
"blank": "assets/sounds/blank.ogg",
|
||||||
"pickup": "assets/sounds/pickup.ogg",
|
"pickup": "assets/sounds/pickup.ogg",
|
||||||
"ambient_1": "assets/sounds/ambient_1.ogg",
|
"ambient_1": "assets/sounds/ambient_1.ogg"
|
||||||
"ui_click": "assets/sounds/ui_click.ogg",
|
|
||||||
"ui_hover": "assets/sounds/ui_hover.ogg",
|
|
||||||
"punch_cartoony": "assets/sounds/punch_cartoony.ogg",
|
|
||||||
"electric_shock_01": "assets/sounds/electric_shock_01.ogg",
|
|
||||||
"fireball_01": "assets/sounds/fireball_01.ogg",
|
|
||||||
"hp_status_80": "assets/sounds/hp_status_80.ogg",
|
|
||||||
"hp_status_60": "assets/sounds/hp_status_60.ogg",
|
|
||||||
"hp_status_30": "assets/sounds/hp_status_30.ogg",
|
|
||||||
"hp_status_10": "assets/sounds/hp_status_10.ogg",
|
|
||||||
"hp_status_00": "assets/sounds/hp_status_00.ogg"
|
|
||||||
},
|
},
|
||||||
"sprites": {
|
"sprites": {
|
||||||
"gold_savior":
|
"armored_knight": "assets/armored_knight_1-256.png",
|
||||||
{"path": "assets/sprites/gold_savior.png",
|
"sword": "assets/cinqueda_1-512.png",
|
||||||
"frame_width": 256,
|
"rat_with_sword": "assets/rat_with_sword-256.png",
|
||||||
"frame_height": 256
|
"rat_king": "assets/rat_king-256.png",
|
||||||
},
|
"rat_king_boss": "assets/rat_king_2_frame_animation.png",
|
||||||
"armored_knight":
|
"barrel_small": "assets/wood_barrel_small-256.png",
|
||||||
{"path": "assets/sprites/armored_knight_1.png",
|
"hanging_brazier": "assets/hanging_brazier-256.png",
|
||||||
"frame_width": 256,
|
"torch_pillar": "assets/torch_pillar-256.png",
|
||||||
"frame_height": 256
|
"torch_crappy": "assets/torch_crappy-256.png",
|
||||||
},
|
"torch_horizontal_floor": "assets/torch_horizontal_floor-256.png",
|
||||||
"axe_ranger":
|
"evil_eye": "assets/evil_eye-sprites.png",
|
||||||
{"path": "assets/sprites/axe_ranger.png",
|
"peasant_girl": "assets/undead_peasant-256.png",
|
||||||
"frame_width": 256,
|
"grave_stone": "assets/grave_stone-256.png",
|
||||||
"frame_height": 256
|
"floor": "assets/floor_tile_test-256.png",
|
||||||
},
|
"ceiling": "assets/ceiling_test-256.png",
|
||||||
"hairy_spider":
|
"healing_potion_small": "assets/healing_potion_small-256.png",
|
||||||
{"path": "assets/sprites/hairy_spider.png",
|
"well_down": "assets/well_down-256.png",
|
||||||
"frame_width": 256,
|
"rope_vines_up": "assets/rope_vines_up-256.png",
|
||||||
"frame_height": 256
|
"tripwire_trap": "assets/tripwire_trap-256.png",
|
||||||
},
|
"cinqueda": "assets/cinqueda_1-256.png",
|
||||||
"rat_with_sword":
|
"left_gui": "assets/left_gui.png",
|
||||||
{"path": "assets/sprites/rat_with_sword.png",
|
"blood_splatter": "assets/blood_splatter-256.png",
|
||||||
"frame_width": 256,
|
"trash_button": "assets/trash_button.png",
|
||||||
"frame_height": 256
|
"axe_ranger": "assets/axe_ranger-256.png",
|
||||||
},
|
"hairy_spider": "assets/hairy_spider-256.png",
|
||||||
"rat_king_boss":
|
"down_the_well": "assets/down_the_well.jpg",
|
||||||
{"path": "assets/bossfights/rat_king_2_frame_animation.png",
|
"boss_fight_background": "assets/rat_king_boss_fight_background.jpg",
|
||||||
"frame_width": 720,
|
"devils_fingers_background": "assets/devils_fingers_background.jpg",
|
||||||
"frame_height": 720
|
"devils_fingers_sprite": "assets/devils_fingers_sprite.png",
|
||||||
},
|
"devils_fingers_stage": "assets/devils_fingers_stage.png",
|
||||||
"barrel_small":
|
"tunnel_with_rocks": "assets/tunnel_with_rocks.png",
|
||||||
{"path": "assets/items/wood_barrel_small.png",
|
"tunnel_with_rocks_stage": "assets/tunnel_with_rocks_stage.png"
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"torch_pillar":
|
|
||||||
{"path": "assets/sprites/torch_pillar.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"torch_crappy":
|
|
||||||
{"path": "assets/items/torch_crappy.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"torch_horizontal_floor":
|
|
||||||
{"path": "assets/items/torch_horizontal_floor.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"peasant_girl":
|
|
||||||
{"path": "assets/sprites/peasant_girl_2.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"grave_stone":
|
|
||||||
{"path": "assets/sprites/grave_stone.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"healing_potion_small":
|
|
||||||
{"path": "assets/items/healing_potion_small.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"well_down":
|
|
||||||
{"path": "assets/sprites/well_down.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"rope_vines_up":
|
|
||||||
{"path": "assets/sprites/rope_vines_up.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"tripwire_trap":
|
|
||||||
{"path": "assets/sprites/tripwire_trap.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"boss_fight_background":
|
|
||||||
{"path": "assets/bossfights/rat_king_boss_fight_background.jpg",
|
|
||||||
"frame_width": 1080,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"devils_fingers_background":
|
|
||||||
{"path": "assets/bossfights/devils_fingers_background.jpg",
|
|
||||||
"frame_width": 1080,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"devils_fingers_sprite":
|
|
||||||
{"path": "assets/bossfights/devils_fingers_sprite.png",
|
|
||||||
"frame_width": 720,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"devils_fingers_stage":
|
|
||||||
{"path": "assets/bossfights/devils_fingers_stage.png",
|
|
||||||
"frame_width": 1080,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"tunnel_with_rocks":
|
|
||||||
{"path": "assets/bossfights/tunnel_with_rocks.png",
|
|
||||||
"frame_width": 1080,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"tunnel_with_rocks_stage":
|
|
||||||
{"path": "assets/bossfights/tunnel_with_rocks_stage.png",
|
|
||||||
"frame_width": 1080,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"ritual_crafting_area":
|
|
||||||
{"path": "assets/ui/ritual_crafting_area.png",
|
|
||||||
"frame_width": 380,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"full_screen_paper":
|
|
||||||
{"path": "assets/ui/full_screen_paper.png",
|
|
||||||
"frame_width": 1280,
|
|
||||||
"frame_height": 720
|
|
||||||
},
|
|
||||||
"broken_locket":
|
|
||||||
{"path": "assets/items/broken_locket.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"broken_pen_knife":
|
|
||||||
{"path": "assets/items/broken_pen_knife.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"broken_yoyo":
|
|
||||||
{"path": "assets/items/broken_yoyo.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"chess_pawn":
|
|
||||||
{"path": "assets/items/chess_pawn.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"dirty_kerchief":
|
|
||||||
{"path": "assets/items/dirty_kerchief.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"leather_pouch":
|
|
||||||
{"path": "assets/items/leather_pouch.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"mushroom":
|
|
||||||
{"path": "assets/items/mushroom.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"pocket_watch":
|
|
||||||
{"path": "assets/items/pocket_watch.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"rusty_nails":
|
|
||||||
{"path": "assets/items/rusty_nails.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"severed_finger":
|
|
||||||
{"path": "assets/items/severed_finger.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"stone_doll_cursed":
|
|
||||||
{"path": "assets/items/stone_doll_cursed.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"dubious_combination":
|
|
||||||
{"path": "assets/items/dubious_combination.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"dead_body":
|
|
||||||
{"path": "assets/sprites/dead_body.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
},
|
|
||||||
"dead_body_lootable":
|
|
||||||
{"path": "assets/sprites/dead_body_lootable.png",
|
|
||||||
"frame_width": 256,
|
|
||||||
"frame_height": 256
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"worldgen": {
|
"worldgen": {
|
||||||
"enemy_probability": 50,
|
"enemy_probability": 80,
|
||||||
|
"empty_room_probability": 10,
|
||||||
"device_probability": 10
|
"device_probability": 10
|
||||||
},
|
|
||||||
"graphics": {
|
|
||||||
"smooth_textures": false
|
|
||||||
},
|
|
||||||
"compass": {
|
|
||||||
"N": 65514,
|
|
||||||
"NE": 8663,
|
|
||||||
"E": 8594,
|
|
||||||
"SE": 8600,
|
|
||||||
"S": 65516,
|
|
||||||
"SW": 8665,
|
|
||||||
"W": 8592,
|
|
||||||
"NW": 8598
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"NOTE": "colors are in assets/palette.json",
|
|
||||||
"padding": 3,
|
|
||||||
"border_px": 1,
|
|
||||||
"text_size": 20,
|
|
||||||
"label_size": 20,
|
|
||||||
"font_file_name": "assets/text.otf"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
"inventory_count": 0,
|
"inventory_count": 0,
|
||||||
"randomized": false,
|
"randomized": false,
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 6105,
|
{"_type": "Tile", "display": "\u2ac5",
|
||||||
"foreground": "devices/fg:stairs_down",
|
"foreground": [24, 205, 189],
|
||||||
"background": "devices/bg:stairs_down"
|
"background": [24, 205, 189]
|
||||||
},
|
},
|
||||||
{"_type": "Device",
|
{"_type": "Device",
|
||||||
"config": {},
|
"config": {"test": true},
|
||||||
"events": ["STAIRS_DOWN"]},
|
"events": ["Events::GUI::STAIRS_DOWN"]},
|
||||||
{"_type": "Sprite", "name": "well_down", "width": 256, "height": 256, "scale": 1.0}
|
{"_type": "Sprite", "name": "well_down", "width": 256, "height": 256, "scale": 1.0}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -24,13 +24,13 @@
|
||||||
"inventory_count": 0,
|
"inventory_count": 0,
|
||||||
"placement": "fixed",
|
"placement": "fixed",
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 8793,
|
{"_type": "Tile", "display": "\u2259",
|
||||||
"foreground": "devices/fg:stairs_up",
|
"foreground": [24, 205, 189],
|
||||||
"background": "devices/fg:stairs_up"
|
"background": [24, 205, 189]
|
||||||
},
|
},
|
||||||
{"_type": "Device",
|
{"_type": "Device",
|
||||||
"config": {},
|
"config": {"test": true},
|
||||||
"events": ["STAIRS_UP"]},
|
"events": ["Events::GUI::STAIRS_UP"]},
|
||||||
{"_type": "Sprite", "name": "rope_vines_up", "width": 256, "height": 256, "scale": 1.0}
|
{"_type": "Sprite", "name": "rope_vines_up", "width": 256, "height": 256, "scale": 1.0}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -40,66 +40,14 @@
|
||||||
"description": "Watch where you're going.",
|
"description": "Watch where you're going.",
|
||||||
"inventory_count": 0,
|
"inventory_count": 0,
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 95,
|
{"_type": "Tile", "display": "\u1ac7",
|
||||||
"foreground": "devices/fg:tripwire",
|
"foreground": [24, 205, 189],
|
||||||
"background": "devices/bg:tripwire"
|
"background": [24, 205, 189]
|
||||||
},
|
},
|
||||||
{"_type": "Device", "config": {}, "events": ["TRAP"]},
|
{"_type": "Device",
|
||||||
|
"config": {"test": true},
|
||||||
|
"events": ["Events::GUI::TRAP"]},
|
||||||
{"_type": "Sprite", "name": "tripwire_trap", "width": 256, "height": 256, "scale": 1.0}
|
{"_type": "Sprite", "name": "tripwire_trap", "width": 256, "height": 256, "scale": 1.0}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"BARREL_SMALL": {
|
|
||||||
"id": "BARREL_SMALL",
|
|
||||||
"name": "Small Barrel",
|
|
||||||
"description": "A small rotten barrel that may hold things.",
|
|
||||||
"components": [
|
|
||||||
{"_type": "Tile", "display": 85,
|
|
||||||
"foreground": "devices/fg:barrel",
|
|
||||||
"background": "devices/bg:barrel"
|
|
||||||
},
|
|
||||||
{"_type": "Device", "config": {}, "events": ["LOOT_CONTAINER"]},
|
|
||||||
{"_type": "Sprite", "name": "barrel_small", "width": 256, "height": 256, "scale": 1.0},
|
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"GRAVE_STONE": {
|
|
||||||
"id": "GRAVE_STONE",
|
|
||||||
"name": "Grave Stone",
|
|
||||||
"description": "Something died here. Was this your doing?",
|
|
||||||
"components": [
|
|
||||||
{"_type": "Tile", "display": 8687,
|
|
||||||
"foreground": "devices/fg:grave_stone",
|
|
||||||
"background": "devices/bg:grave_stone"
|
|
||||||
},
|
|
||||||
{"_type": "Device", "config": {}, "events": ["LOOT_CONTAINER"]},
|
|
||||||
{"_type": "Sprite", "name": "grave_stone", "width": 256, "height": 256, "scale": 1.0},
|
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"DEAD_BODY_LOOTABLE": {
|
|
||||||
"id": "DEAD_BODY_LOOTABLE",
|
|
||||||
"name": "Grave Stone",
|
|
||||||
"description": "Something died here. Was this your doing?",
|
|
||||||
"components": [
|
|
||||||
{"_type": "Tile", "display": 1890,
|
|
||||||
"foreground": "devices/fg:dead_body_lootable",
|
|
||||||
"background": "devices/bg:dead_body_lootable"
|
|
||||||
},
|
|
||||||
{"_type": "Device", "config": {}, "events": ["LOOT_CONTAINER"]},
|
|
||||||
{"_type": "Sprite", "name": "dead_body_lootable", "width": 256, "height": 256, "scale": 1.0},
|
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"DEAD_BODY": {
|
|
||||||
"id": "DEAD_BODY",
|
|
||||||
"name": "Something Dead",
|
|
||||||
"description": "You can't loot this, weirdo.",
|
|
||||||
"components": [
|
|
||||||
{"_type": "Tile", "display": 1939,
|
|
||||||
"foreground": "devices/fg:dead_body",
|
|
||||||
"background": "devices/bg:dead_body"
|
|
||||||
},
|
|
||||||
{"_type": "Sprite", "name": "dead_body", "width": 256, "height": 256, "scale": 1.0}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
Before Width: | Height: | Size: 665 KiB After Width: | Height: | Size: 665 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
@ -2,43 +2,24 @@
|
||||||
"PLAYER_TILE": {
|
"PLAYER_TILE": {
|
||||||
"placement": "fixed",
|
"placement": "fixed",
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 10733,
|
{"_type": "Tile", "display": "\ua66b",
|
||||||
"foreground": "enemies/fg:player",
|
"foreground": [255, 200, 125],
|
||||||
"background": "color:transparent"
|
"background": [30, 20, 75]
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 200, "max_hp": 200, "damage": 10, "dead": false},
|
{"_type": "Combat", "hp": 200, "max_hp": 200, "damage": 10, "dead": false},
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||||
{"_type": "Collision", "has": true},
|
{"_type": "LightSource", "strength": 45, "radius": 2.0}
|
||||||
{"_type": "LightSource", "strength": 35, "radius": 2.0}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"GOLD_SAVIOR": {
|
|
||||||
"components": [
|
|
||||||
{"_type": "Tile", "display": 42586,
|
|
||||||
"foreground": "enemies/fg:gold_savior",
|
|
||||||
"background": "color:transparent"
|
|
||||||
},
|
|
||||||
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false},
|
|
||||||
{"_type": "Collision", "has": true},
|
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
|
||||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
|
||||||
{"_type": "Personality", "hearing_distance": 5, "tough": true},
|
|
||||||
{"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3, "stationary": false},
|
|
||||||
{"_type": "Sprite", "name": "gold_savior", "width": 256, "height": 256, "width": 256, "height": 256, "scale": 1.0},
|
|
||||||
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"KNIGHT": {
|
"KNIGHT": {
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 2216,
|
{"_type": "Tile", "display": "\u088d",
|
||||||
"foreground": "enemies/fg:knight",
|
"foreground": [131, 213, 238],
|
||||||
"background": "color:transparent"
|
"background": [30, 20, 75]
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false},
|
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false},
|
||||||
{"_type": "Collision", "has": true},
|
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
{"_type": "EnemyConfig", "hearing_distance": 5},
|
||||||
{"_type": "Personality", "hearing_distance": 5, "tough": true},
|
|
||||||
{"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3, "stationary": false},
|
{"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3, "stationary": false},
|
||||||
{"_type": "Sprite", "name": "armored_knight", "width": 256, "height": 256, "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "armored_knight", "width": 256, "height": 256, "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"}
|
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"}
|
||||||
|
@ -46,47 +27,41 @@
|
||||||
},
|
},
|
||||||
"AXE_RANGER": {
|
"AXE_RANGER": {
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 1898,
|
{"_type": "Tile", "display": "\u076a",
|
||||||
"foreground": "enemies/fg:axe_ranger",
|
"foreground": [156, 172, 197],
|
||||||
"background": "color:transparent"
|
"background": [30, 20, 75]
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false},
|
{"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false},
|
||||||
{"_type": "Collision", "has": true},
|
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": true},
|
{"_type": "Motion", "dx": 0, "dy": 0, "random": true},
|
||||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
{"_type": "EnemyConfig", "hearing_distance": 5},
|
||||||
{"_type": "Personality", "hearing_distance": 5, "tough": true},
|
|
||||||
{"_type": "Sprite", "name": "axe_ranger", "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "axe_ranger", "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 1, "speed": 0.6, "stationary": false},
|
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.6, "stationary": false},
|
||||||
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"}
|
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"RAT_GIANT": {
|
"RAT_GIANT": {
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 2220,
|
{"_type": "Tile", "display": "\u08ac",
|
||||||
"foreground": "enemies/fg:rat_giant",
|
"foreground": [205, 164, 246],
|
||||||
"background": "color:transparent"
|
"background": [30, 20, 75]
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 2, "dead": false},
|
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
||||||
{"_type": "Collision", "has": true},
|
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
{"_type": "EnemyConfig", "hearing_distance": 10},
|
||||||
{"_type": "Personality", "hearing_distance": 5, "tough": true},
|
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0, "stationary": false},
|
||||||
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 1, "speed": 1.0, "stationary": false},
|
|
||||||
{"_type": "Sprite", "name": "rat_with_sword", "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "rat_with_sword", "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"}
|
{"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"SPIDER_GIANT_HAIRY": {
|
"SPIDER_GIANT_HAIRY": {
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 1218,
|
{"_type": "Tile", "display": "\u08ea",
|
||||||
"foreground": "enemies/fg:spider_giant",
|
"foreground": [205, 164, 246],
|
||||||
"background": "color:transparent"
|
"background": [30, 20, 75]
|
||||||
},
|
},
|
||||||
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
|
||||||
{"_type": "Collision", "has": true},
|
|
||||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
{"_type": "EnemyConfig", "hearing_distance": 10},
|
||||||
{"_type": "Personality", "hearing_distance": 5, "tough": true},
|
|
||||||
{"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0, "stationary": false},
|
{"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0, "stationary": false},
|
||||||
{"_type": "Sprite", "name": "hairy_spider", "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "hairy_spider", "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"}
|
{"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"}
|
||||||
|
|
BIN
assets/evil_eye-sprites.png
Normal file
After Width: | Height: | Size: 316 KiB |
BIN
assets/evil_eye_test-256.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/evil_eye_test-512.png
Normal file
After Width: | Height: | Size: 204 KiB |
BIN
assets/floor_tile_test-256.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
assets/floor_tile_test-512.png
Normal file
After Width: | Height: | Size: 350 KiB |
BIN
assets/grave_stone-256.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
assets/hairy_spider-256.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
assets/hanging_brazier-256.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
assets/healing_potion_small-256.png
Normal file
After Width: | Height: | Size: 11 KiB |
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"healing_potion_small":
|
|
||||||
{"path": "assets/icons/healing_potion_small.png",
|
|
||||||
"frame_width": 96,
|
|
||||||
"frame_height": 96
|
|
||||||
},
|
|
||||||
"torch_horizontal_floor":
|
|
||||||
{"path": "assets/icons/torch_horizontal_floor.png",
|
|
||||||
"frame_width": 96,
|
|
||||||
"frame_height": 96
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 5.6 KiB |
|
@ -6,27 +6,87 @@
|
||||||
"inventory_count": 1,
|
"inventory_count": 1,
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "LightSource", "strength": 50, "radius": 2.5},
|
{"_type": "LightSource", "strength": 50, "radius": 2.5},
|
||||||
{"_type": "Tile", "display": 3848,
|
{"_type": "Tile", "display": "\u0f08",
|
||||||
"foreground": "items/fg:flame",
|
"foreground": [24, 120, 189],
|
||||||
"background": "color:transparent"
|
"background": [230,120, 120]
|
||||||
},
|
},
|
||||||
{"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"SWORD_RUSTY": {
|
||||||
|
"id": "SWORD_RUSTY",
|
||||||
|
"name": "Rusty Junk Sword",
|
||||||
|
"description": "A sword left to rot in a deep hole where it acquired a patina of dirt and tetanus. You aren't sure if it's more deadly for you to hold it or for the people you stab with it.",
|
||||||
|
"inventory_count": 1,
|
||||||
|
"components": [
|
||||||
|
{"_type": "Weapon", "damage": 15},
|
||||||
|
{"_type": "Tile", "display": "\u1e37",
|
||||||
|
"foreground": [24, 120, 189],
|
||||||
|
"background": [24, 120, 189]
|
||||||
|
},
|
||||||
|
{"_type": "Sprite", "name": "cinqueda", "width": 256, "height": 256, "scale": 1.0},
|
||||||
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"BARREL_SMALL": {
|
||||||
|
"id": "BARREL_SMALL",
|
||||||
|
"name": "Small Barrel",
|
||||||
|
"description": "A small rotten barrel that may hold things.",
|
||||||
|
"components": [
|
||||||
|
{"_type": "Tile", "display": "\uaaea",
|
||||||
|
"foreground": [150, 100, 189],
|
||||||
|
"background": [150, 100, 189]
|
||||||
|
},
|
||||||
|
{"_type": "Loot", "amount": 10},
|
||||||
|
{"_type": "Sprite", "name": "barrel_small", "width": 256, "height": 256, "scale": 1.0},
|
||||||
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
|
],
|
||||||
|
"inventory_count": 1
|
||||||
|
},
|
||||||
|
"TORCH_PILLAR": {
|
||||||
|
"id": "TORCH_PILLAR",
|
||||||
|
"name": "Light Hanging from Ceiling",
|
||||||
|
"description": "Light Hanging from Ceiling",
|
||||||
|
"inventory_count": 0,
|
||||||
|
"components": [
|
||||||
|
{"_type": "Tile", "display": "\u077e",
|
||||||
|
"foreground": [24, 205, 210],
|
||||||
|
"background": [24, 205, 210]
|
||||||
|
},
|
||||||
|
{"_type": "LightSource", "strength": 50, "radius": 2.8},
|
||||||
|
{"_type": "Sprite", "name": "torch_pillar", "width": 256, "height": 256, "scale": 1.0},
|
||||||
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
|
]
|
||||||
|
},
|
||||||
"POTION_HEALING_SMALL": {
|
"POTION_HEALING_SMALL": {
|
||||||
"id": "POTION_HEALING_SMALL",
|
"id": "POTION_HEALING_SMALL",
|
||||||
"name": "Small Healing Potion",
|
"name": "Small Healing Potion",
|
||||||
"description": "A small healing potion.",
|
"description": "A small healing potion.",
|
||||||
"inventory_count": 1,
|
"inventory_count": 1,
|
||||||
"components": [
|
"components": [
|
||||||
{"_type": "Tile", "display": 1003,
|
{"_type": "Tile", "display": "\u03eb",
|
||||||
"foreground": "items/fg:potion",
|
"foreground": [255, 205, 189],
|
||||||
"background": "color:transparent"
|
"background": [255, 205, 189]
|
||||||
},
|
},
|
||||||
{"_type": "Curative", "hp": 20},
|
{"_type": "Curative", "hp": 20},
|
||||||
{"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256, "scale": 1.0},
|
{"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256, "scale": 1.0},
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"GRAVE_STONE": {
|
||||||
|
"id": "GRAVE_STONE",
|
||||||
|
"name": "Grave Stone",
|
||||||
|
"description": "Something died here. Was this your doing?",
|
||||||
|
"inventory_count": 1,
|
||||||
|
"components": [
|
||||||
|
{"_type": "Tile", "display": "\u21ef",
|
||||||
|
"foreground": [32, 123, 164],
|
||||||
|
"background": [24, 205, 189]
|
||||||
|
},
|
||||||
|
{"_type": "Loot", "amount": 10},
|
||||||
|
{"_type": "Sprite", "name": "grave_stone", "width": 256, "height": 256, "scale": 1.0},
|
||||||
|
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 4.1 KiB |
BIN
assets/left_gui.png
Normal file
After Width: | Height: | Size: 85 KiB |
|
@ -1,140 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 35,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 8284,
|
|
||||||
"x": 64,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 11590,
|
|
||||||
"x": 128,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 10899,
|
|
||||||
"x": 192,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 9256,
|
|
||||||
"x": 256,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 9608,
|
|
||||||
"x": 320,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 10747,
|
|
||||||
"x": 384,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": false,
|
|
||||||
"display": 8285,
|
|
||||||
"x": 448,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 1003,
|
|
||||||
"x": 512,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 3848,
|
|
||||||
"x": 576,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 85,
|
|
||||||
"x": 0,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 1939,
|
|
||||||
"x": 64,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 1890,
|
|
||||||
"x": 128,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 8687,
|
|
||||||
"x": 192,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 6105,
|
|
||||||
"x": 256,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 8793,
|
|
||||||
"x": 320,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 95,
|
|
||||||
"x": 384,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 1898,
|
|
||||||
"x": 448,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 42586,
|
|
||||||
"x": 512,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 2216,
|
|
||||||
"x": 576,
|
|
||||||
"y": 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 10733,
|
|
||||||
"x": 0,
|
|
||||||
"y": 128
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 2220,
|
|
||||||
"x": 64,
|
|
||||||
"y": 128
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"centered": true,
|
|
||||||
"display": 1218,
|
|
||||||
"x": 128,
|
|
||||||
"y": 128
|
|
||||||
}
|
|
||||||
]
|
|
Before Width: | Height: | Size: 9.5 KiB |
|
@ -1,81 +0,0 @@
|
||||||
{
|
|
||||||
"color": {
|
|
||||||
"transparent": [100, 100, 100, 100],
|
|
||||||
"BAD": [255, 0, 0]
|
|
||||||
},
|
|
||||||
"gui/theme": {
|
|
||||||
"black": [0, 0, 0, 255],
|
|
||||||
"dark_dark": [10, 10, 10, 255],
|
|
||||||
"dark_mid": [30, 30, 30, 255],
|
|
||||||
"dark_light": [60, 60, 60, 255],
|
|
||||||
"mid": [100, 100, 100, 255],
|
|
||||||
"light_dark": [150, 150, 150, 255],
|
|
||||||
"light_mid": [200, 200, 200, 255],
|
|
||||||
"light_light": [230, 230, 230, 255],
|
|
||||||
"white": [255, 255, 255, 255],
|
|
||||||
"fill_color": "gui/theme:dark_mid",
|
|
||||||
"text_color": "gui/theme:light_light",
|
|
||||||
"bg_color": "gui/theme:mid",
|
|
||||||
"border_color": "gui/theme:dark_dark",
|
|
||||||
"bg_color_dark": "gui/theme:black"
|
|
||||||
},
|
|
||||||
"map/theme": {
|
|
||||||
"black": [0, 0, 0, 255],
|
|
||||||
"dark_dark": [10, 10, 10, 255],
|
|
||||||
"dark_mid": [30, 30, 30, 255],
|
|
||||||
"dark_light": [60, 60, 60, 255],
|
|
||||||
"mid": [100, 100, 100, 255],
|
|
||||||
"light_dark": [150, 150, 150, 255],
|
|
||||||
"light_mid": [200, 200, 200, 255],
|
|
||||||
"light_light": [230, 230, 230, 255],
|
|
||||||
"white": [255, 255, 255, 255]
|
|
||||||
},
|
|
||||||
"items/fg": {
|
|
||||||
"flame": "map/theme:white",
|
|
||||||
"potion": "map/theme:white"
|
|
||||||
},
|
|
||||||
"enemies/fg": {
|
|
||||||
"player": "map/theme:white",
|
|
||||||
"gold_savior": "map/theme:white",
|
|
||||||
"knight": "map/theme:white",
|
|
||||||
"axe_ranger": "map/theme:white",
|
|
||||||
"rat_giant": "map/theme:white",
|
|
||||||
"spider_giant": "map/theme:white"
|
|
||||||
},
|
|
||||||
"tiles/fg": {
|
|
||||||
"floor_tile": "map/theme:mid",
|
|
||||||
"wall_plain": "map/theme:dark_mid",
|
|
||||||
"wall_moss": "map/theme:dark_light",
|
|
||||||
"ceiling_black": "color:transparent",
|
|
||||||
"lava_floor": [200, 100, 100],
|
|
||||||
"gray_stone_floor_light": [40, 60, 180],
|
|
||||||
"wood_wall": "map/theme:dark_mid"
|
|
||||||
},
|
|
||||||
"tiles/bg": {
|
|
||||||
"floor_tile": "map/theme:dark_dark",
|
|
||||||
"wall_plain": "map/theme:dark_dark",
|
|
||||||
"wall_moss": "map/theme:light_dark",
|
|
||||||
"ceiling_black": "color:transparent",
|
|
||||||
"lava_floor": "map/theme:dark_dark",
|
|
||||||
"gray_stone_floor_light": "map/theme:dark_mid",
|
|
||||||
"wood_wall": "map/theme:dark_dark"
|
|
||||||
},
|
|
||||||
"devices/fg": {
|
|
||||||
"stairs_down": [24, 205, 189],
|
|
||||||
"stairs_up": [24, 205, 189],
|
|
||||||
"tripwire": [24, 205, 189],
|
|
||||||
"barrel": [150, 100, 189],
|
|
||||||
"grave_stone": [32, 123, 164],
|
|
||||||
"dead_body": [32, 123, 164],
|
|
||||||
"dead_body_lootable": [32, 123, 164]
|
|
||||||
},
|
|
||||||
"devices/bg": {
|
|
||||||
"stairs_down": [24, 205, 189],
|
|
||||||
"stairs_up": [24, 205, 189],
|
|
||||||
"tripwire": [24, 205, 189],
|
|
||||||
"barrel": [150, 100, 189],
|
|
||||||
"grave_stone": [24, 205, 189],
|
|
||||||
"dead_body": [24, 205, 189],
|
|
||||||
"dead_body_lootable": [24, 205, 189]
|
|
||||||
}
|
|
||||||
}
|
|
BIN
assets/rat-king-boss-fight-test-small.jpg
Normal file
After Width: | Height: | Size: 211 KiB |
BIN
assets/rat_king-256.png
Normal file
After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 1,011 KiB After Width: | Height: | Size: 1,011 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 466 KiB After Width: | Height: | Size: 466 KiB |
BIN
assets/rat_with_sword-256.png
Normal file
After Width: | Height: | Size: 20 KiB |
|
@ -1,202 +0,0 @@
|
||||||
{
|
|
||||||
"profile": {
|
|
||||||
"has_spikes": 0,
|
|
||||||
"has_magick": 1,
|
|
||||||
"shiny_bauble": 2,
|
|
||||||
"cursed_item": 3,
|
|
||||||
"$does_physical": 4,
|
|
||||||
"$does_magick": 5,
|
|
||||||
"$does_damage": 6,
|
|
||||||
"$user_cursed": 7,
|
|
||||||
"$does_healing": 8,
|
|
||||||
"$damage_boost": 9,
|
|
||||||
"$large_boost": 10,
|
|
||||||
"$is_complete": 11
|
|
||||||
},
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"name": "pierce_type",
|
|
||||||
"cost": 100,
|
|
||||||
"needs": {
|
|
||||||
"has_spikes": true,
|
|
||||||
"$is_complete": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$does_physical": true,
|
|
||||||
"$does_damage": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "magick_type",
|
|
||||||
"cost": 100,
|
|
||||||
"needs": {
|
|
||||||
"$is_complete": false,
|
|
||||||
"has_magick": true
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$does_magick": true,
|
|
||||||
"$does_damage": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "combined",
|
|
||||||
"cost": 0,
|
|
||||||
"needs": {
|
|
||||||
"$does_damage": true
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$is_complete": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "boost_magick",
|
|
||||||
"cost": 0,
|
|
||||||
"needs": {
|
|
||||||
"shiny_bauble": true,
|
|
||||||
"$does_magick": true,
|
|
||||||
"$does_damage": true,
|
|
||||||
"$is_complete": false,
|
|
||||||
"$user_cursed": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$damage_boost": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "boost_damage_large",
|
|
||||||
"cost": 0,
|
|
||||||
"needs": {
|
|
||||||
"$user_cursed": true,
|
|
||||||
"$is_complete": false,
|
|
||||||
"$does_damage": true
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$large_boost": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "curses_user",
|
|
||||||
"cost": 1000,
|
|
||||||
"needs": {
|
|
||||||
"$is_complete": false,
|
|
||||||
"cursed_item": true
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$user_cursed": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "heals_user",
|
|
||||||
"cost": 0,
|
|
||||||
"needs": {
|
|
||||||
"cursed_item": true,
|
|
||||||
"$does_damage": false
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"$does_healing": true,
|
|
||||||
"$is_complete": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"states": {
|
|
||||||
"initial": {
|
|
||||||
"shiny_bauble": false,
|
|
||||||
"cursed_item": false,
|
|
||||||
"has_spikes": false,
|
|
||||||
"has_magick": false,
|
|
||||||
"$user_cursed": false,
|
|
||||||
"$does_damage": false,
|
|
||||||
"$is_complete": false,
|
|
||||||
"$does_healing": false,
|
|
||||||
"$does_magick": false,
|
|
||||||
"$does_physical": false,
|
|
||||||
"$large_boost": false,
|
|
||||||
"$damage_boost": false
|
|
||||||
},
|
|
||||||
"final": {
|
|
||||||
"$user_cursed": true,
|
|
||||||
"$does_damage": true,
|
|
||||||
"$is_complete": true,
|
|
||||||
"$does_healing": true,
|
|
||||||
"$does_magick": true,
|
|
||||||
"$does_physical": true,
|
|
||||||
"$large_boost": true,
|
|
||||||
"$damage_boost": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"actions": [
|
|
||||||
"boost_magick",
|
|
||||||
"pierce_type",
|
|
||||||
"magick_type",
|
|
||||||
"heals_user",
|
|
||||||
"curses_user",
|
|
||||||
"boost_damage_large",
|
|
||||||
"combined"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"effects": {
|
|
||||||
"boost_magick": {
|
|
||||||
"damage": 10,
|
|
||||||
"kind": 2,
|
|
||||||
"element": 2,
|
|
||||||
"probability": 1.0
|
|
||||||
},
|
|
||||||
"pierce_type": {
|
|
||||||
"damage": 11,
|
|
||||||
"kind": 1,
|
|
||||||
"probability": 1.0
|
|
||||||
},
|
|
||||||
"magick_type": {
|
|
||||||
"damage": 12,
|
|
||||||
"kind": 2,
|
|
||||||
"element": 1,
|
|
||||||
"probability": 1.0
|
|
||||||
},
|
|
||||||
"heals_user": {
|
|
||||||
"damage": 13,
|
|
||||||
"probability": 1.0
|
|
||||||
},
|
|
||||||
"curses_user": {
|
|
||||||
"damage": 14,
|
|
||||||
"probability": 0.5
|
|
||||||
},
|
|
||||||
"boost_damage_large": {
|
|
||||||
"damage": 15,
|
|
||||||
"probability": 1.0
|
|
||||||
},
|
|
||||||
"combined": {
|
|
||||||
"damage": 16,
|
|
||||||
"probability": 1.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"junk": {
|
|
||||||
"chess_pawn": {
|
|
||||||
"name": "chess_pawn",
|
|
||||||
"provides": ["cursed_item"]
|
|
||||||
},
|
|
||||||
"dirty_kerchief": {
|
|
||||||
"name": "dirty_kerchief",
|
|
||||||
"provides": ["has_magick"]
|
|
||||||
},
|
|
||||||
"mushroom": {
|
|
||||||
"name": "mushroom",
|
|
||||||
"provides": ["has_magick"]
|
|
||||||
},
|
|
||||||
"pocket_watch": {
|
|
||||||
"name": "pocket_watch",
|
|
||||||
"provides": ["shiny_bauble"]
|
|
||||||
},
|
|
||||||
"rusty_nails": {
|
|
||||||
"name": "rusty_nails",
|
|
||||||
"provides": ["has_spikes"]
|
|
||||||
},
|
|
||||||
"severed_finger": {
|
|
||||||
"name": "severed_finger",
|
|
||||||
"provides": ["cursed_item"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"starting_junk": [
|
|
||||||
"pocket_watch", "mushroom", "rusty_nails"
|
|
||||||
]
|
|
||||||
}
|
|
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 8.9 KiB |