Compare commits
291 Commits
version-0.
...
master
@ -1 +1 @@ |
||||
set makeprg=meson\ compile\ -C\ . |
||||
set makeprg=make\ -f\ ../Makefile\ build |
||||
|
@ -1,47 +1,69 @@ |
||||
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
all: build test |
||||
|
||||
reset: |
||||
ifeq '$(OS)' 'Windows_NT' |
||||
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
||||
else |
||||
sh -x ./scripts/reset_build.sh
|
||||
endif |
||||
|
||||
%.cpp : %.rl |
||||
ragel -o $@ $<
|
||||
ragel -I $(ROOT_DIR) -G1 -o $@ $<
|
||||
|
||||
build: ansi_parser.cpp lel_parser.cpp |
||||
meson compile -j 10 -C builddir
|
||||
%.dot: %.rl |
||||
ragel -Vp -I $(ROOT_DIR) -o $@ $<
|
||||
|
||||
%.png: %.dot |
||||
dot -Tpng $< -o $@
|
||||
|
||||
build: |
||||
meson compile -j 10 -C $(ROOT_DIR)/builddir
|
||||
|
||||
asset_build: build |
||||
./builddir/icongen
|
||||
|
||||
release_build: |
||||
meson --wipe builddir -Db_ndebug=true --buildtype release
|
||||
meson compile -j 10 -C builddir
|
||||
|
||||
debug_build: |
||||
meson setup --wipe builddir --buildtype debug
|
||||
meson setup --wipe builddir -Db_ndebug=true --buildtype debugoptimized
|
||||
meson compile -j 10 -C builddir
|
||||
|
||||
tracy_build: |
||||
meson setup --wipe builddir --buildtype debugoptimized -Dtracy_enable=true -Dtracy:on_demand=true
|
||||
meson compile -j 10 -C builddir
|
||||
|
||||
test: build |
||||
./builddir/runtests
|
||||
test: asset_build build |
||||
./builddir/runtests "[map-sprite]"
|
||||
|
||||
run: build test |
||||
ifeq '$(OS)' 'Windows_NT' |
||||
powershell "cp ./builddir/zedcaster.exe ."
|
||||
./zedcaster
|
||||
else |
||||
./builddir/zedcaster
|
||||
endif |
||||
|
||||
debug: build |
||||
gdb --nx -x .gdbinit --ex run --args builddir/zedcaster.exe
|
||||
gdb --nx -x .gdbinit --ex run --args builddir/zedcaster
|
||||
|
||||
debug_run: build |
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe
|
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster
|
||||
|
||||
debug_walk: build |
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe t
|
||||
debug_walk: build test |
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster t
|
||||
|
||||
clean: |
||||
meson compile --clean -C builddir
|
||||
|
||||
debug_test: build |
||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests.exe -e
|
||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[map-sprite]"
|
||||
|
||||
win_installer: |
||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" win_installer.ifp'
|
||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
||||
|
||||
coverage_report: |
||||
powershell 'scripts/coverage_report.ps1'
|
||||
|
@ -0,0 +1,212 @@ |
||||
#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; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,64 @@ |
||||
#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(); |
||||
}; |
||||
|
||||
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); |
||||
} |
@ -0,0 +1,64 @@ |
||||
#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); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,10 @@ |
||||
#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); |
||||
} |
@ -0,0 +1,117 @@ |
||||
#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); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
#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); |
||||
} |
@ -1,376 +0,0 @@ |
||||
|
||||
#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; |
||||
} |
@ -1,23 +0,0 @@ |
||||
#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); |
||||
}; |
@ -1,167 +0,0 @@ |
||||
#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; |
||||
} |
@ -0,0 +1,125 @@ |
||||
{ |
||||
"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 |
||||
}, |
||||
"actions": [ |
||||
{ |
||||
"name": "find_enemy", |
||||
"cost": 5, |
||||
"needs": { |
||||
"detect_enemy": true, |
||||
"in_combat": false, |
||||
"no_more_enemies": false, |
||||
"enemy_found": false |
||||
}, |
||||
"effects": { |
||||
"enemy_found": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "run_away", |
||||
"cost": 0, |
||||
"needs": { |
||||
"tough_personality": false, |
||||
"in_combat": true, |
||||
"have_healing": false, |
||||
"health_good": 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": "use_healing", |
||||
"cost": 0, |
||||
"needs": { |
||||
"have_item": true, |
||||
"have_healing": true, |
||||
"in_combat": false, |
||||
"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", |
||||
"use_healing"], |
||||
"Enemy::actions": |
||||
["find_enemy", "run_away", "kill_enemy", "use_healing"] |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
{ |
||||
"ritual_blanket": { |
||||
"_type": "Animation", |
||||
"easing": 0, |
||||
"ease_rate": 0.5, |
||||
"scale": 1.0, |
||||
"simple": false, |
||||
"frames": 3, |
||||
"speed": 0.2, |
||||
"stationary": true |
||||
} |
||||
} |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 82 KiB |
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 |
Before Width: | Height: | Size: 1011 KiB After Width: | Height: | Size: 1011 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 |
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 818 KiB |
Before Width: | Height: | Size: 413 KiB After Width: | Height: | Size: 413 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 249 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 316 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 204 KiB |
Before Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 350 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 85 KiB |
@ -0,0 +1,128 @@ |
||||
[ |
||||
{ |
||||
"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": 8687, |
||||
"x": 64, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 10949, |
||||
"x": 128, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 8793, |
||||
"x": 192, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 95, |
||||
"x": 256, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 1898, |
||||
"x": 320, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 42586, |
||||
"x": 384, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 2189, |
||||
"x": 448, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 41981, |
||||
"x": 512, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 2220, |
||||
"x": 576, |
||||
"y": 64 |
||||
}, |
||||
{ |
||||
"centered": true, |
||||
"display": 1218, |
||||
"x": 0, |
||||
"y": 128 |
||||
} |
||||
] |
After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 211 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 20 KiB |
@ -0,0 +1,202 @@ |
||||
{ |
||||
"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" |
||||
] |
||||
} |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 28 KiB |
@ -0,0 +1,22 @@ |
||||
{ |
||||
"ui_shader": { |
||||
"file_name": "assets/shaders/ui_shader.frag", |
||||
"type": "fragment" |
||||
}, |
||||
"ERROR": { |
||||
"file_name": "assets/shaders/ui_error.frag", |
||||
"type": "fragment" |
||||
}, |
||||
"rayview_sprites": { |
||||
"file_name": "assets/shaders/rayview_sprites.frag", |
||||
"type": "fragment" |
||||
}, |
||||
"flame": { |
||||
"file_name": "assets/shaders/flame_trash.frag", |
||||
"type": "fragment" |
||||
}, |
||||
"lightning": { |
||||
"file_name": "assets/shaders/lightning_attack.frag", |
||||
"type": "fragment" |
||||
} |
||||
} |
@ -0,0 +1,79 @@ |
||||
#version 120 |
||||
uniform vec2 u_resolution; |
||||
uniform float u_time; |
||||
uniform sampler2D source; |
||||
uniform float u_mouse; |
||||
uniform float value = 0.2; |
||||
uniform int octaves=8; |
||||
|
||||
float random (in vec2 st) { |
||||
return fract(sin(dot(st.xy, |
||||
vec2(12.9898,78.233)))* |
||||
43758.5453123); |
||||
} |
||||
|
||||
float noise(in vec2 st) { |
||||
vec2 i = floor(st); |
||||
vec2 f = fract(st); |
||||
|
||||
float a = random(i); |
||||
float b = random(i + vec2(1.0, 0.0)); |
||||
float c = random(i + vec2(0.0, 1.0)); |
||||
float d = random(i + vec2(1.0, 1.0)); |
||||
|
||||
vec2 u = f * f * (3.0 - 2.0 * f); |
||||
|
||||
return mix(a, b, u.x) + |
||||
(c - a) * u.y * (1.0 - u.x) + |
||||
(d - b) * u.x * u.y; |
||||
} |
||||
|
||||
float fbm(in vec2 st) { |
||||
float v = 0.0; |
||||
float a = 0.5; |
||||
vec2 shift = vec2(100.0); |
||||
mat2 rot = mat2(cos(0.5), sin(0.5), |
||||
-sin(0.5), cos(0.5)); |
||||
|
||||
for(int i = 0; i < octaves; i++) { |
||||
v += a * noise(st); |
||||
st = rot * st * 2.0 + shift; |
||||
a *= 0.5; |
||||
} |
||||
|
||||
return v; |
||||
} |
||||
|
||||
void main() { |
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy * 3.0; |
||||
vec3 color = vec3(0.0); |
||||
|
||||
float speed = u_time * 10.0; |
||||
float value = 0.8; // cos(u_time) * cos(u_time); |
||||
|
||||
vec2 q = vec2(0.0); |
||||
q.x = fbm(st + 0.00 * speed); |
||||
q.y = fbm(st + vec2(1.0)); |
||||
|
||||
vec2 r = vec2(0,0); |
||||
r.x += fbm( st + 1.0*q + vec2(1.0, 0.0)+ 0.15* speed ); |
||||
r.y += fbm( st + 1.0*q + vec2(-1.0, 0.0)+ 0.126* speed); |
||||
|
||||
float f = fbm(st * r); |
||||
|
||||
color = mix(vec3(0.666667,0.619608, 0.122777), |
||||
vec3(0.666667,0.666667,0.498039), |
||||
clamp((f*f)*4.0,0.0,1.0)); |
||||
|
||||
color = mix(color, |
||||
vec3(0.666667, 0.122222, 0.0666667), |
||||
clamp(length(r.x), 0.0, 1.0)); |
||||
|
||||
color *= (f*f*f+0.5*f*f+0.6*f) * value; |
||||
|
||||
vec4 pixel = texture2D(source, gl_TexCoord[0].xy); |
||||
|
||||
float mask = color.r * pixel.a; |
||||
|
||||
gl_FragColor = gl_Color * vec4(color, mask) + pixel; |
||||
} |