mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-07-29 22:02:50 +00:00
ru:: ghosts and bones
This commit is contained in:
parent
447c8e469b
commit
7183c849a7
@ -199,7 +199,7 @@ struct entity {
|
||||
|
||||
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;
|
||||
void kino();
|
||||
@ -208,7 +208,7 @@ struct entity {
|
||||
void apply_walls_reflect();
|
||||
void apply_grav();
|
||||
void apply_portal_grav();
|
||||
void stay_on_screen();
|
||||
bool stay_on_screen(); /* returns true if flipped */
|
||||
virtual void act() { kino(); }
|
||||
|
||||
double get_scale() { return get_scale_at(where.y); }
|
||||
@ -235,12 +235,14 @@ struct entity {
|
||||
existing = false;
|
||||
}
|
||||
|
||||
virtual int invinc_time() { return 150; }
|
||||
|
||||
virtual bool reduce_hp(int x) {
|
||||
if(hp < 0) return false;
|
||||
if(gframeid < invinc_end) return false;
|
||||
hp -= x;
|
||||
if(hp <= 0) on_kill();
|
||||
invinc_end = gframeid + 150;
|
||||
invinc_end = gframeid + invinc_time();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -350,6 +352,21 @@ struct boar : public enemy {
|
||||
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 {
|
||||
int dir, respawn_dir;
|
||||
xy siz() override { return {18, 8}; }
|
||||
|
@ -115,6 +115,9 @@ void entity::apply_walls() {
|
||||
else if(b != wFrozen) hit_wall();
|
||||
}
|
||||
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;
|
||||
}
|
||||
if((walls[b].flags & W_PAIN) && pain_effect()) goto again;
|
||||
@ -206,11 +209,13 @@ void entity::apply_walls() {
|
||||
}
|
||||
}
|
||||
|
||||
void entity::stay_on_screen() {
|
||||
if(where.x < l_margin_at && vel.x < 0) vel.x = -vel.x;
|
||||
if(where.x > r_margin_at && vel.x > 0) vel.x = -vel.x;
|
||||
if(where.y < t_margin_at && vel.y < 0) vel.y = -vel.y;
|
||||
if(where.y > b_margin_at && vel.y > 0) vel.y = -vel.y;
|
||||
bool entity::stay_on_screen() {
|
||||
bool res = false;
|
||||
if(where.x < l_margin_at && vel.x < 0) vel.x = -vel.x, res = true;
|
||||
if(where.x > r_margin_at && vel.x > 0) vel.x = -vel.x, res = true;
|
||||
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() {
|
||||
@ -218,6 +223,7 @@ void entity::kino() {
|
||||
on_ice = false;
|
||||
wallhug = false;
|
||||
on_bounce = false;
|
||||
is_stable = false;
|
||||
zero_vel = xy(0, 0);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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() {
|
||||
stay_on_screen();
|
||||
kino();
|
||||
|
@ -65,12 +65,13 @@ flagtype W_PAIN = 16;
|
||||
flagtype W_BOUNCY = 32;
|
||||
flagtype W_FROZEN = 64;
|
||||
flagtype W_BLOCKBIRD = 128;
|
||||
flagtype W_STABLE = 256;
|
||||
|
||||
constexpr int qwall = int(wGUARD);
|
||||
|
||||
ruwall walls[qwall] = {
|
||||
{"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."},
|
||||
{"spike", "^", 0xC08080FF, W_TRANS | W_PAIN | W_BLOCKBIRD, "Dangerous!"},
|
||||
{"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS | W_BLOCKBIRD, "Not used yet."},
|
||||
|
@ -6,6 +6,9 @@ bool on_fountain;
|
||||
room *fountain_room;
|
||||
xy fountain_where;
|
||||
|
||||
room *stable_room;
|
||||
xy stable_where;
|
||||
|
||||
void regenerate_all() {
|
||||
m.hp = m.max_hp();
|
||||
for(auto& p: powers) p.refill();
|
||||
@ -37,6 +40,11 @@ void check_fountains() {
|
||||
void man::act() {
|
||||
kino();
|
||||
|
||||
if(is_stable) {
|
||||
stable_room = current_room;
|
||||
stable_where = where;
|
||||
}
|
||||
|
||||
current_stats = next_stats;
|
||||
next_stats = base_stats;
|
||||
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;
|
||||
int gold_id;
|
||||
|
||||
void gen_powers() {
|
||||
powers.reserve(100);
|
||||
@ -158,6 +159,9 @@ void gen_powers() {
|
||||
d.p->flags |= IDENTIFIED;
|
||||
if(d.keystate == 1) {
|
||||
if(!m.existing) {
|
||||
auto w = m.where;
|
||||
auto cr = current_room;
|
||||
int hp = m.max_hp();
|
||||
revert_all(death_revert);
|
||||
regenerate_all();
|
||||
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.");
|
||||
else
|
||||
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)
|
||||
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); }
|
||||
).be_potion(),
|
||||
|
||||
gold_id = isize(powers);
|
||||
|
||||
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"
|
||||
"This can be used to buy things in shops. "
|
||||
|
Loading…
x
Reference in New Issue
Block a user