From 2ae913ccfa3831f29a10d02f9164ac9f782ce495 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Mon, 5 May 2025 18:56:13 +0200 Subject: [PATCH] implemented the magic fountains (except ghosts and bones mechanics) --- rogueviz/ru/classes.cpp | 16 ++++++++++++-- rogueviz/ru/globals.cpp | 8 +++++++ rogueviz/ru/man.cpp | 37 +++++++++++++++++++++++++------ rogueviz/ru/powers.cpp | 48 ++++++++++++++++++++++++++++++++++------- rogueviz/ru/render.cpp | 2 +- rogueviz/ru/save.cpp | 3 ++- 6 files changed, 96 insertions(+), 18 deletions(-) diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index 71214ab6..1da2446f 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -25,7 +25,7 @@ struct power { flagtype flags; int random_flavor; void init(); - hr::function act, paused_act; + hr::function act, paused_act, dead_act; hr::function get_name; hr::function get_desc; hr::function get_glyph; @@ -37,6 +37,7 @@ struct power { power& be_weapon(); power& be_resource(string plural); power& while_paused(); + power& while_dead(); power& identified_name(string, string); power& be_wearable(string wear_effect, string remove_effect); power& be_jewelry(string jtype, string desc); @@ -44,6 +45,11 @@ struct power { }; extern vector powers; +extern power *extra_life; + +flagtype IDENTIFIED = Flag(1); +flagtype ACTIVE = Flag(2); +flagtype PARTIAL = Flag(4); struct bbox { int minx, miny, maxx, maxy; @@ -230,9 +236,10 @@ struct entity { } virtual bool reduce_hp(int x) { + if(hp < 0) return false; if(gframeid < invinc_end) return false; hp -= x; - if(hp < 0) on_kill(); + if(hp <= 0) on_kill(); invinc_end = gframeid + 150; return true; } @@ -270,6 +277,8 @@ struct man : public entity { virtual bool hurt_by_spikes() { return true; } string get_name() override { return "alchemist"; } string get_help() override { return "This is you."; } + + void on_kill() override; }; extern man m; @@ -403,6 +412,9 @@ struct item : public entity { kino(); if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { addMessage(pickup_message); + int q0 = powers[id].qty_filled; + int q1 = powers[id].qty_owned; + add_revert(death_revert, [this, q0, q1] { existing = true; powers[id].qty_filled = q0; powers[id].qty_owned = q1; }); powers[id].picked_up(qty); existing = false; } diff --git a/rogueviz/ru/globals.cpp b/rogueviz/ru/globals.cpp index 8f4ec615..ac19aad1 100644 --- a/rogueviz/ru/globals.cpp +++ b/rogueviz/ru/globals.cpp @@ -148,4 +148,12 @@ void asciiletter(ld minx, ld miny, ld maxx, ld maxy, const string& ch, color_t c void render_the_map(); void shuffle_all(); +using revert_stack = vector; + +revert_stack death_revert, fountain_revert; + +void add_revert(revert_stack& s, const reaction_t& what); + +void revert_all(revert_stack& s); + } diff --git a/rogueviz/ru/man.cpp b/rogueviz/ru/man.cpp index f1a46a99..a237aaed 100644 --- a/rogueviz/ru/man.cpp +++ b/rogueviz/ru/man.cpp @@ -4,6 +4,16 @@ void handle_powers(data& d); bool on_fountain; room *fountain_room; +xy fountain_where; + +void regenerate_all() { + m.hp = m.max_hp(); + for(auto& p: powers) p.refill(); + for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate(); + revert_all(fountain_revert); + current_target = nullptr; + shuffle_all(); + } void check_fountains() { bool next_on_fountain = false; @@ -14,13 +24,12 @@ void check_fountains() { if(b == wFountain) next_on_fountain = true; } if(next_on_fountain && !on_fountain) { - fountain_room = current_room; + if(extra_life->flags & ACTIVE) { + fountain_room = current_room; + fountain_where = m.where; + } addMessage("A magic fountain! You feel safe and refill your potions."); - m.hp = m.max_hp(); - for(auto& p: powers) p.refill(); - for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate(); - current_target = nullptr; - shuffle_all(); + regenerate_all(); } swap(on_fountain, next_on_fountain); } @@ -58,4 +67,20 @@ void man::act() { check_fountains(); } +void man::on_kill() { + entity::on_kill(); + if(extra_life->flags & ACTIVE) + addMessage("You die... Press [key:Extra Life] to revive."); + else + addMessage("You die... permanently. You will have to create a new character. Or just press [key:Extra Life] for a narrative cheat."); + } + +void add_revert(revert_stack& s, const reaction_t& what) { + s.push_back(what); + } + +void revert_all(revert_stack& s) { + while(!s.empty()) { s.back()(); s.pop_back(); } + } + } diff --git a/rogueviz/ru/powers.cpp b/rogueviz/ru/powers.cpp index bea75a86..c39bed70 100644 --- a/rogueviz/ru/powers.cpp +++ b/rogueviz/ru/powers.cpp @@ -1,14 +1,12 @@ namespace rogue_unlike { -flagtype IDENTIFIED = Flag(1); -flagtype ACTIVE = Flag(2); -flagtype PARTIAL = Flag(4); - data fakedata; power& power::is_starting() { qty_filled = qty_owned = 1; return self; } -power& power::while_paused() { paused_act = act; return self; } +power& power::while_paused() { paused_act = act; dead_act = act; return self; } + +power& power::while_dead() { dead_act = act; return self; } power& power::identified_name(string s, string desc) { auto gn = get_name; @@ -122,6 +120,7 @@ void power::init() { flags = 0; act = [this] (data& d) { pf(d); }; paused_act = [] (data&) {}; + dead_act = [] (data&) {}; get_name = [this] { return name; }; get_desc = [this] { return desc; }; get_color = [this] { return color; }; @@ -144,17 +143,47 @@ power& gen_power(int key, string name, string desc, string glyph, color_t color, return p; } +power *extra_life; + void gen_powers() { powers.reserve(100); - gen_power('1', "Extra Life", + extra_life = &gen_power('1', "Extra Life", "You are really proud of this potion, which, after you die, will let you return to the moment of time when you drank it. " "Unfortunately it still requires an ingredient found only in the magical fountains of the Dungeons of Alchemy.\n\n" "You can only drink this potion when at a magical fountain. To protect yourself from dying permanently, when you drink it, " "you drink it automatically whenever you are at a magical fountain.", "!", 0xFFFF00FF, - [] (data& d) { d.p->flags |= IDENTIFIED; } - ).is_starting().be_potion(), + [] (data& d) { + d.p->flags |= IDENTIFIED; + if(d.keystate == 1) { + if(!m.existing) { + revert_all(death_revert); + regenerate_all(); + if(!(extra_life->flags & ACTIVE)) extra_life->qty_filled = 0; + m.existing = true; + m.where = fountain_where; + current_room = fountain_room; + if(d.p->flags & ACTIVE) + addMessage("You wake up at the Magic Fountain."); + else + addMessage("You wake up from a very bad nightmare. Wow, you are really stressed."); + } + else if(!d.p->qty_filled) + addMessage("You need to find a Magic Fountain to prepare this potion."); + else if(d.p->flags & ACTIVE) + addMessage("This potion is drank automatically whenever you visit a Magic Fountain."); + else if(!on_fountain) + addMessage("For safety, you can only drink " + d.p->get_name() + " at the Magic Fountain."); + else { + d.p->flags = ACTIVE; + fountain_room = current_room; fountain_where = m.where; + addMessage("You drink the " + d.p->get_name() + " and you feel that nothing will stop you now!"); + } + } + } + ).is_starting().be_potion().while_dead(); + extra_life->qty_filled = 0; gen_power('d', "move right", "A special power of human beings, and most other animals, that they earn early in their life.", @@ -212,6 +241,8 @@ void gen_powers() { if(b == wDoor) { current_room->replace_block(x, y, wSmashedDoor); addMessage("You smash the door!"); + auto cr = current_room; + add_revert(fountain_revert, [cr, x, y] { cr->replace_block(x, y, wDoor); }); } } }).be_weapon(), @@ -374,6 +405,7 @@ void handle_powers(data& d) { if(keywasheld(p.key)) d.keystate |= 2; d.p = &p; if(cmode == mode::paused) p.paused_act(d); + else if(!m.existing) p.dead_act(d); else p.act(d); } } diff --git a/rogueviz/ru/render.cpp b/rogueviz/ru/render.cpp index 031fb301..a8100f31 100644 --- a/rogueviz/ru/render.cpp +++ b/rogueviz/ru/render.cpp @@ -251,7 +251,7 @@ void man::draw() { void render_room_objects(room *r) { initquickqueue(); - if(r == current_room && m.visible_inv()) m.draw(); + if(r == current_room && m.visible_inv() && m.existing) m.draw(); for(auto& e: r->entities) if(e->existing && (cmode == mode::editmap || (e->visible(r) && e->visible_inv()))) e->draw(); diff --git a/rogueviz/ru/save.cpp b/rogueviz/ru/save.cpp index 40716844..b4ab85dc 100644 --- a/rogueviz/ru/save.cpp +++ b/rogueviz/ru/save.cpp @@ -105,8 +105,9 @@ void load_room(fhstream& f, cell *c) { string cap = s.substr(0, pos); string param = s.substr(pos+1); if(cap == "START") { - current_room = &r; + fountain_room = current_room = &r; sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y); + fountain_where = m.where; } else if(cap == "ITEM") { auto b = std::make_unique();