mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +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
	 Zeno Rogue
					Zeno Rogue