mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-15 18:32:48 +00:00
add the fucking xp doritos
This commit is contained in:
parent
7b8e0abc5e
commit
84ac596d50
|
@ -88,6 +88,9 @@ bitfield! {
|
||||||
pub flag_x01, set_flag_x01: 0;
|
pub flag_x01, set_flag_x01: 0;
|
||||||
pub control_enabled, set_control_enabled: 1;
|
pub control_enabled, set_control_enabled: 1;
|
||||||
pub interactions_disabled, set_interactions_disabled: 2;
|
pub interactions_disabled, set_interactions_disabled: 2;
|
||||||
|
|
||||||
|
// engine specific flags
|
||||||
|
pub wind, set_wind: 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub mod egg_corridor;
|
||||||
pub mod first_cave;
|
pub mod first_cave;
|
||||||
pub mod mimiga_village;
|
pub mod mimiga_village;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
|
pub mod pickups;
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -58,6 +59,7 @@ pub struct NPC {
|
||||||
pub vel_y: isize,
|
pub vel_y: isize,
|
||||||
pub target_x: isize,
|
pub target_x: isize,
|
||||||
pub target_y: isize,
|
pub target_y: isize,
|
||||||
|
pub exp: u16,
|
||||||
pub size: u8,
|
pub size: u8,
|
||||||
pub shock: u16,
|
pub shock: u16,
|
||||||
pub life: u16,
|
pub life: u16,
|
||||||
|
@ -73,6 +75,7 @@ pub struct NPC {
|
||||||
pub flag_num: u16,
|
pub flag_num: u16,
|
||||||
pub event_num: u16,
|
pub event_num: u16,
|
||||||
pub action_counter: u16,
|
pub action_counter: u16,
|
||||||
|
pub action_counter2: u16,
|
||||||
pub anim_counter: u16,
|
pub anim_counter: u16,
|
||||||
pub anim_rect: Rect<usize>,
|
pub anim_rect: Rect<usize>,
|
||||||
}
|
}
|
||||||
|
@ -82,6 +85,7 @@ impl GameEntity<&mut Player> for NPC {
|
||||||
// maybe use macros?
|
// maybe use macros?
|
||||||
match self.npc_type {
|
match self.npc_type {
|
||||||
0 => { self.tick_n000_null(state) }
|
0 => { self.tick_n000_null(state) }
|
||||||
|
1 => { self.tick_n001_experience(state) }
|
||||||
2 => { self.tick_n002_behemoth(state) }
|
2 => { self.tick_n002_behemoth(state) }
|
||||||
5 => { self.tick_n005_green_critter(state, player) }
|
5 => { self.tick_n005_green_critter(state, player) }
|
||||||
7 => { self.tick_n007_basil(state, player) }
|
7 => { self.tick_n007_basil(state, player) }
|
||||||
|
@ -202,6 +206,11 @@ impl PhysicalEntity for NPC {
|
||||||
&mut self.flags
|
&mut self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn direction(&self) -> Direction {
|
||||||
|
self.direction
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_player(&self) -> bool {
|
fn is_player(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
@ -237,9 +246,9 @@ impl NPCMap {
|
||||||
pub fn create_npc_from_data(&mut self, table: &NPCTable, data: &NPCData) -> &mut NPC {
|
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 display_bounds = table.get_display_bounds(data.npc_type);
|
||||||
let hit_bounds = table.get_hit_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) {
|
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) }
|
Some(entry) => { (entry.size, entry.life, entry.damage as u16, entry.npc_flags, entry.experience as u16) }
|
||||||
None => { (1, 0, 0, NPCFlag(0)) }
|
None => { (1, 0, 0, NPCFlag(0), 0) }
|
||||||
};
|
};
|
||||||
let npc_flags = NPCFlag(data.flags | flags.0);
|
let npc_flags = NPCFlag(data.flags | flags.0);
|
||||||
|
|
||||||
|
@ -257,6 +266,7 @@ impl NPCMap {
|
||||||
flag_num: data.flag_num,
|
flag_num: data.flag_num,
|
||||||
event_num: data.event_num,
|
event_num: data.event_num,
|
||||||
shock: 0,
|
shock: 0,
|
||||||
|
exp,
|
||||||
size,
|
size,
|
||||||
life,
|
life,
|
||||||
damage,
|
damage,
|
||||||
|
@ -267,6 +277,7 @@ impl NPCMap {
|
||||||
display_bounds,
|
display_bounds,
|
||||||
hit_bounds,
|
hit_bounds,
|
||||||
action_counter: 0,
|
action_counter: 0,
|
||||||
|
action_counter2: 0,
|
||||||
anim_counter: 0,
|
anim_counter: 0,
|
||||||
anim_rect: Rect::new(0, 0, 0, 0),
|
anim_rect: Rect::new(0, 0, 0, 0),
|
||||||
};
|
};
|
||||||
|
@ -277,6 +288,46 @@ impl NPCMap {
|
||||||
self.npcs.get_mut(&data.id).unwrap().get_mut()
|
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) {
|
pub fn garbage_collect(&mut self) {
|
||||||
self.npcs.retain(|_, npc_cell| npc_cell.borrow().cond.alive());
|
self.npcs.retain(|_, npc_cell| npc_cell.borrow().cond.alive());
|
||||||
}
|
}
|
||||||
|
@ -292,8 +343,8 @@ impl NPCMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_id(&mut self) -> u16 {
|
pub fn allocate_id(&mut self, start: u16) -> u16 {
|
||||||
for i in 0..(u16::MAX) {
|
for i in start..(u16::MAX) {
|
||||||
if !self.npc_ids.contains(&i) {
|
if !self.npc_ids.contains(&i) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -336,6 +387,37 @@ impl NPCMap {
|
||||||
new_npcs.append(&mut npcs);
|
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);
|
state.game_flags.set(npc.flag_num as usize, true);
|
||||||
|
|
||||||
// todo vanish / show damage
|
// todo vanish / show damage
|
||||||
|
@ -346,12 +428,17 @@ impl NPCMap {
|
||||||
|
|
||||||
for mut npc in new_npcs {
|
for mut npc in new_npcs {
|
||||||
let id = if npc.id == 0 {
|
let id = if npc.id == 0 {
|
||||||
self.allocate_id()
|
if npc.npc_type == 1 {
|
||||||
|
self.allocate_id(0x100)
|
||||||
|
} else {
|
||||||
|
self.allocate_id(0)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
npc.id
|
npc.id
|
||||||
};
|
};
|
||||||
|
|
||||||
npc.id = id;
|
npc.id = id;
|
||||||
|
self.npc_ids.insert(id);
|
||||||
self.npcs.insert(id, RefCell::new(npc));
|
self.npcs.insert(id, RefCell::new(npc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
146
src/npc/pickups.rs
Normal file
146
src/npc/pickups.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,6 +70,11 @@ impl PhysicalEntity for Player {
|
||||||
&mut self.flags
|
&mut self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn direction(&self) -> Direction {
|
||||||
|
self.direction
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_player(&self) -> bool {
|
fn is_player(&self) -> bool {
|
||||||
true
|
true
|
||||||
|
|
|
@ -683,8 +683,8 @@ impl Scene for GameScene {
|
||||||
self.player.target_y = self.player.y;
|
self.player.target_y = self.player.y;
|
||||||
self.frame.immediate_update(state, &self.player, &self.stage);
|
self.frame.immediate_update(state, &self.player, &self.stage);
|
||||||
|
|
||||||
//self.inventory.add_weapon(WeaponType::PolarStar, 0);
|
self.inventory.add_weapon(WeaponType::PolarStar, 0);
|
||||||
//self.player.equip.set_booster_2_0(true);
|
self.player.equip.set_booster_2_0(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ impl Scene for GameScene {
|
||||||
|
|
||||||
self.player.flags.0 = 0;
|
self.player.flags.0 = 0;
|
||||||
state.tick_carets();
|
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_map_collisions(state, &mut self.stage);
|
||||||
self.player.tick_npc_collisions(state, &mut self.npc_map);
|
self.player.tick_npc_collisions(state, &mut self.npc_map);
|
||||||
|
|
Loading…
Reference in a new issue