ru:: stater system implemented

This commit is contained in:
Zeno Rogue
2025-12-06 21:56:52 +01:00
parent f26ff4c900
commit 1983f2ce66
8 changed files with 214 additions and 133 deletions
+73 -43
View File
@@ -198,6 +198,17 @@ template<class T> struct statarray : array<T, qstat> {
const T& operator [] (stat s) const { return array<T, qstat>::operator[] ((int) s); };
};
struct stater {
virtual stater& act(const string& s, int& i, int _i) = 0;
virtual stater& act(const string& s, bool& b, bool _b) = 0;
virtual stater& act(const string& s, ld& d, ld _d) = 0;
virtual stater& act(const string& s, string& w, const string& _w) = 0;
virtual stater& act(const string& s, color_t& c, color_t _c) = 0;
virtual stater& act(const string& s, intxy& xy, intxy _xy) { act(s+".x", xy.x, _xy.x); act(s+".y", xy.y, _xy.y); return self; }
virtual stater& act(const string& s, xy& p, xy _p) { act(s+".x", p.x, _p.x); act(s+".y", p.y, _p.y); return self; }
virtual stater& only_full() { return self; }
};
struct entity {
string name;
virtual ~entity() {}
@@ -221,27 +232,26 @@ struct entity {
int invinc_end;
virtual int max_hp() { return 100; }
virtual void regenerate() {}
virtual bool visible(room *r);
void clearg() {
virtual xy default_where() { return {screen_x/2., screen_y/2.}; }
virtual xy default_vel() { return {0, 0}; }
virtual bool default_existing() { return true; }
virtual void hs(stater& s) {
println(hlog, "called hs for ", get_name(), " '", name, "' with default_where() of ", make_pair(default_where().x, default_where().y));
// println(hlog, name + ": where is ", tie(where.x, where.y), " respawn is ", tie(respawn.x, respawn.y), " default_where is ", make_pair(default_where().x, default_where().y));
s.act("where", where, default_where())
.act("vel", vel, default_vel())
.act("existing", existing, default_existing())
.act("hp", hp, max_hp())
.act("invinc_end", invinc_end, -1)
.act("destroyed", destroyed, false);
gwhere = where;
gvel = vel;
}
entity() {
where = xy(screen_x / 2., screen_y / 2.);
vel = xy(0, 0);
existing = true;
destroyed = false; invinc_end = -1;
clearg();
};
void postfix() {
hp = max_hp();
}
data get_dat();
virtual bool hidden() { return false; }
@@ -347,12 +357,7 @@ struct man : public entity {
virtual int max_hp() { return 10 * current.stats[stat::con]; }
bool can_see(entity& e);
man() {
facing = 1; attack_facing = 1;
for(auto s: allstats) base_stats[s] = 10;
next.reset(); current.reset();
postfix();
}
man();
xy siz() override {
if(morphed) return morphed->siz();
return {12, 12};
@@ -388,12 +393,14 @@ extern man m;
struct moving_platform : public entity {
xy ctr;
ld radius, shift;
ld cur_t;
virtual int width() { return 3; }
virtual eWall platform_type() { return wWall; }
xy siz() override { return {12.*width(), 12}; }
string glyph() override { return "#"; }
color_t color() override { return 0xFFFFFFFF; }
virtual xy location_at(ld t) = 0;
virtual xy default_where() override { return location_at(cur_t); }
void draw() override;
void act() override;
virtual moving_platform* as_platform() { return this; }
@@ -426,7 +433,13 @@ struct rope_platform : public moving_platform {
void draw() override;
};
struct timed_orb : public entity {
/* entities with a defined 'respawn' location */
struct located_entity : public entity {
xy respawn;
xy default_where() override { return respawn; }
};
struct timed_orb : public located_entity {
int duration;
xy siz() override { return {18, 18}; }
string glyph() override { return "O"; }
@@ -440,12 +453,13 @@ struct timed_orb : public entity {
string get_help() override { return "These orbs activate mechanisms for a limited time."; }
};
struct npc_or_trader : public entity {
struct npc_or_trader : public located_entity {
string text;
int talk_on;
xy siz() override { return {12, 12}; }
void act() override;
string get_name() override { return name; }
virtual void hs(stater& s) override { entity::hs(s); s.act("talk_on", talk_on, 0); }
};
struct npc : public npc_or_trader {
@@ -466,22 +480,20 @@ struct trader : public npc_or_trader {
virtual struct trader* as_trader() { return this; }
};
struct enemy : public entity {
xy respawn;
struct enemy : public located_entity {
int num_kills;
void on_kill() override {
entity::on_kill();
num_kills++;
m.experience += (base_xp() * 25 + 24) / (4 + num_kills) / (4 + num_kills);
}
enemy() { num_kills = 0; postfix(); }
virtual void hs(stater& s) override { located_entity::hs(s); s.only_full().act("kills", num_kills, 0); }
void attacked(int s) override;
void regenerate() override { where = respawn; vel = xy(0, 0); existing = true; hp = max_hp(); }
virtual int base_xp() { return 0; }
bool hit_by_missile(missile *m) override { return true; }
};
struct vtrap : public entity {
struct vtrap : public located_entity {
xy siz() override { return {6, 18}; }
string glyph() override { return "^"; }
color_t color() override { return 0xD00000FF; }
@@ -496,6 +508,8 @@ struct cat_color {
color_t col;
};
void sact(stater& s, string t, cat_color co) { s.act(t+".name", co.name, "black").act(t+".col", co.col, 0xFFFFFFFF); }
struct cat : public enemy {
cat_color col;
cat();
@@ -504,6 +518,7 @@ struct cat : public enemy {
color_t color() override { return col.col; }
string get_name() override { return col.name + " cat"; }
string get_help() override { return "Do not fight cats!"; }
virtual void hs(stater& s) override { enemy::hs(s); sact(s, "color", col); }
int base_xp() { return 10; }
int max_hp() { return 20; }
};
@@ -543,6 +558,7 @@ struct frog : public enemy {
string get_help() override { return "What a nice frog."; }
int base_xp() { return 30; }
int max_hp() { return 30; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("jphase", jphase, 0).act("jump_at", jump_at, 0); }
};
struct giantfrog : public frog {
@@ -556,7 +572,7 @@ struct giantfrog : public frog {
};
struct ghost : public enemy {
int xp, hp;
int ghost_xp, ghost_hp, extra_invinc;
bool flipped;
xy siz() override { return {12, 12}; }
string glyph() override { return "g"; }
@@ -564,9 +580,14 @@ struct ghost : public enemy {
void act() override;
string get_name() override { return "ghost"; }
string get_help() override { return "This apparition looks strangely like you..."; }
int base_xp() { return hp; }
int max_hp() { return xp; }
void regenerate() override {}
int base_xp() { return ghost_hp; }
int max_hp() { return ghost_xp; }
xy default_where() override { return where; } // do not reset on fountains
virtual void hs(stater& s) override {
enemy::hs(s);
s.act("extra_invinc", extra_invinc, 2 * game_fps).
only_full().act("flipped", flipped, false).act("xp", ghost_xp, 50).act("hp", ghost_hp, 100).act("where", where, {0, 0});
}
};
struct snake : public enemy {
@@ -578,10 +599,10 @@ struct snake : public enemy {
void attacked(int s) override;
string get_name() override { return "snake"; }
string get_help() override { return "A nasty dungeon snake."; }
void regenerate() override { enemy::regenerate(); dir = respawn_dir; }
int base_xp() override { return 10; }
int max_hp() override { return 30; }
virtual int bite() { return 25; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("dir", dir, respawn_dir); }
};
struct disnake : public snake {
@@ -605,9 +626,9 @@ struct kestrel : public enemy {
void attacked(int s) override;
string get_name() override { return "kestrel"; }
string get_help() override { return "A standard dungeon kestrel."; }
void regenerate() override { enemy::regenerate(); vel = respawn_vel; }
int base_xp() { return 30; }
int max_hp() { return 30; }
xy default_vel() override { return respawn_vel; }
};
struct gridbug : public enemy {
@@ -620,6 +641,7 @@ struct gridbug : public enemy {
string get_help() override { return "You are not sure whether this is some kind of insect or some glitch in the fabric of the reality."; }
int base_xp() { return 10; }
int max_hp() { return 10; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("nextmove", next_move, 0); }
};
struct bat : public enemy {
@@ -633,6 +655,7 @@ struct bat : public enemy {
string get_help() override { return "A cave bat."; }
int base_xp() { return 10; }
int max_hp() { return 10; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("nextchange", next_change, 0); }
};
struct guineapig : public enemy {
@@ -647,9 +670,9 @@ struct guineapig : public enemy {
void attacked(int s) override;
string get_name() override { return "guinea pig"; }
string get_help() override { return "A standard dungeon guinea pig."; }
void regenerate() override { enemy::regenerate(); falling = true; spindir = respawn_spindir; }
int base_xp() { return 30; }
int max_hp() { return 30; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("falling", falling, true).act("spindir", spindir, respawn_spindir).act("ca", ca, 0); }
};
struct icicle : public enemy {
@@ -658,14 +681,16 @@ struct icicle : public enemy {
xy siz() override { return {10, 10}; }
string glyph() override { return "|"; }
color_t color() override { return 0xA0A0F0FF; }
xy default_vel() override { auto dat = get_dat(); return { 0, 150 * 0.005 * dat.modv * dat.d }; }
void act() override;
string get_name() override { return "icicle"; }
string get_help() override { return "A dangerous looking icicle."; }
int base_xp() { return 1; }
int max_hp() { return 1; }
virtual void hs(stater& s) override { enemy::hs(s); s.act("state", state, 0); }
};
struct hint : public entity {
struct hint : public located_entity {
string hint_text;
int state;
xy size;
@@ -677,25 +702,26 @@ struct hint : public entity {
bool have_help() { return false; }
};
struct item : public entity {
int id, qty;
struct item : public located_entity {
power *p;
int qty;
string pickup_message;
xy siz() override { return {12, 12}; }
string glyph() override { return powers[id].get_glyph(); }
color_t color() override { return powers[id].get_color(); }
string glyph() override { return p->get_glyph(); }
color_t color() override { return p->get_color(); }
void act() override {
stay_on_screen();
kino();
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
addMessage(pickup_message);
add_revert(death_revert, {"ITEM", powers[id].name, its(powers[id].qty_filled), its(powers[id].qty_owned)});
add_revert(death_revert, {"ITEM", p->name, its(p->qty_filled), its(p->qty_owned)});
add_revert(death_revert, {"EXIST", name});
powers[id].picked_up(qty);
p->picked_up(qty);
existing = false;
}
}
string get_name() override { return powers[id].name; }
string get_help() override { return powers[id].get_desc(); }
string get_name() override { return p->name; }
string get_help() override { return p->get_desc(); }
};
struct shopitem : public item {
@@ -716,11 +742,13 @@ struct shopitem : public item {
string get_name() override { if(bought) return its(price) + " gold"; return item::get_name(); }
string get_help() override { if(bought) return "You have bought something from this shop. The trader has stored the gold here."; return item::get_help() + "\n\nPrice: " + its(price); }
shopitem* as_shopitem() override { return this; }
virtual void hs(stater& s) override { item::hs(s); s.act("bought", bought, false).act("last_intersect", last_intersect, 0); }
};
struct loot : public item {
entity *owner;
bool dropped;
virtual bool default_existing() { return dropped; }
void act() {
item::act();
if(on_floor) {
@@ -735,6 +763,7 @@ struct loot : public item {
dropped = true; existing = true;
}
}
virtual void hs(stater& s) override { s.act("dropped", dropped, false); item::hs(s); }
};
struct missile : public entity {
@@ -746,6 +775,7 @@ struct missile : public entity {
void act() override;
void hit_wall() override { destroyed = true; }
struct missile* as_missile() override { return this; }
virtual void hs(stater& s) override { entity::hs(s); s.act("power", power, 0); }
};
struct ice_missile : public missile {
+1 -1
View File
@@ -446,6 +446,7 @@ void frog::attacked(int dmg) {
}
void ghost::act() {
if(gframeid >= invinc_end && extra_invinc) gframeid += extra_invinc, extra_invinc = 0;
hyperpoint g = to_hyper(where);
hyperpoint h = to_hyper(m.where);
ld d = hdist(g, h);
@@ -800,7 +801,6 @@ void icicle::act() {
kino();
if(on_floor) break;
}
regenerate();
}
if(state == 0) {
auto w = m.where;
+59 -69
View File
@@ -134,57 +134,56 @@ void load_room(fhstream& f, cell *c) {
auto pos = s.find(" ");
if(pos != string::npos) {
string cap = s.substr(0, pos);
string param = s.substr(pos+1);
auto nam = [&] (entity& b) {
if(param == "") { println(hlog, "got nothing"); b.name = "NOTHING"; return; }
if(param[0] >= '0' && param[0] <= '9') { println(hlog, "error: expecting a name, got ", param); b.name = "UNNAMED"; return; }
pos = param.find(" "); b.name = param.substr(0, pos); param = param.substr(pos + 1);
string param = s.substr(pos+1) + " ";
auto cutoff = [&] (const string& val) {
if(param == "") { println(hlog, "parameter missing"); return val; }
pos = param.find(" "); auto res = param.substr(0, pos); param = param.substr(pos + 1);
return res;
};
auto nam = [&] (entity& b) { b.name = cutoff("NOTHING"); };
auto get_ld = [&] () { return atof(cutoff("0").c_str()); };
auto get_int = [&] () { return atoi(cutoff("0").c_str()); };
auto get_color = [&] () { color_t col; sscanf(cutoff("0").c_str(), "%08x", &col); return col; };
auto get_xy = [&] () { ld x = get_ld(); ld y = get_ld(); return xy{x, y}; };
if(cap == "START") {
fountain_room = current_room = &r;
sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y);
m.where = get_xy();
fountain_where = m.where;
}
else if(cap == "ITEM") {
auto b = std::make_unique<item>();
b->qty = 1;
sscanf(param.c_str(), "%lf%lf%d", &b->where.x, &b->where.y, &b->qty);
s = scanline_noblank(f);
b->id = -1;
for(int i=0; i<isize(powers); i++) if(powers[i].name == s) b->id = i;
if(b->id == -1) println(hlog, "error: unknown item name ", s), b->id = 0;
b->respawn = get_xy();
b->qty = param == "" ? 1 : get_int();
println(hlog, "qty is ", b->qty);
b->p = &find_power(scanline_noblank(f));
b->name = b->pickup_message = scanline_noblank(f);
r.entities.emplace_back(std::move(b));
}
else if(cap == "LOOT") {
auto b = std::make_unique<loot>();
b->qty = 1;
b->owner = &*r.entities.back();
sscanf(param.c_str(), "%d", &b->qty);
s = scanline_noblank(f);
b->id = -1;
b->where = xy(320, 200);
for(int i=0; i<isize(powers); i++) if(powers[i].name == s) b->id = i;
if(b->id == -1) println(hlog, "error: unknown loot name ", s), b->id = 0;
b->qty = param == "" ? 1 : get_int();
b->p = &find_power(scanline_noblank(f));
b->name = b->pickup_message = scanline_noblank(f);
b->existing = false; b->dropped = false;
b->existing = false;
r.entities.emplace_back(std::move(b));
println(hlog, "loot pushed");
}
else if(cap == "SHOPITEM") {
auto b = std::make_unique<shopitem>();
b->qty = 1; b->qty1 = 0;
sscanf(param.c_str(), "%lf%lf%d%d%d", &b->where.x, &b->where.y, &b->price, &b->qty, &b->qty1);
s = scanline_noblank(f);
b->id = -1;
for(int i=0; i<isize(powers); i++) if(powers[i].name == s) b->id = i;
if(b->id == -1) println(hlog, "error: unknown item name ", s), b->id = 0;
b->respawn = get_xy();
b->price = get_int();
b->qty = param == "" ? 1 : get_int();
b->qty1 = param == "" ? 0 : get_int();
b->p = &find_power(scanline_noblank(f));
b->name = b->pickup_message = scanline_noblank(f);
r.entities.emplace_back(std::move(b));
}
else if(cap == "NPC") {
auto b = std::make_unique<npc>();
sscanf(param.c_str(), "%lf%lf%08x", &b->where.x, &b->where.y, &b->col);
b->respawn = get_xy();
b->col = get_color();
s = scanline_noblank(f);
b->sglyph = s[0];
b->name = s.substr(1);
@@ -193,87 +192,73 @@ void load_room(fhstream& f, cell *c) {
}
else if(cap == "TRADER") {
auto b = std::make_unique<trader>();
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = get_xy();
b->name = scanline_noblank(f);
b->text = scanline_noblank(f);
r.entities.emplace_back(std::move(b));
}
else if(cap == "BOAR") {
auto b = std::make_unique<boar>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "GIANTFROG") {
auto b = std::make_unique<giantfrog>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "FROG") {
auto b = std::make_unique<frog>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "TIMEORB") {
auto b = std::make_unique<timed_orb>(); nam(*b);
ld dur = 0;
sscanf(param.c_str(), "%lf%lf%lf", &b->where.x, &b->where.y, &dur);
b->duration = dur * game_fps;
b->respawn = get_xy();
b->duration = get_ld() * game_fps;
r.entities.emplace_back(std::move(b));
}
else if(cap == "BAT") {
auto b = std::make_unique<bat>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "GUINEAPIG") {
auto b = std::make_unique<guineapig>(); nam(*b);
sscanf(param.c_str(), "%lf%lf%lf%d", &b->where.x, &b->where.y, &b->pigvel, &b->spindir);
b->pigvel /= game_fps; b->falling = true; b->vel = xy{0,0};
b->respawn = b->where; b->respawn_spindir = b->spindir; b->postfix();
b->respawn = get_xy();
b->pigvel = get_ld() / game_fps;
b->respawn_spindir = get_int();
r.entities.emplace_back(std::move(b));
}
else if(cap == "ICICLE") {
auto b = std::make_unique<icicle>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->state = 0; b->vel = xy{0,0};
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "VTRAP") {
auto b = std::make_unique<vtrap>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
auto dat = b->get_dat();
b->vel.x = 0; b->vel.y = 150 * 0.005 * dat.modv * dat.d;
b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "GRIDBUG") {
auto b = std::make_unique<gridbug>(); nam(*b);
sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);
b->respawn = b->where; b->postfix();
b->respawn = get_xy();
r.entities.emplace_back(std::move(b));
}
else if(cap == "KESTREL") {
auto b = std::make_unique<kestrel>(); nam(*b);
sscanf(param.c_str(), "%lf%lf%lf%lf", &b->where.x, &b->where.y, &b->vel.x, &b->vel.y);
b->vel *= xy(block_x, block_y) / game_fps;
b->respawn = b->where; b->respawn_vel = b->vel; b->postfix();
b->respawn = get_xy();
b->respawn_vel = get_xy() * xy(block_x, block_y) / game_fps;
r.entities.emplace_back(std::move(b));
}
else if(cap == "SNAKE") {
auto b = std::make_unique<snake>(); nam(*b);
sscanf(param.c_str(), "%lf%lf%d", &b->where.x, &b->where.y, &b->dir);
b->respawn = b->where; b->respawn_dir = b->dir; b->postfix();
b->respawn = get_xy();
b->respawn_dir = get_int();
r.entities.emplace_back(std::move(b));
}
else if(cap == "FERRIS") {
ld cx, cy, radius; int qty;
sscanf(param.c_str(), "%lf%lf%lf%d", &cx, &cy, &radius, &qty);
ld cx = get_ld(), cy = get_ld(), radius = get_ld(); int qty = get_int();
for(int i=0; i<qty; i++) {
auto b = std::make_unique<ferris_platform>();
@@ -283,8 +268,9 @@ void load_room(fhstream& f, cell *c) {
}
}
else if(cap == "ROPE") {
ld cx, cy, radius, period, shift, max_swing; int qty;
sscanf(param.c_str(), "%lf%lf%lf%d%lf%lf%lf", &cx, &cy, &radius, &qty, &period, &shift, &max_swing);
ld cx = get_ld(), cy = get_ld(), radius = get_ld();
int qty = get_int();
ld period = get_ld(), shift = get_ld(), max_swing = get_ld();
for(int i=0; i<qty; i++) {
auto b = std::make_unique<rope_platform>();
@@ -298,12 +284,12 @@ void load_room(fhstream& f, cell *c) {
}
else if(cap == "PENDULUM") {
auto b = std::make_unique<pendulum_platform>();
sscanf(param.c_str(), "%lf%lf%lf%lf%lf%lf", &b->a.x, &b->a.y, &b->b.x, &b->b.y, &b->period, &b->shift);
b->a = get_xy(); b->b = get_xy(); b->period = get_ld(); b->shift = get_ld();
r.entities.emplace_back(std::move(b));
}
else if(cap == "HINT") {
auto b = std::make_unique<hint>();
sscanf(param.c_str(), "%lf%lf%lf%lf", &b->where.x, &b->where.y, &b->size.x, &b->size.y);
b->respawn = get_xy(); b->size = get_xy();
b->hint_text = scanline_noblank(f);
r.entities.emplace_back(std::move(b));
}
@@ -328,13 +314,17 @@ void load_map(string fname) {
}
else err("load_map", s);
}
for(auto& [c,r]: rooms)
for(auto& e: r.entities) if(e->name != "") {
while(entity_by_name.count(e->name)) {
println(hlog, "error: double entity name: ", e->name);
e->name += "'";
for(auto& [c,r]: rooms) {
for(auto& e: r.entities) {
e->hs(resetter);
if(e->name != "") {
while(entity_by_name.count(e->name)) {
println(hlog, "error: double entity name: ", e->name);
e->name += "'";
}
entity_by_name[e->name] = &*e;
}
}
entity_by_name[e->name] = &*e;
}
}
+9 -2
View File
@@ -10,9 +10,9 @@ room *stable_room;
xy stable_where;
void regenerate_all() {
m.hp = m.max_hp();
m.hs(fountain_resetter);
for(auto& p: powers) p.refill();
for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate();
for(auto& r: rooms) for(auto& e: r.second.entities) e->hs(fountain_resetter);
revert_all(fountain_revert);
current_target = nullptr;
shuffle_all();
@@ -48,6 +48,13 @@ void statdata::reset() {
mods.clear();
}
man::man() {
facing = 1; attack_facing = 1;
for(auto s: allstats) base_stats[s] = 10;
next.reset(); current.reset();
hs(fountain_resetter);
}
void man::act() {
kino();
+13 -11
View File
@@ -247,14 +247,16 @@ void gen_powers() {
if(m.experience >= 50) {
auto g = std::make_unique<ghost>();
g->where = w; g->hp = hp; g->xp = m.experience/2; m.experience -= g->xp; g->postfix();
g->extra_invinc = 2 * game_fps;
g->where = w; g->ghost_hp = hp; g->ghost_xp = m.experience/2; m.experience -= g->ghost_xp;
g->hs(fountain_resetter);
cr->entities.emplace_back(std::move(g));
}
auto bones = std::make_unique<item>();
bones->qty = 10;
bones->where = stable_where;
bones->id = gold_id;
bones->p = &powers[gold_id];
bones->pickup_message = "You got it back.";
stable_room->entities.emplace_back(std::move(bones));
}
@@ -511,15 +513,15 @@ void gen_powers() {
if(it == 0 && on && si->existing && !si->bought) {
done_something = true;
addMessage(si->pickup_message);
power_death_revert(powers[si->id]);
powers[si->id].qty_owned += si->qty; powers[si->id].qty_filled += si->qty1;
power_death_revert(*si->p);
si->p->qty_owned += si->qty; si->p->qty_filled += si->qty1;
add_revert(death_revert, {"EXIST", si->name});
si->existing = false;
}
else if(it == 0 && on && si->existing && si->bought) {
done_something = true;
addMessage("You get some gold.");
power_death_revert(powers[gold_id]);
power_death_revert(*si->p);
powers[gold_id].qty_owned += si->price; powers[gold_id].qty_filled += si->price;
add_revert(death_revert, {"EXIST", si->name});
si->existing = false;
@@ -527,30 +529,30 @@ void gen_powers() {
else if((it ? !done_something : on) && !si->existing && !si->bought) {
done_something = true;
addMessage("You rethink your purchase.");
power_death_revert(powers[si->id]);
powers[si->id].qty_owned -= si->qty; powers[si->id].qty_filled -= si->qty1;
power_death_revert(*si->p);
si->p->qty_owned -= si->qty; si->p->qty_filled -= si->qty1;
add_revert(death_revert, {"UNEXIST", si->name});
si->existing = true;
}
else if((it ? !done_something : on) && !si->existing && si->bought) {
done_something = true;
addMessage("You rethink your actions.");
power_death_revert(powers[gold_id]);
power_death_revert(*si->p);
powers[gold_id].qty_owned -= si->price; powers[gold_id].qty_filled -= si->price;
add_revert(death_revert, {"UNEXIST", si->name});
si->existing = true;
}
else if(it == 0 && on_trader && !si->existing && d.p->qty_owned >= si->price) {
done_something = true;
addMessage("You buy the " + powers[si->id].get_name() + ".");
power_death_revert(powers[gold_id]);
addMessage("You buy the " + si->p->get_name() + ".");
power_death_revert(*si->p);
powers[gold_id].qty_owned -= si->price; powers[gold_id].qty_filled -= si->price;
si->existing = true; si->bought = true;
add_revert(death_revert, {"UNBOUGHT", si->name});
}
else if(it == 0 && on_trader && !si->existing && !si->bought) {
done_something = true;
addMessage("You have not enough gold to buy the " + powers[si->id].get_name() + ".");
addMessage("You have not enough gold to buy the " + si->p->get_name() + ".");
}
}
if(!done_something) addMessage("You count your gold. You have " + its(d.p->qty_owned) + " gold.");
+4 -5
View File
@@ -53,11 +53,10 @@ randeff trap_snake("Snake Hair", "Lets you create snakes that can be used to dis
if(d.mode == rev::start || (d.mode == rev::active && d.keystate == 1)) {
auto d = m.get_dat();
auto mi = std::make_unique<disnake>();
mi->where = m.where + xy(m.facing * m.get_scale() * m.siz().y * 0.45, 0);
mi->vel = m.vel + xy(m.facing * d.modv * 2, -d.modv * 3.5);
mi->clearg();
mi->respawn = m.where + xy(m.facing * m.get_scale() * m.siz().y * 0.45, 0);
mi->hs(fountain_resetter);
mi->invinc_end = gframeid + 50;
mi->postfix();
mi->vel = m.vel + xy(m.facing * d.modv * 2, -d.modv * 3.5);
mi->dir = m.facing * 2;
current_room->entities.emplace_back(std::move(mi));
}
@@ -109,9 +108,9 @@ randeff fire_spit("Fiery Spit", "Lets you spit fire.", "You feel fire in your mo
for(int i=1; i<10; i++) {
auto d = m.get_dat();
auto mi = std::make_unique<fire_missile>();
mi->hs(fountain_resetter);
mi->where = m.where + xy(m.facing * m.get_scale() * m.siz().y * 0.45, 0);
mi->vel = m.vel + xy(m.facing * d.modv * i, d.modv * (10-i) / 5.);
mi->clearg();
mi->index = i; mi->power = m.current.stats[stat::wis] * 2 / 5 + 1e-6;
current_room->entities.emplace_back(std::move(mi));
}
+2 -2
View File
@@ -25,6 +25,7 @@ Have fun!
#include "globals.cpp"
#include "classes.cpp"
#include "staters.cpp"
#include "geometry.cpp"
#include "entity.cpp"
#include "man.cpp"
@@ -32,7 +33,7 @@ Have fun!
#include "render.cpp"
#include "portals.cpp"
#include "powers.cpp"
#include "save.cpp"
#include "load-world.cpp"
#include "stats.cpp"
#include "randeff.cpp"
#include "reverts.cpp"
@@ -160,7 +161,6 @@ void playing_frame() {
m.where = w1;
m.vel *= vmul;
switch_to_adjacent_room(cr);
m.clearg();
}
}
+53
View File
@@ -0,0 +1,53 @@
namespace rogue_unlike {
// state manager
struct nop : stater {
virtual stater& act(const string& s, int& i, int _i) { return self; }
virtual stater& act(const string& s, ld& d, ld _d) { return self; }
virtual stater& act(const string& s, bool& b, bool _b) { return self; }
virtual stater& act(const string& s, string& w, const string& _w) { return self; }
virtual stater& act(const string& s, color_t& c, color_t _c) { return self; }
} nop;
struct changeseeker : stater {
bool changed = false;
stater& act(const string& s, int& i, int _i) override { if(i != _i) changed = true; return self; }
stater& act(const string& s, ld& d, ld _d) override { if(d != _d) changed = true; return self; }
stater& act(const string& s, bool& b, bool _b) override { if(b != _b) changed = true; return self; }
stater& act(const string& s, string& w, const string& _w) override { if(w != _w) changed = true; return self; }
stater& act(const string& s, color_t& c, color_t _c) override { if(c != _c) changed = true; return self; }
};
struct saver : stater {
fhstream f;
stater& act(const string& s, int& i, int _i) override { if(i != _i) println(f, s, "=", i); return self; }
stater& act(const string& s, ld& d, ld _d) override { if(d != _d) println(f, s, "=", d); return self; }
stater& act(const string& s, bool& b, bool _b) override { if(b != _b) println(f, s, "=", b); return self; }
stater& act(const string& s, string& w, const string& _w) override { if(w != _w) println(f, s, "=", w); return self; }
stater& act(const string& s, color_t& c, color_t _c) override { if(c != _c) println(f, s, "=", format("%08X", c)); return self; }
};
struct loader : stater {
string name, value;
bool loaded = false;
stater& act(const string& s, int& i, int _i) override { if(s == name) loaded = true, i = atoi(value.c_str()); return self; }
stater& act(const string& s, ld& d, ld _d) override { if(s == name) loaded = true, d = atof(value.c_str()); return self; }
stater& act(const string& s, bool& b, bool _b) override { if(s == name) loaded = true, b = atoi(value.c_str()); return self; }
stater& act(const string& s, string& w, const string& _w) override { if(s == name) loaded = true, w = value; return self; }
stater& act(const string& s, color_t& c, color_t _c) override { if(s == name) loaded = true, sscanf(value.c_str(), "%08X", &c); return self; }
};
struct resetter : stater {
stater& act(const string& s, int& i, int _i) override { i = _i; return self; }
stater& act(const string& s, ld& d, ld _d) override { d = _d; return self; }
stater& act(const string& s, bool& b, bool _b) override { b = _b; return self; }
stater& act(const string& s, string& w, const string& _w) override { w = _w; return self; }
stater& act(const string& s, color_t& c, color_t _c) override { c = _c; return self; }
} resetter;
struct fountain_resetter : resetter {
virtual stater& only_full() { return nop; }
} fountain_resetter;
}