mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	implemented the magic fountains (except ghosts and bones mechanics)
This commit is contained in:
		| @@ -25,7 +25,7 @@ struct power { | |||||||
|   flagtype flags; |   flagtype flags; | ||||||
|   int random_flavor; |   int random_flavor; | ||||||
|   void init(); |   void init(); | ||||||
|   hr::function<void(data&)> act, paused_act; |   hr::function<void(data&)> act, paused_act, dead_act; | ||||||
|   hr::function<string()> get_name; |   hr::function<string()> get_name; | ||||||
|   hr::function<string()> get_desc; |   hr::function<string()> get_desc; | ||||||
|   hr::function<string()> get_glyph; |   hr::function<string()> get_glyph; | ||||||
| @@ -37,6 +37,7 @@ struct power { | |||||||
|   power& be_weapon(); |   power& be_weapon(); | ||||||
|   power& be_resource(string plural); |   power& be_resource(string plural); | ||||||
|   power& while_paused(); |   power& while_paused(); | ||||||
|  |   power& while_dead(); | ||||||
|   power& identified_name(string, string); |   power& identified_name(string, string); | ||||||
|   power& be_wearable(string wear_effect, string remove_effect); |   power& be_wearable(string wear_effect, string remove_effect); | ||||||
|   power& be_jewelry(string jtype, string desc); |   power& be_jewelry(string jtype, string desc); | ||||||
| @@ -44,6 +45,11 @@ struct power { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
| extern vector<power> powers; | extern vector<power> powers; | ||||||
|  | extern power *extra_life; | ||||||
|  |  | ||||||
|  | flagtype IDENTIFIED = Flag(1); | ||||||
|  | flagtype ACTIVE = Flag(2); | ||||||
|  | flagtype PARTIAL = Flag(4); | ||||||
|  |  | ||||||
| struct bbox { | struct bbox { | ||||||
|   int minx, miny, maxx, maxy; |   int minx, miny, maxx, maxy; | ||||||
| @@ -230,9 +236,10 @@ struct entity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|   virtual bool reduce_hp(int x) { |   virtual bool reduce_hp(int x) { | ||||||
|  |     if(hp < 0) return false; | ||||||
|     if(gframeid < invinc_end) return false; |     if(gframeid < invinc_end) return false; | ||||||
|     hp -= x; |     hp -= x; | ||||||
|     if(hp < 0) on_kill(); |     if(hp <= 0) on_kill(); | ||||||
|     invinc_end = gframeid + 150; |     invinc_end = gframeid + 150; | ||||||
|     return true; |     return true; | ||||||
|     } |     } | ||||||
| @@ -270,6 +277,8 @@ struct man : public entity { | |||||||
|   virtual bool hurt_by_spikes() { return true; } |   virtual bool hurt_by_spikes() { return true; } | ||||||
|   string get_name() override { return "alchemist"; } |   string get_name() override { return "alchemist"; } | ||||||
|   string get_help() override { return "This is you."; } |   string get_help() override { return "This is you."; } | ||||||
|  |  | ||||||
|  |   void on_kill() override; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| extern man m; | extern man m; | ||||||
| @@ -403,6 +412,9 @@ struct item : public entity { | |||||||
|     kino(); |     kino(); | ||||||
|     if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { |     if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { | ||||||
|       addMessage(pickup_message); |       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); |       powers[id].picked_up(qty); | ||||||
|       existing = false; |       existing = false; | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -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 render_the_map(); | ||||||
| void shuffle_all(); | void shuffle_all(); | ||||||
|  |  | ||||||
|  | using revert_stack = vector<reaction_t>; | ||||||
|  |  | ||||||
|  | revert_stack death_revert, fountain_revert; | ||||||
|  |  | ||||||
|  | void add_revert(revert_stack& s, const reaction_t& what); | ||||||
|  |  | ||||||
|  | void revert_all(revert_stack& s); | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,16 @@ void handle_powers(data& d); | |||||||
|  |  | ||||||
| bool on_fountain; | bool on_fountain; | ||||||
| room *fountain_room; | 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() { | void check_fountains() { | ||||||
|   bool next_on_fountain = false; |   bool next_on_fountain = false; | ||||||
| @@ -14,13 +24,12 @@ void check_fountains() { | |||||||
|     if(b == wFountain) next_on_fountain = true; |     if(b == wFountain) next_on_fountain = true; | ||||||
|     } |     } | ||||||
|   if(next_on_fountain && !on_fountain) { |   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."); |     addMessage("A magic fountain! You feel safe and refill your potions."); | ||||||
|     m.hp = m.max_hp(); |     regenerate_all(); | ||||||
|     for(auto& p: powers) p.refill(); |  | ||||||
|     for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate(); |  | ||||||
|     current_target = nullptr; |  | ||||||
|     shuffle_all(); |  | ||||||
|     } |     } | ||||||
|   swap(on_fountain, next_on_fountain); |   swap(on_fountain, next_on_fountain); | ||||||
|   } |   } | ||||||
| @@ -58,4 +67,20 @@ void man::act() { | |||||||
|   check_fountains(); |   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(); } | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,14 +1,12 @@ | |||||||
| namespace rogue_unlike { | namespace rogue_unlike { | ||||||
|  |  | ||||||
| flagtype IDENTIFIED = Flag(1); |  | ||||||
| flagtype ACTIVE = Flag(2); |  | ||||||
| flagtype PARTIAL = Flag(4); |  | ||||||
|  |  | ||||||
| data fakedata; | data fakedata; | ||||||
|  |  | ||||||
| power& power::is_starting() { qty_filled = qty_owned = 1; return self; } | 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) { | power& power::identified_name(string s, string desc) { | ||||||
|   auto gn = get_name; |   auto gn = get_name; | ||||||
| @@ -122,6 +120,7 @@ void power::init() { | |||||||
|   flags = 0; |   flags = 0; | ||||||
|   act = [this] (data& d) { pf(d); }; |   act = [this] (data& d) { pf(d); }; | ||||||
|   paused_act = [] (data&) {}; |   paused_act = [] (data&) {}; | ||||||
|  |   dead_act = [] (data&) {}; | ||||||
|   get_name = [this] { return name; }; |   get_name = [this] { return name; }; | ||||||
|   get_desc = [this] { return desc; }; |   get_desc = [this] { return desc; }; | ||||||
|   get_color = [this] { return color; }; |   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; |   return p; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | power *extra_life; | ||||||
|  |  | ||||||
| void gen_powers() { | void gen_powers() { | ||||||
|   powers.reserve(100); |   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. " |     "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" |     "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 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.", |     "you drink it automatically whenever you are at a magical fountain.", | ||||||
|     "!", 0xFFFF00FF, |     "!", 0xFFFF00FF, | ||||||
|     [] (data& d) { d.p->flags |= IDENTIFIED; } |     [] (data& d) { | ||||||
|     ).is_starting().be_potion(), |       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", |   gen_power('d', "move right", | ||||||
|     "A special power of human beings, and most other animals, that they earn early in their life.", |     "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) { |         if(b == wDoor) { | ||||||
|           current_room->replace_block(x, y, wSmashedDoor); |           current_room->replace_block(x, y, wSmashedDoor); | ||||||
|           addMessage("You smash the door!"); |           addMessage("You smash the door!"); | ||||||
|  |           auto cr = current_room; | ||||||
|  |           add_revert(fountain_revert, [cr, x, y] { cr->replace_block(x, y, wDoor); }); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       }).be_weapon(), |       }).be_weapon(), | ||||||
| @@ -374,6 +405,7 @@ void handle_powers(data& d) { | |||||||
|     if(keywasheld(p.key)) d.keystate |= 2; |     if(keywasheld(p.key)) d.keystate |= 2; | ||||||
|     d.p = &p; |     d.p = &p; | ||||||
|     if(cmode == mode::paused) p.paused_act(d); |     if(cmode == mode::paused) p.paused_act(d); | ||||||
|  |     else if(!m.existing) p.dead_act(d); | ||||||
|     else p.act(d); |     else p.act(d); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -251,7 +251,7 @@ void man::draw() { | |||||||
|  |  | ||||||
| void render_room_objects(room *r) { | void render_room_objects(room *r) { | ||||||
|   initquickqueue(); |   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) |   for(auto& e: r->entities) | ||||||
|     if(e->existing && (cmode == mode::editmap || (e->visible(r) && e->visible_inv()))) |     if(e->existing && (cmode == mode::editmap || (e->visible(r) && e->visible_inv()))) | ||||||
|       e->draw(); |       e->draw(); | ||||||
|   | |||||||
| @@ -105,8 +105,9 @@ void load_room(fhstream& f, cell *c) { | |||||||
|       string cap = s.substr(0, pos); |       string cap = s.substr(0, pos); | ||||||
|       string param = s.substr(pos+1); |       string param = s.substr(pos+1); | ||||||
|       if(cap == "START") { |       if(cap == "START") { | ||||||
|         current_room = &r; |         fountain_room = current_room = &r; | ||||||
|         sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y); |         sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y); | ||||||
|  |         fountain_where = m.where; | ||||||
|         } |         } | ||||||
|       else if(cap == "ITEM") { |       else if(cap == "ITEM") { | ||||||
|         auto b = std::make_unique<item>(); |         auto b = std::make_unique<item>(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue