add the fucking xp doritos

This commit is contained in:
Alula 2020-09-12 23:43:27 +02:00
parent 7b8e0abc5e
commit 84ac596d50
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
5 changed files with 250 additions and 9 deletions

View File

@ -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)]

View File

@ -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<usize>,
}
@ -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));
}
}

146
src/npc/pickups.rs Normal file
View File

@ -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(())
}
}

View File

@ -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

View File

@ -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);