mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-06-26 15:12:48 +00:00
implemented the magic fountains (except ghosts and bones mechanics)
This commit is contained in:
parent
1e23eed4e3
commit
2ae913ccfa
@ -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>();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user