Compare commits

..

No commits in common. 'master' and 'version-0.1' have entirely different histories.

  1. 2
      .gitignore
  2. 2
      .vimrc_proj
  3. 49
      Makefile
  4. 133
      README.md
  5. 212
      ai.cpp
  6. 65
      ai.hpp
  7. 74
      ai_debug.cpp
  8. 10
      ai_debug.hpp
  9. 0
      amt/main.cpp
  10. 0
      amt/matrix.hpp
  11. 0
      amt/pixel.hpp
  12. 1
      amt/raycaster.cpp
  13. 0
      amt/raycaster.hpp
  14. 0
      amt/texture.cpp
  15. 0
      amt/texture.hpp
  16. 0
      amt/thread.hpp
  17. 117
      animation.cpp
  18. 17
      animation.hpp
  19. 376
      ansi_parser.cpp
  20. 23
      ansi_parser.hpp
  21. 167
      ansi_parser.rl
  22. 141
      assets/ai.json
  23. 12
      assets/animations.json
  24. BIN
      assets/armored_knight_1-256.png
  25. BIN
      assets/armored_knight_1-512.png
  26. BIN
      assets/axe_ranger-256.png
  27. BIN
      assets/blood_splatter-256.png
  28. 4
      assets/bosses.json
  29. BIN
      assets/ceiling_test-256.png
  30. BIN
      assets/ceiling_test-512.png
  31. BIN
      assets/ceiling_worm-256.png
  32. BIN
      assets/cinqueda_1-256.png
  33. BIN
      assets/cinqueda_1-512.png
  34. 258
      assets/config.json
  35. 84
      assets/devices.json
  36. 0
      assets/devils_fingers_background.jpg
  37. 0
      assets/devils_fingers_sprite.png
  38. 0
      assets/devils_fingers_stage.png
  39. 0
      assets/down_the_well.jpg
  40. 71
      assets/enemies.json
  41. BIN
      assets/evil_eye-sprites.png
  42. BIN
      assets/evil_eye_test-256.png
  43. BIN
      assets/evil_eye_test-512.png
  44. BIN
      assets/floor_tile_test-256.png
  45. BIN
      assets/floor_tile_test-512.png
  46. BIN
      assets/grave_stone-256.png
  47. BIN
      assets/hairy_spider-256.png
  48. BIN
      assets/hanging_brazier-256.png
  49. BIN
      assets/healing_potion_small-256.png
  50. 12
      assets/icons.json
  51. BIN
      assets/icons/healing_potion_small.png
  52. BIN
      assets/icons/torch_horizontal_floor.png
  53. 72
      assets/items.json
  54. BIN
      assets/items/broken_locket.png
  55. BIN
      assets/items/broken_pen_knife.png
  56. BIN
      assets/items/broken_yoyo.png
  57. BIN
      assets/items/chess_pawn.png
  58. BIN
      assets/items/cinqueda.png
  59. BIN
      assets/items/dirty_kerchief.png
  60. BIN
      assets/items/dubious_combination.png
  61. BIN
      assets/items/healing_postion_small.png
  62. BIN
      assets/items/healing_potion_small.png
  63. BIN
      assets/items/leather_pouch.png
  64. BIN
      assets/items/mushroom.png
  65. BIN
      assets/items/pocket_watch.png
  66. BIN
      assets/items/rusty_nails.png
  67. BIN
      assets/items/severed_finger.png
  68. BIN
      assets/items/stone_doll_cursed.png
  69. BIN
      assets/items/torch_crappy.png
  70. BIN
      assets/items/torch_horizontal_floor.png
  71. BIN
      assets/items/wood_barrel_small.png
  72. BIN
      assets/left_gui.png
  73. 140
      assets/map_tiles.json
  74. BIN
      assets/map_tiles.png
  75. 81
      assets/palette.json
  76. BIN
      assets/rat-king-boss-fight-test-small.jpg
  77. BIN
      assets/rat_king-256.png
  78. 0
      assets/rat_king_2_frame_animation.png
  79. 0
      assets/rat_king_boss_fight_background.jpg
  80. 0
      assets/rat_king_boss_fight_sprite.png
  81. BIN
      assets/rat_with_sword-256.png
  82. 202
      assets/rituals.json
  83. BIN
      assets/rituals/broken_locket-128.png
  84. BIN
      assets/rituals/broken_locket-64.png
  85. BIN
      assets/rituals/broken_pen_knife-128.png
  86. BIN
      assets/rituals/broken_pen_knife-64.png
  87. BIN
      assets/rituals/broken_yoyo-128.png
  88. BIN
      assets/rituals/broken_yoyo-64.png
  89. BIN
      assets/rituals/chess_pawn-128.png
  90. BIN
      assets/rituals/chess_pawn-64.png
  91. BIN
      assets/rituals/dirty_kerchief-128.png
  92. BIN
      assets/rituals/dirty_kerchief-64.png
  93. BIN
      assets/rituals/dubious_combination-128.png
  94. BIN
      assets/rituals/dubious_combination-64.png
  95. BIN
      assets/rituals/leather_pouch-128.png
  96. BIN
      assets/rituals/leather_pouch-64.png
  97. BIN
      assets/rituals/mushroom-128.png
  98. BIN
      assets/rituals/mushroom-64.png
  99. BIN
      assets/rituals/pocket_watch-128.png
  100. BIN
      assets/rituals/pocket_watch-64.png
  101. Some files were not shown because too many files have changed in this diff Show More

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\ .

