mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-23 10:29:18 +00:00
complete the xp and weapon leveling system
This commit is contained in:
parent
84ac596d50
commit
aee221107e
|
@ -119,6 +119,7 @@ pub struct BulletRects {
|
|||
pub struct WeaponConsts {
|
||||
pub bullet_table: Vec<BulletData>,
|
||||
pub bullet_rects: BulletRects,
|
||||
pub level_table: [[u16; 3]; 14],
|
||||
}
|
||||
|
||||
impl Clone for WeaponConsts {
|
||||
|
@ -126,6 +127,7 @@ impl Clone for WeaponConsts {
|
|||
WeaponConsts {
|
||||
bullet_table: self.bullet_table.clone(),
|
||||
bullet_rects: self.bullet_rects,
|
||||
level_table: self.level_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -935,6 +937,22 @@ impl EngineConstants {
|
|||
Rect { left: 256, top: 32, right: 264, bottom: 40 },
|
||||
],
|
||||
},
|
||||
level_table: [
|
||||
[0, 0, 100],
|
||||
[30, 40, 16],
|
||||
[10, 20, 10],
|
||||
[10, 20, 20],
|
||||
[30, 40, 10],
|
||||
[10, 20, 10],
|
||||
[10, 20, 30],
|
||||
[10, 20, 5],
|
||||
[10, 20, 100],
|
||||
[30, 60, 0],
|
||||
[30, 60, 10],
|
||||
[10, 20, 100],
|
||||
[1, 1, 1],
|
||||
[40, 60, 200],
|
||||
],
|
||||
},
|
||||
tex_sizes: case_insensitive_hashmap! {
|
||||
"ArmsImage" => (256, 16),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::engine_constants::EngineConstants;
|
||||
use crate::SharedGameState;
|
||||
use crate::weapon::{Weapon, WeaponLevel, WeaponType};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -11,6 +13,13 @@ pub struct Inventory {
|
|||
weapons: Vec<Weapon>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AddExperienceResult {
|
||||
None,
|
||||
LevelUp,
|
||||
AddStar,
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Inventory {
|
||||
|
@ -56,6 +65,10 @@ impl Inventory {
|
|||
self.weapons.get(idx)
|
||||
}
|
||||
|
||||
pub fn get_current_weapon(&self) -> Option<&Weapon> {
|
||||
self.weapons.get(self.current_weapon as usize)
|
||||
}
|
||||
|
||||
pub fn get_current_weapon_mut(&mut self) -> Option<&mut Weapon> {
|
||||
self.weapons.get_mut(self.current_weapon as usize)
|
||||
}
|
||||
|
@ -73,6 +86,50 @@ impl Inventory {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_xp(&mut self, exp: u16, state: &mut SharedGameState) -> AddExperienceResult {
|
||||
let mut result = AddExperienceResult::None;
|
||||
|
||||
if let Some(weapon) = self.get_current_weapon_mut() {
|
||||
let curr_level_idx = weapon.level as usize - 1;
|
||||
let lvl_table = state.constants.weapon.level_table[weapon.wtype as usize];
|
||||
|
||||
weapon.experience += exp;
|
||||
|
||||
if weapon.level == WeaponLevel::Level3 {
|
||||
if weapon.experience > lvl_table[2] {
|
||||
weapon.experience = lvl_table[2];
|
||||
result = AddExperienceResult::AddStar;
|
||||
}
|
||||
} else {
|
||||
if weapon.experience > lvl_table[curr_level_idx] {
|
||||
weapon.level = weapon.level.next();
|
||||
weapon.experience = 0;
|
||||
|
||||
if weapon.wtype != WeaponType::Spur {
|
||||
result = AddExperienceResult::LevelUp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_current_max_exp(&self, constants: &EngineConstants) -> (u16, u16) {
|
||||
if let Some(weapon) = self.weapons.get(self.current_weapon as usize) {
|
||||
if weapon.level == WeaponLevel::None {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
let level_idx = weapon.level as usize - 1;
|
||||
let max_exp = constants.weapon.level_table[weapon.wtype as usize][level_idx];
|
||||
|
||||
(weapon.experience, max_exp)
|
||||
} else {
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_current_ammo(&self) -> (u16, u16) {
|
||||
if let Some(weapon) = self.weapons.get(self.current_weapon as usize) {
|
||||
(weapon.ammo, weapon.max_ammo)
|
||||
|
|
|
@ -43,12 +43,12 @@ pub struct Player {
|
|||
pub shock_counter: u8,
|
||||
pub current_weapon: u8,
|
||||
pub update_target: bool,
|
||||
pub stars: u8,
|
||||
weapon_offset_y: i8,
|
||||
index_x: isize,
|
||||
index_y: isize,
|
||||
sprash: bool,
|
||||
splash: bool,
|
||||
booster_switch: u8,
|
||||
star: u8,
|
||||
bubble: u8,
|
||||
exp_wait: isize,
|
||||
exp_count: isize,
|
||||
|
@ -82,7 +82,7 @@ impl Player {
|
|||
booster_fuel: 0,
|
||||
index_x: 0,
|
||||
index_y: 0,
|
||||
sprash: false,
|
||||
splash: false,
|
||||
update_target: true,
|
||||
up: false,
|
||||
down: false,
|
||||
|
@ -90,7 +90,7 @@ impl Player {
|
|||
weapon_offset_y: 0,
|
||||
shock_counter: 0,
|
||||
booster_switch: 0,
|
||||
star: 0,
|
||||
stars: 0,
|
||||
bubble: 0,
|
||||
exp_wait: 0,
|
||||
exp_count: 0,
|
||||
|
@ -357,7 +357,7 @@ impl Player {
|
|||
// todo: water splashing
|
||||
|
||||
if !self.flags.in_water() {
|
||||
self.sprash = false;
|
||||
self.splash = false;
|
||||
}
|
||||
|
||||
// spike damage
|
||||
|
@ -528,8 +528,8 @@ impl Player {
|
|||
|
||||
self.life = if hp >= self.life as isize { 0 } else { (self.life as isize - hp) as usize };
|
||||
|
||||
if self.equip.has_whimsical_star() && self.star > 0 {
|
||||
self.star -= 1;
|
||||
if self.equip.has_whimsical_star() && self.stars > 0 {
|
||||
self.stars -= 1;
|
||||
}
|
||||
|
||||
if self.life == 0 {
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::player::Player;
|
|||
use crate::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
use std::borrow::Borrow;
|
||||
use crate::inventory::{Inventory, AddExperienceResult};
|
||||
|
||||
impl PhysicalEntity for Player {
|
||||
#[inline(always)]
|
||||
|
@ -152,10 +153,10 @@ impl Player {
|
|||
flags
|
||||
}
|
||||
|
||||
pub fn tick_npc_collisions(&mut self, state: &mut SharedGameState, npc_map: &mut NPCMap) {
|
||||
pub fn tick_npc_collisions(&mut self, state: &mut SharedGameState, npc_map: &mut NPCMap, inventory: &mut Inventory) {
|
||||
for npc_id in npc_map.npc_ids.iter() {
|
||||
if let Some(npc_cell) = npc_map.npcs.get(npc_id) {
|
||||
let npc = npc_cell.borrow_mut();
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
if !npc.cond.alive() { continue; }
|
||||
|
||||
let mut flags = Flag(0);
|
||||
|
@ -169,6 +170,23 @@ impl Player {
|
|||
flags = self.judge_hit_npc_non_solid(npc.borrow());
|
||||
}
|
||||
|
||||
// xp pickup
|
||||
if flags.0 != 0 && npc.npc_type == 1 {
|
||||
match inventory.add_xp(npc.exp, state) {
|
||||
AddExperienceResult::None => {},
|
||||
AddExperienceResult::LevelUp => {
|
||||
// todo play sound 27
|
||||
state.create_caret(self.x, self.y, CaretType::LevelUp, Direction::Left);
|
||||
},
|
||||
AddExperienceResult::AddStar => {
|
||||
if self.equip.has_whimsical_star() && self.stars < 3 {
|
||||
self.stars += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
npc.cond.set_alive(false);
|
||||
}
|
||||
|
||||
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
||||
state.textscript_vm.start_script(npc.event_num);
|
||||
self.cond.set_interacted(false);
|
||||
|
|
|
@ -103,6 +103,7 @@ impl GameScene {
|
|||
// none
|
||||
let weap_x = self.weapon_x_pos as f32;
|
||||
let (ammo, max_ammo) = self.inventory.get_current_ammo();
|
||||
let (xp, max_xp) = self.inventory.get_current_max_exp(&state.constants);
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;
|
||||
|
||||
if max_ammo == 0 {
|
||||
|
@ -113,17 +114,28 @@ impl GameScene {
|
|||
}
|
||||
|
||||
// per
|
||||
batch.add_rect(16.0 + 32.0, 24.0,
|
||||
batch.add_rect(weap_x + 32.0, 24.0,
|
||||
&Rect::<usize>::new_size(72, 48, 8, 8));
|
||||
// lv
|
||||
batch.add_rect(16.0, 32.0,
|
||||
batch.add_rect(weap_x, 32.0,
|
||||
&Rect::<usize>::new_size(80, 80, 16, 8));
|
||||
// xp box
|
||||
batch.add_rect(40.0, 32.0,
|
||||
batch.add_rect(weap_x + 24.0, 32.0,
|
||||
&Rect::<usize>::new_size(0, 72, 40, 8));
|
||||
// experience
|
||||
//batch.add_rect(40.0, 32.0,
|
||||
// &Rect::<usize>::new_size(0, 80, (40), 8)); // todo
|
||||
if max_xp > 0 {
|
||||
if xp == max_xp {
|
||||
// max level bar
|
||||
batch.add_rect(weap_x + 24.0, 32.0,
|
||||
&Rect::<usize>::new_size(40, 72, 40, 8));
|
||||
|
||||
} else {
|
||||
// xp bar
|
||||
let bar_width = (xp as f32 / max_xp as f32 * 40.0) as usize;
|
||||
|
||||
batch.add_rect(weap_x + 24.0, 32.0,
|
||||
&Rect::<usize>::new_size(0, 80, bar_width, 8));
|
||||
}
|
||||
}
|
||||
|
||||
if self.player.max_life != 0 {
|
||||
// life box
|
||||
|
@ -174,7 +186,7 @@ impl GameScene {
|
|||
self.draw_number(weap_x + 64.0, 16.0, ammo as usize, Alignment::Right, state, ctx)?;
|
||||
self.draw_number(weap_x + 64.0, 24.0, max_ammo as usize, Alignment::Right, state, ctx)?;
|
||||
}
|
||||
self.draw_number(40.0, 32.0, self.inventory.get_current_level() as usize, Alignment::Right, state, ctx)?;
|
||||
self.draw_number(weap_x + 24.0, 32.0, self.inventory.get_current_level() as usize, Alignment::Right, state, ctx)?;
|
||||
self.draw_number(40.0, 40.0, self.life_bar as usize, Alignment::Right, state, ctx)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -486,7 +498,6 @@ impl GameScene {
|
|||
|
||||
let text_offset = if state.textscript_vm.face == 0 { 0.0 } else { 56.0 };
|
||||
|
||||
// todo: proper text rendering
|
||||
if !state.textscript_vm.line_1.is_empty() {
|
||||
state.font.draw_text(state.textscript_vm.line_1.iter().copied(), left_pos + text_offset + 14.0, top_pos + 10.0, &state.constants, &mut state.texture_set, ctx)?;
|
||||
}
|
||||
|
@ -683,8 +694,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(())
|
||||
}
|
||||
|
||||
|
@ -706,7 +717,7 @@ impl Scene for GameScene {
|
|||
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);
|
||||
self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory);
|
||||
|
||||
for npc_id in self.npc_map.npc_ids.iter() {
|
||||
if let Some(npc_cell) = self.npc_map.npcs.get_mut(npc_id) {
|
||||
|
|
|
@ -22,15 +22,6 @@ pub enum WeaponType {
|
|||
Spur = 13,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Weapon {
|
||||
pub wtype: WeaponType,
|
||||
pub level: WeaponLevel,
|
||||
pub experience: u16,
|
||||
pub ammo: u16,
|
||||
pub max_ammo: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum WeaponLevel {
|
||||
|
@ -40,6 +31,26 @@ pub enum WeaponLevel {
|
|||
Level3 = 3,
|
||||
}
|
||||
|
||||
impl WeaponLevel {
|
||||
pub fn next(self) -> WeaponLevel {
|
||||
match self {
|
||||
WeaponLevel::None => { WeaponLevel::Level1 }
|
||||
WeaponLevel::Level1 => { WeaponLevel::Level2 }
|
||||
WeaponLevel::Level2 => { WeaponLevel::Level3 }
|
||||
WeaponLevel::Level3 => { WeaponLevel::Level3 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Weapon {
|
||||
pub wtype: WeaponType,
|
||||
pub level: WeaponLevel,
|
||||
pub experience: u16,
|
||||
pub ammo: u16,
|
||||
pub max_ammo: u16,
|
||||
}
|
||||
|
||||
impl Weapon {
|
||||
pub fn new(wtype: WeaponType, level: WeaponLevel, experience: u16, ammo: u16, max_ammo: u16) -> Weapon {
|
||||
Weapon {
|
||||
|
|
Loading…
Reference in a new issue