From 1983f2ce66e09f133734aae502388c25d607547e Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sat, 6 Dec 2025 21:56:52 +0100 Subject: [PATCH] ru:: stater system implemented --- rogueviz/ru/classes.cpp | 116 ++++++++++++++++++++------------- rogueviz/ru/entity.cpp | 2 +- rogueviz/ru/load-world.cpp | 128 +++++++++++++++++-------------------- rogueviz/ru/man.cpp | 11 +++- rogueviz/ru/powers.cpp | 24 +++---- rogueviz/ru/randeff.cpp | 9 ++- rogueviz/ru/ru.cpp | 4 +- rogueviz/ru/staters.cpp | 53 +++++++++++++++ 8 files changed, 214 insertions(+), 133 deletions(-) create mode 100644 rogueviz/ru/staters.cpp diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index de144957..b6a88047 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -198,6 +198,17 @@ template struct statarray : array { const T& operator [] (stat s) const { return array::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 { diff --git a/rogueviz/ru/entity.cpp b/rogueviz/ru/entity.cpp index c86f2e08..7bb133b4 100644 --- a/rogueviz/ru/entity.cpp +++ b/rogueviz/ru/entity.cpp @@ -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; diff --git a/rogueviz/ru/load-world.cpp b/rogueviz/ru/load-world.cpp index 25e24e82..c71031ef 100644 --- a/rogueviz/ru/load-world.cpp +++ b/rogueviz/ru/load-world.cpp @@ -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(); - 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; iid = 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(); - 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; iid = 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(); - 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; iid = 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(); - 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(); - 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); @@ -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(); @@ -298,12 +284,12 @@ void load_room(fhstream& f, cell *c) { } else if(cap == "PENDULUM") { auto b = std::make_unique(); - 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(); - 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; } } diff --git a/rogueviz/ru/man.cpp b/rogueviz/ru/man.cpp index 8361421e..88a1d0f8 100644 --- a/rogueviz/ru/man.cpp +++ b/rogueviz/ru/man.cpp @@ -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(); diff --git a/rogueviz/ru/powers.cpp b/rogueviz/ru/powers.cpp index 0e1f2648..3a091d58 100644 --- a/rogueviz/ru/powers.cpp +++ b/rogueviz/ru/powers.cpp @@ -247,14 +247,16 @@ void gen_powers() { if(m.experience >= 50) { auto g = std::make_unique(); - 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(); 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."); diff --git a/rogueviz/ru/randeff.cpp b/rogueviz/ru/randeff.cpp index 72b8a486..298b47e1 100644 --- a/rogueviz/ru/randeff.cpp +++ b/rogueviz/ru/randeff.cpp @@ -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(); - 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(); + 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)); } diff --git a/rogueviz/ru/ru.cpp b/rogueviz/ru/ru.cpp index 7a709ed3..fc6e67e9 100644 --- a/rogueviz/ru/ru.cpp +++ b/rogueviz/ru/ru.cpp @@ -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(); } } diff --git a/rogueviz/ru/staters.cpp b/rogueviz/ru/staters.cpp new file mode 100644 index 00000000..74835d06 --- /dev/null +++ b/rogueviz/ru/staters.cpp @@ -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; + +}