@ -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
ragel -Vp -I $(ROOT_DIR) -o $@ $<
%.png: %.dot
dot -Tpng $< -o $@
build:
meson compile -j 10 -C $(ROOT_DIR)/builddir
asset_build: build build: ansi_parser.cpp lel_parser.cpp
./builddir/icongen meson compile -j 10 -C builddir
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: asset_build build test: build
./builddir/runtests -d yes "[pathing]" ./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 "[pathing]" 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

@ -1,5 +1,134 @@
# Repository Moved # The Artisanal Handcrafted Retro-Future "3D" Dungeon Crawler
This repository is archived here and moved to https://git.zedshaw.games/games/raycaster Welcome to my latest obsession, and turn based dungeon crawler in the style of old school raycasted
games like _Wizardry_, _Might and Magic_, _Ultima_, and similar games. The game uses SFML 3.x as
it's "cross platform layer" but other than that everything is hand coded by me. It's fully
artisinal, created manually, with nothing but a terminal and vim. No LSPs, AI, or anything.
This code is truly a work of art. Like an espresso at that Speakeasy Coffee bar in Brooklyn nobody
talks about. You know the one? You don't? Oh sorry, I thought you were cool.
## STATUS
Currently it's only officially tested on Windows, but I'm not really using anything OS specific (I
think).
## Where's the LICENSE?
You don't need a LICENSE that gives everything away to thieving corporations just to publish your
works online. Nobody makes artists, musicians, painters, photographers, or sculptors get a license
before posting online, so why do programmers need one? You worried you'll get sued? Ok, so just put
a disclaimer but why do you _also_ have to give your hard work away for anyone to steal and profit
from just so they don't sue you?
You don't, and no matter what the OSI says, nobody can sue you if they steal your code and cause a
plane to crash. _They_ would get sued for stealing your code and putting it in a plane, not you.
Requiring _only_ programmers to release their code with a license to avoid lawsuits creates a
[Chilling Effect](https://www.thefire.org/research-learn/chilling-effect-overview) on programmer free speech and that violates the First Amendment.
So this code isn't licensed, it's copyright by default. I'm publishing it using my free speech
rights to express myself and that means you can look at it the same as if I posted a painting or an
essay on my blog. I obviously can't sue you for just looking at it and playing the game because I
published it so you can, but _that doesn't mean you own it._ You can't resell it, fork it,
nothing.
Just grab the code and play it. That's it. Tell people about it. Fair use says you can even record
videos reviewing it and talking about it.
See? That's how Free Speech works. You don't need a LICENSE.
## Build Instructions
On all platforms you'll need these components:
* [Meson](https://mesonbuild.com/) -- which needs Python.
* 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.
* [git](https://git-scm.com/) -- Which should be on almost every platform, and is installed by default with my Windows setup scripts.
### Windows Instructions
I primarily develop in Windows using the above setup, so this should work the best. Open [Windows
Terminal](https://github.com/microsoft/terminal) and run these commands _one at a time_. Don't
copy-past bomb this:
```shell
git clone https://git.learnjsthehardway.com/learn-code-the-hard-way/raycaster.git
cd raycaster
# ignore the errors the first time
./scripts/reset_build.ps1
# first compile takes a while
make
# this copies the binary so you can run it
make run
```
After that the game should be running. It'll be in different states depending on how far I've
pushed it, but you should at least have a few enemies, some loot, and rooms light in it. Go find them.
## Linux and OSX
Linux and OSX have the same requirements as Windows and almost the same install steps. The only
difference is that once you get your developer tools installed then you only need [Meson](https://mesonbuild.com/). Linux and OSX should have everything else you need or there's a package for it.
Once you have that installed you can run these commands:
```shell
git clone https://git.learnjsthehardway.com/learn-code-the-hard-way/raycaster.git
cd raycaster
# ignore the errors the first time
./scripts/reset_build.sh
# first compile takes a while
make
./builddir/raycaster
```
You don't need `make run` because Linux and OSX are sane operating systems that don't lock every
damn thing a process touches.
### Other Platforms
No testing done on other platforms but let me know if you get it to build somewhere fun and I'll
mention it.
## Development Guide
You can look in the `notes.txt` file for my informal TODO list of things to fix and make. I'm not
really accepting contributions from others, but if you want to follow along then that's what I'm
doing.
If you're just starting out in C++ or programming then the project is designed to be readable by
someone who knows very little. Every file is small and should be easy to read. I don't use any
insane tricks or weird C++ idioms. I also try to avoid too many external libraries so I'll use
plain old [std::vector]() and [std::unordered_map]() rather than external libraries that might be
faster. This is done _on purpose_ so people (myself included) can learn about the basics of C++ and
the STL.
I also don't do a lot of performance tuning or obsession over _THE CACHE_. Clean, simple, readable
code is more important than squeezing 4% performance out of the code. I do however attempt to
design things so that it doesn't do useless work because the fastest thing you can do in a computer
is nothing. If I can architect away a performance issue and not make the code too complex then I'll
do that instead.
That means if you have a suggestion for a micro-benchmark improvement that will dramatically boost
performance, but the code is convoluted and hard to understand, then it won't work. If your
suggestion is interesting and provides a massive boost then let me know and I'll check it out. But,
I would also like statistics that show it's better, not just your word.
## Known Bugs
It's early so probably a bunch of bugs.
## 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.
* You need to run the .command script in Application/your python that updates the SSL certs.
* You have to give iTerm access to your keystrokes...because wtf it already has them?

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;
}
}

@ -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);
}

@ -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;
}
}

@ -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);
} }

@ -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);
}

@ -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;
}

@ -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);
};

@ -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;
}

@ -1,141 +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": {
"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": "face_enemy",
"cost": 10,
"needs": {
"no_more_enemies": false,
"in_combat": false,
"enemy_found": true
},
"effects": {
"in_combat": true,
"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",
"face_enemy",
"collect_items",
"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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

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},

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

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": false},
{"_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": false}, {"_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"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

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
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

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"}
]
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

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
}
]

Binary file not shown.

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]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 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

Binary file not shown.

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"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Some files were not shown because too many files have changed in this diff Show More