mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-11-04 07:43:02 +00:00 
			
		
		
		
	ru:: ghosts and bones
This commit is contained in:
		@@ -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. "
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user