From 84ac596d5010dc2ad98d2466e525eb5ed806f29d Mon Sep 17 00:00:00 2001 From: Alula Date: Sat, 12 Sep 2020 23:43:27 +0200 Subject: [PATCH] add the fucking xp doritos --- src/common.rs | 3 + src/npc/mod.rs | 99 +++++++++++++++++++++++++-- src/npc/pickups.rs | 146 ++++++++++++++++++++++++++++++++++++++++ src/player_hit.rs | 5 ++ src/scene/game_scene.rs | 6 +- 5 files changed, 250 insertions(+), 9 deletions(-) create mode 100644 src/npc/pickups.rs diff --git a/src/common.rs b/src/common.rs index 0b7a3f0..87c9ebc 100644 --- a/src/common.rs +++ b/src/common.rs @@ -88,6 +88,9 @@ bitfield! { pub flag_x01, set_flag_x01: 0; pub control_enabled, set_control_enabled: 1; pub interactions_disabled, set_interactions_disabled: 2; + + // engine specific flags + pub wind, set_wind: 15; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/npc/mod.rs b/src/npc/mod.rs index 08734e8..e9d7dbf 100644 --- a/src/npc/mod.rs +++ b/src/npc/mod.rs @@ -24,6 +24,7 @@ pub mod egg_corridor; pub mod first_cave; pub mod mimiga_village; pub mod misc; +pub mod pickups; bitfield! { #[derive(Clone, Copy)] @@ -58,6 +59,7 @@ pub struct NPC { pub vel_y: isize, pub target_x: isize, pub target_y: isize, + pub exp: u16, pub size: u8, pub shock: u16, pub life: u16, @@ -73,6 +75,7 @@ pub struct NPC { pub flag_num: u16, pub event_num: u16, pub action_counter: u16, + pub action_counter2: u16, pub anim_counter: u16, pub anim_rect: Rect, } @@ -82,6 +85,7 @@ impl GameEntity<&mut Player> for NPC { // maybe use macros? match self.npc_type { 0 => { self.tick_n000_null(state) } + 1 => { self.tick_n001_experience(state) } 2 => { self.tick_n002_behemoth(state) } 5 => { self.tick_n005_green_critter(state, player) } 7 => { self.tick_n007_basil(state, player) } @@ -202,6 +206,11 @@ impl PhysicalEntity for NPC { &mut self.flags } + #[inline(always)] + fn direction(&self) -> Direction { + self.direction + } + #[inline(always)] fn is_player(&self) -> bool { false @@ -237,9 +246,9 @@ impl NPCMap { pub fn create_npc_from_data(&mut self, table: &NPCTable, data: &NPCData) -> &mut NPC { let display_bounds = table.get_display_bounds(data.npc_type); let hit_bounds = table.get_hit_bounds(data.npc_type); - let (size, life, damage, flags) = match table.get_entry(data.npc_type) { - Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags) } - None => { (1, 0, 0, NPCFlag(0)) } + let (size, life, damage, flags, exp) = match table.get_entry(data.npc_type) { + Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags, entry.experience as u16) } + None => { (1, 0, 0, NPCFlag(0), 0) } }; let npc_flags = NPCFlag(data.flags | flags.0); @@ -257,6 +266,7 @@ impl NPCMap { flag_num: data.flag_num, event_num: data.event_num, shock: 0, + exp, size, life, damage, @@ -267,6 +277,7 @@ impl NPCMap { display_bounds, hit_bounds, action_counter: 0, + action_counter2: 0, anim_counter: 0, anim_rect: Rect::new(0, 0, 0, 0), }; @@ -277,6 +288,46 @@ impl NPCMap { self.npcs.get_mut(&data.id).unwrap().get_mut() } + pub fn create_npc(&self, npc_type: u16, table: &NPCTable) -> NPC { + let display_bounds = table.get_display_bounds(npc_type); + let hit_bounds = table.get_hit_bounds(npc_type); + let (size, life, damage, flags, exp) = match table.get_entry(npc_type) { + Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags, entry.experience as u16) } + None => { (1, 0, 0, NPCFlag(0), 0) } + }; + let npc_flags = NPCFlag(flags.0); + + NPC { + id: 0, + npc_type, + x: 0, + y: 0, + vel_x: 0, + vel_y: 0, + target_x: 0, + target_y: 0, + action_num: 0, + anim_num: 0, + flag_num: 0, + event_num: 0, + shock: 0, + exp, + size, + life, + damage, + cond: Condition(0x00), + flags: Flag(0), + direction: if npc_flags.spawn_facing_right() { Direction::Right } else { Direction::Left }, + npc_flags, + display_bounds, + hit_bounds, + action_counter: 0, + action_counter2: 0, + anim_counter: 0, + anim_rect: Rect::new(0, 0, 0, 0), + } + } + pub fn garbage_collect(&mut self) { self.npcs.retain(|_, npc_cell| npc_cell.borrow().cond.alive()); } @@ -292,8 +343,8 @@ impl NPCMap { } } - pub fn allocate_id(&mut self) -> u16 { - for i in 0..(u16::MAX) { + pub fn allocate_id(&mut self, start: u16) -> u16 { + for i in start..(u16::MAX) { if !self.npc_ids.contains(&i) { return i; } @@ -336,6 +387,37 @@ impl NPCMap { new_npcs.append(&mut npcs); } + if npc.exp != 0 { + //if state.game_rng.range(0..4) == 0 { + // health + + //} else { + let mut exp = npc.exp; + + while exp > 0 { + let exp_piece = if exp >= 20 { + exp -= 20; + 20 + } else if exp >= 5 { + exp -= 5; + 5 + } else { + exp -= 1; + 1 + }; + + let mut xp_npc = self.create_npc(1, &state.npc_table); + xp_npc.cond.set_alive(true); + xp_npc.direction = Direction::Left; + xp_npc.x = npc.x; + xp_npc.y = npc.y; + xp_npc.exp = exp_piece; + + new_npcs.push(xp_npc); + } + //} + } + state.game_flags.set(npc.flag_num as usize, true); // todo vanish / show damage @@ -346,12 +428,17 @@ impl NPCMap { for mut npc in new_npcs { let id = if npc.id == 0 { - self.allocate_id() + if npc.npc_type == 1 { + self.allocate_id(0x100) + } else { + self.allocate_id(0) + } } else { npc.id }; npc.id = id; + self.npc_ids.insert(id); self.npcs.insert(id, RefCell::new(npc)); } } diff --git a/src/npc/pickups.rs b/src/npc/pickups.rs new file mode 100644 index 0000000..f78983a --- /dev/null +++ b/src/npc/pickups.rs @@ -0,0 +1,146 @@ +use nalgebra::clamp; + +use crate::common::Direction; +use crate::ggez::GameResult; +use crate::npc::NPC; +use crate::SharedGameState; + +impl NPC { + pub(crate) fn tick_n001_experience(&mut self, state: &mut SharedGameState) -> GameResult { + if state.control_flags.wind() { + if self.action_num == 0 { + self.action_num = 1; + + self.vel_x = state.game_rng.range(-0x80..0x80) as isize; + self.vel_y = state.game_rng.range(-0x7f..0x100) as isize; + } + + self.vel_x -= 0x8; + + if self.x < 80 * 0x200 { + self.cond.set_alive(false); + return Ok(()); + } + + if self.vel_x < -0x600 { + self.vel_x = -0x600; + } + + if self.flags.hit_left_wall() { + self.vel_x = 0x100; + } + + if self.flags.hit_top_wall() { + self.vel_y = 0x40; + } + + if self.flags.hit_bottom_wall() { + self.vel_y = -0x40; + } + } else { + if self.action_num == 0 { + self.action_num = 1; + self.anim_num = state.game_rng.range(0..4) as u16; + + self.vel_x = state.game_rng.range(-0x200..0x200) as isize; + self.vel_y = state.game_rng.range(-0x400..0) as isize; + + self.direction = if state.game_rng.range(0..1) != 0 { + Direction::Left + } else { + Direction::Right + }; + } + + self.vel_y += if self.flags.in_water() { + 0x15 + } else { + 0x2a + }; + + if self.flags.hit_left_wall() && self.vel_x < 0 { + self.vel_x = -self.vel_x; + } + + if self.flags.hit_right_wall() && self.vel_x > 0 { + self.vel_x = -self.vel_x; + } + + if self.flags.hit_top_wall() && self.vel_y < 0 { + self.vel_y = -self.vel_y; + } + + if self.flags.hit_bottom_wall() { + // todo play sound 45 + + self.vel_y = -0x280; + self.vel_x = 2 * self.vel_x / 3; + } + + if self.flags.hit_left_wall() || self.flags.hit_right_wall() || self.flags.hit_bottom_wall() { + // todo play sound 45 + self.action_counter2 += 1; + + if self.action_counter2 > 2 { + self.vel_y -= 0x200; + } + } else { + self.action_counter2 = 0; + } + + self.vel_x = clamp(self.vel_x, -0x5ff, 0x5ff); + self.vel_y = clamp(self.vel_y, -0x5ff, 0x5ff); + } + + self.x += self.vel_x; + self.y += self.vel_y; + + self.anim_counter += 1; + + if self.direction == Direction::Left { + if self.anim_counter > 2 { + self.anim_counter = 0; + + self.anim_num += 1; + if self.anim_num > 5 { + self.anim_num = 0; + } + } + } else if self.anim_counter > 2 { + self.anim_counter = 0; + + if self.anim_num > 0 { + self.anim_num -= 1; + } else { + self.anim_num = 5; + } + } + + self.anim_rect = state.constants.npc.n001_experience[self.anim_num as usize]; + + if self.action_num != 0 { + if self.exp >= 5 { + self.anim_rect.top += 16; + self.anim_rect.bottom += 16; + } else if self.exp >= 20 { + self.anim_rect.top += 32; + self.anim_rect.bottom += 32; + } + } + + self.action_counter += 1; + if self.action_counter > 500 && self.anim_num == 5 && self.anim_counter == 2 { + self.cond.set_alive(false); + return Ok(()); + } + + if self.action_counter > 400 && (self.action_counter / 2 % 2) != 0 { + self.anim_rect.left = 0; + self.anim_rect.top = 0; + self.anim_rect.right = 0; + self.anim_rect.bottom = 0; + } + + Ok(()) + } +} diff --git a/src/player_hit.rs b/src/player_hit.rs index 4055e22..a23a9b7 100644 --- a/src/player_hit.rs +++ b/src/player_hit.rs @@ -70,6 +70,11 @@ impl PhysicalEntity for Player { &mut self.flags } + #[inline(always)] + fn direction(&self) -> Direction { + self.direction + } + #[inline(always)] fn is_player(&self) -> bool { true diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 4ea5128..649a778 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -683,8 +683,8 @@ impl Scene for GameScene { self.player.target_y = self.player.y; self.frame.immediate_update(state, &self.player, &self.stage); - //self.inventory.add_weapon(WeaponType::PolarStar, 0); - //self.player.equip.set_booster_2_0(true); + self.inventory.add_weapon(WeaponType::PolarStar, 0); + self.player.equip.set_booster_2_0(true); Ok(()) } @@ -703,7 +703,7 @@ impl Scene for GameScene { self.player.flags.0 = 0; state.tick_carets(); - self.bullet_manager.tick_bullets(state, &mut self.stage); + self.bullet_manager.tick_bullets(state, &self.player, &mut self.stage); self.player.tick_map_collisions(state, &mut self.stage); self.player.tick_npc_collisions(state, &mut self.npc_map);