mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-10-26 19:37:40 +00:00
ru:: ghosts and bones
This commit is contained in:
@@ -199,7 +199,7 @@ struct entity {
|
|||||||
|
|
||||||
virtual double grav() { return 0.1; }
|
virtual double grav() { return 0.1; }
|
||||||
|
|
||||||
bool on_floor, fallthru, on_ice, wallhug, on_bounce;
|
bool on_floor, fallthru, on_ice, wallhug, on_bounce, is_stable;
|
||||||
|
|
||||||
bool destroyed;
|
bool destroyed;
|
||||||
void kino();
|
void kino();
|
||||||
@@ -208,7 +208,7 @@ struct entity {
|
|||||||
void apply_walls_reflect();
|
void apply_walls_reflect();
|
||||||
void apply_grav();
|
void apply_grav();
|
||||||
void apply_portal_grav();
|
void apply_portal_grav();
|
||||||
void stay_on_screen();
|
bool stay_on_screen(); /* returns true if flipped */
|
||||||
virtual void act() { kino(); }
|
virtual void act() { kino(); }
|
||||||
|
|
||||||
double get_scale() { return get_scale_at(where.y); }
|
double get_scale() { return get_scale_at(where.y); }
|
||||||
@@ -235,12 +235,14 @@ struct entity {
|
|||||||
existing = false;
|
existing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual int invinc_time() { return 150; }
|
||||||
|
|
||||||
virtual bool reduce_hp(int x) {
|
virtual bool reduce_hp(int x) {
|
||||||
if(hp < 0) return false;
|
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 + invinc_time();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +352,21 @@ struct boar : public enemy {
|
|||||||
int max_hp() { return 60; }
|
int max_hp() { return 60; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ghost : public enemy {
|
||||||
|
int xp, hp;
|
||||||
|
bool flipped;
|
||||||
|
xy siz() override { return {12, 12}; }
|
||||||
|
string glyph() override { return "g"; }
|
||||||
|
color_t color() override { return 0x4040A0FF; }
|
||||||
|
void act() override;
|
||||||
|
void attacked(int s) 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 {}
|
||||||
|
};
|
||||||
|
|
||||||
struct snake : public enemy {
|
struct snake : public enemy {
|
||||||
int dir, respawn_dir;
|
int dir, respawn_dir;
|
||||||
xy siz() override { return {18, 8}; }
|
xy siz() override { return {18, 8}; }
|
||||||
|
|||||||
@@ -115,6 +115,9 @@ void entity::apply_walls() {
|
|||||||
else if(b != wFrozen) hit_wall();
|
else if(b != wFrozen) hit_wall();
|
||||||
}
|
}
|
||||||
if(pixel_to_block(get_pixel_bbox_at(where + vel)).maxy <= y) where.y += vel.y;
|
if(pixel_to_block(get_pixel_bbox_at(where + vel)).maxy <= y) where.y += vel.y;
|
||||||
|
|
||||||
|
if(walls[b].flags & W_STABLE) is_stable = true;
|
||||||
|
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if((walls[b].flags & W_PAIN) && pain_effect()) goto again;
|
if((walls[b].flags & W_PAIN) && pain_effect()) goto again;
|
||||||
@@ -206,11 +209,13 @@ void entity::apply_walls() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void entity::stay_on_screen() {
|
bool entity::stay_on_screen() {
|
||||||
if(where.x < l_margin_at && vel.x < 0) vel.x = -vel.x;
|
bool res = false;
|
||||||
if(where.x > r_margin_at && vel.x > 0) vel.x = -vel.x;
|
if(where.x < l_margin_at && vel.x < 0) vel.x = -vel.x, res = true;
|
||||||
if(where.y < t_margin_at && vel.y < 0) vel.y = -vel.y;
|
if(where.x > r_margin_at && vel.x > 0) vel.x = -vel.x, res = true;
|
||||||
if(where.y > b_margin_at && vel.y > 0) vel.y = -vel.y;
|
if(where.y < t_margin_at && vel.y < 0) vel.y = -vel.y, res = true;
|
||||||
|
if(where.y > b_margin_at && vel.y > 0) vel.y = -vel.y, res = true;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entity::kino() {
|
void entity::kino() {
|
||||||
@@ -218,6 +223,7 @@ void entity::kino() {
|
|||||||
on_ice = false;
|
on_ice = false;
|
||||||
wallhug = false;
|
wallhug = false;
|
||||||
on_bounce = false;
|
on_bounce = false;
|
||||||
|
is_stable = false;
|
||||||
zero_vel = xy(0, 0);
|
zero_vel = xy(0, 0);
|
||||||
|
|
||||||
// ld modv = 60. / game_fps;
|
// ld modv = 60. / game_fps;
|
||||||
@@ -288,6 +294,29 @@ void boar::attacked(int dmg) {
|
|||||||
if(on_floor) vel.x = dat.d * dat.modv * s * 2, vel.y = -dat.d * dat.modv * 2.5;
|
if(on_floor) vel.x = dat.d * dat.modv * s * 2, vel.y = -dat.d * dat.modv * 2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ghost::act() {
|
||||||
|
hyperpoint g = to_hyper(where);
|
||||||
|
hyperpoint h = to_hyper(m.where);
|
||||||
|
ld d = hdist(g, h);
|
||||||
|
ld angle = gframeid < invinc_end ? M_PI : d > 0.5 ? 90._deg : d > 0.05 ? 80._deg : 5._deg;
|
||||||
|
ld gv = d > 0.04 && gframeid > invinc_end ? 0.2 : 0.1;
|
||||||
|
if(flipped) angle = -angle;
|
||||||
|
hyperpoint g1 = rgpushxto0(g) * rspintox(gpushxto0(g) * h) * spin(angle) * xpush0(gv / game_fps);
|
||||||
|
vel = from_hyper(g1) - where;
|
||||||
|
if(stay_on_screen()) flipped = !flipped;
|
||||||
|
apply_vel();
|
||||||
|
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||||
|
invinc_end = gframeid + 200;
|
||||||
|
if(m.reduce_hp(20)) addMessage("The ghost passes through you!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ghost::attacked(int dmg) {
|
||||||
|
current_target = this;
|
||||||
|
reduce_hp(dmg);
|
||||||
|
if(!existing) addMessage("You kill the ghost."); else addMessage("You hit the ghost.");
|
||||||
|
}
|
||||||
|
|
||||||
void snake::act() {
|
void snake::act() {
|
||||||
stay_on_screen();
|
stay_on_screen();
|
||||||
kino();
|
kino();
|
||||||
|
|||||||
@@ -65,12 +65,13 @@ flagtype W_PAIN = 16;
|
|||||||
flagtype W_BOUNCY = 32;
|
flagtype W_BOUNCY = 32;
|
||||||
flagtype W_FROZEN = 64;
|
flagtype W_FROZEN = 64;
|
||||||
flagtype W_BLOCKBIRD = 128;
|
flagtype W_BLOCKBIRD = 128;
|
||||||
|
flagtype W_STABLE = 256;
|
||||||
|
|
||||||
constexpr int qwall = int(wGUARD);
|
constexpr int qwall = int(wGUARD);
|
||||||
|
|
||||||
ruwall walls[qwall] = {
|
ruwall walls[qwall] = {
|
||||||
{"air", ".", 0x40404080, W_TRANS, "Looks like an empty space, but actually necessary for survival."},
|
{"air", ".", 0x40404080, W_TRANS, "Looks like an empty space, but actually necessary for survival."},
|
||||||
{"wall", "#", 0xFFFFFFFF, W_BLOCK, "These kinds of tough walls can never be destroyed."},
|
{"wall", "#", 0xFFFFFFFF, W_BLOCK | W_STABLE, "These kinds of tough walls can never be destroyed."},
|
||||||
{"bouncy wall", "#", 0x80FF80FF, W_BLOCK | W_BOUNCY, "Like walls, but things bounce off them."},
|
{"bouncy wall", "#", 0x80FF80FF, W_BLOCK | W_BOUNCY, "Like walls, but things bounce off them."},
|
||||||
{"spike", "^", 0xC08080FF, W_TRANS | W_PAIN | W_BLOCKBIRD, "Dangerous!"},
|
{"spike", "^", 0xC08080FF, W_TRANS | W_PAIN | W_BLOCKBIRD, "Dangerous!"},
|
||||||
{"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS | W_BLOCKBIRD, "Not used yet."},
|
{"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS | W_BLOCKBIRD, "Not used yet."},
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ bool on_fountain;
|
|||||||
room *fountain_room;
|
room *fountain_room;
|
||||||
xy fountain_where;
|
xy fountain_where;
|
||||||
|
|
||||||
|
room *stable_room;
|
||||||
|
xy stable_where;
|
||||||
|
|
||||||
void regenerate_all() {
|
void regenerate_all() {
|
||||||
m.hp = m.max_hp();
|
m.hp = m.max_hp();
|
||||||
for(auto& p: powers) p.refill();
|
for(auto& p: powers) p.refill();
|
||||||
@@ -37,6 +40,11 @@ void check_fountains() {
|
|||||||
void man::act() {
|
void man::act() {
|
||||||
kino();
|
kino();
|
||||||
|
|
||||||
|
if(is_stable) {
|
||||||
|
stable_room = current_room;
|
||||||
|
stable_where = where;
|
||||||
|
}
|
||||||
|
|
||||||
current_stats = next_stats;
|
current_stats = next_stats;
|
||||||
next_stats = base_stats;
|
next_stats = base_stats;
|
||||||
auto dat = get_dat();
|
auto dat = get_dat();
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ power& gen_power(int key, string name, string desc, string glyph, color_t color,
|
|||||||
}
|
}
|
||||||
|
|
||||||
power *extra_life;
|
power *extra_life;
|
||||||
|
int gold_id;
|
||||||
|
|
||||||
void gen_powers() {
|
void gen_powers() {
|
||||||
powers.reserve(100);
|
powers.reserve(100);
|
||||||
@@ -158,6 +159,9 @@ void gen_powers() {
|
|||||||
d.p->flags |= IDENTIFIED;
|
d.p->flags |= IDENTIFIED;
|
||||||
if(d.keystate == 1) {
|
if(d.keystate == 1) {
|
||||||
if(!m.existing) {
|
if(!m.existing) {
|
||||||
|
auto w = m.where;
|
||||||
|
auto cr = current_room;
|
||||||
|
int hp = m.max_hp();
|
||||||
revert_all(death_revert);
|
revert_all(death_revert);
|
||||||
regenerate_all();
|
regenerate_all();
|
||||||
if(!(extra_life->flags & ACTIVE)) extra_life->qty_filled = 0;
|
if(!(extra_life->flags & ACTIVE)) extra_life->qty_filled = 0;
|
||||||
@@ -168,6 +172,19 @@ void gen_powers() {
|
|||||||
addMessage("You wake up at the Magic Fountain.");
|
addMessage("You wake up at the Magic Fountain.");
|
||||||
else
|
else
|
||||||
addMessage("You wake up from a very bad nightmare. Wow, you are really stressed.");
|
addMessage("You wake up from a very bad nightmare. Wow, you are really stressed.");
|
||||||
|
|
||||||
|
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();
|
||||||
|
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->pickup_message = "You got it back.";
|
||||||
|
stable_room->entities.emplace_back(std::move(bones));
|
||||||
}
|
}
|
||||||
else if(!d.p->qty_filled)
|
else if(!d.p->qty_filled)
|
||||||
addMessage("You need to find a Magic Fountain to prepare this potion.");
|
addMessage("You need to find a Magic Fountain to prepare this potion.");
|
||||||
@@ -386,6 +403,8 @@ void gen_powers() {
|
|||||||
[] (data& d) { if(d.keystate == 1) d.p->flags |= (PARTIAL | IDENTIFIED); }
|
[] (data& d) { if(d.keystate == 1) d.p->flags |= (PARTIAL | IDENTIFIED); }
|
||||||
).be_potion(),
|
).be_potion(),
|
||||||
|
|
||||||
|
gold_id = isize(powers);
|
||||||
|
|
||||||
gen_power('g', "gold",
|
gen_power('g', "gold",
|
||||||
"For some weird reason, people love gold, and they will give you anything if you give them enough gold.\n\n"
|
"For some weird reason, people love gold, and they will give you anything if you give them enough gold.\n\n"
|
||||||
"This can be used to buy things in shops. "
|
"This can be used to buy things in shops. "
|
||||||
|
|||||||
Reference in New Issue
Block a user