mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-04-01 07:16:57 +00:00
add CS+ game difficulties
This commit is contained in:
parent
a6272476ba
commit
6b7b6b7032
|
@ -1,10 +1,11 @@
|
|||
use std::fmt;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use num_traits::{abs, Num};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::{SeqAccess, Visitor};
|
||||
use serde::ser::SerializeTupleStruct;
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::texture_set::G_MAG;
|
||||
|
@ -392,6 +393,11 @@ pub fn interpolate_fix9_scale(old_val: i32, val: i32, frame_delta: f64) -> f32 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_timestamp() -> u64 {
|
||||
let now = SystemTime::now();
|
||||
now.duration_since(UNIX_EPOCH).unwrap().as_secs() as u64
|
||||
}
|
||||
|
||||
/// A RGBA color in the `sRGB` color space represented as `f32`'s in the range `[0.0-1.0]`
|
||||
///
|
||||
/// For convenience, [`WHITE`](constant.WHITE.html) and [`BLACK`](constant.BLACK.html) are provided.
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::framework::error::GameResult;
|
|||
use crate::framework::graphics;
|
||||
use crate::input::combined_menu_controller::CombinedMenuController;
|
||||
use crate::menu::save_select_menu::MenuSaveInfo;
|
||||
use crate::shared_game_state::{MenuCharacter, SharedGameState};
|
||||
use crate::shared_game_state::{GameDifficulty, MenuCharacter, SharedGameState};
|
||||
|
||||
pub mod pause_menu;
|
||||
pub mod save_select_menu;
|
||||
|
@ -435,6 +435,42 @@ impl Menu {
|
|||
ctx,
|
||||
)?;
|
||||
|
||||
// Difficulty
|
||||
if state.constants.is_cs_plus && !state.settings.original_textures {
|
||||
let difficulty = GameDifficulty::from_save_value(save.difficulty);
|
||||
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
|
||||
batch.add_rect(
|
||||
self.x as f32 + 20.0,
|
||||
y + 10.0,
|
||||
&Rect::new_size(
|
||||
0,
|
||||
GameDifficulty::get_skinsheet_offset(difficulty).saturating_mul(4 * 16),
|
||||
16,
|
||||
16,
|
||||
),
|
||||
);
|
||||
batch.draw(ctx)?;
|
||||
} else {
|
||||
let mut difficulty_name: String = "Difficulty: ".to_owned();
|
||||
|
||||
match save.difficulty {
|
||||
0 => difficulty_name.push_str("Normal"),
|
||||
2 => difficulty_name.push_str("Easy"),
|
||||
4 => difficulty_name.push_str("Hard"),
|
||||
_ => difficulty_name.push_str("(unknown)"),
|
||||
}
|
||||
|
||||
state.font.draw_text(
|
||||
difficulty_name.chars(),
|
||||
self.x as f32 + 20.0,
|
||||
y + 10.0,
|
||||
&state.constants,
|
||||
&mut state.texture_set,
|
||||
ctx,
|
||||
)?;
|
||||
}
|
||||
|
||||
// Weapons
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "ArmsImage")?;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::input::combined_menu_controller::CombinedMenuController;
|
|||
use crate::menu::MenuEntry;
|
||||
use crate::menu::{Menu, MenuSelectionResult};
|
||||
use crate::profile::GameProfile;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::shared_game_state::{GameDifficulty, SharedGameState};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MenuSaveInfo {
|
||||
|
@ -14,21 +14,24 @@ pub struct MenuSaveInfo {
|
|||
pub life: u16,
|
||||
pub weapon_count: usize,
|
||||
pub weapon_id: [u32; 8],
|
||||
pub difficulty: u8,
|
||||
}
|
||||
|
||||
impl Default for MenuSaveInfo {
|
||||
fn default() -> Self {
|
||||
MenuSaveInfo { current_map: 0, max_life: 0, life: 0, weapon_count: 0, weapon_id: [0; 8] }
|
||||
MenuSaveInfo { current_map: 0, max_life: 0, life: 0, weapon_count: 0, weapon_id: [0; 8], difficulty: 0 }
|
||||
}
|
||||
}
|
||||
pub enum CurrentMenu {
|
||||
SaveMenu,
|
||||
DifficultyMenu,
|
||||
DeleteConfirm,
|
||||
}
|
||||
pub struct SaveSelectMenu {
|
||||
pub saves: [MenuSaveInfo; 3],
|
||||
current_menu: CurrentMenu,
|
||||
save_menu: Menu,
|
||||
difficulty_menu: Menu,
|
||||
delete_confirm: Menu,
|
||||
}
|
||||
|
||||
|
@ -37,13 +40,15 @@ impl SaveSelectMenu {
|
|||
SaveSelectMenu {
|
||||
saves: [MenuSaveInfo::default(); 3],
|
||||
current_menu: CurrentMenu::SaveMenu,
|
||||
save_menu: Menu::new(0, 0, 200, 0),
|
||||
save_menu: Menu::new(0, 0, 230, 0),
|
||||
difficulty_menu: Menu::new(0, 0, 130, 0),
|
||||
delete_confirm: Menu::new(0, 0, 75, 0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult {
|
||||
self.save_menu = Menu::new(0, 0, 200, 0);
|
||||
self.save_menu = Menu::new(0, 0, 230, 0);
|
||||
self.difficulty_menu = Menu::new(0, 0, 130, 0);
|
||||
self.delete_confirm = Menu::new(0, 0, 75, 0);
|
||||
|
||||
for (iter, save) in self.saves.iter_mut().enumerate() {
|
||||
|
@ -55,6 +60,7 @@ impl SaveSelectMenu {
|
|||
save.life = loaded_save.life;
|
||||
save.weapon_count = loaded_save.weapon_data.iter().filter(|weapon| weapon.weapon_id != 0).count();
|
||||
save.weapon_id = loaded_save.weapon_data.map(|weapon| weapon.weapon_id);
|
||||
save.difficulty = loaded_save.difficulty;
|
||||
|
||||
self.save_menu.push_entry(MenuEntry::SaveData(*save));
|
||||
} else {
|
||||
|
@ -65,6 +71,14 @@ impl SaveSelectMenu {
|
|||
self.save_menu.push_entry(MenuEntry::Active("< Back".to_owned()));
|
||||
self.save_menu.push_entry(MenuEntry::Disabled("Press Right to Delete".to_owned()));
|
||||
|
||||
self.difficulty_menu.push_entry(MenuEntry::Disabled("Select Difficulty".to_owned()));
|
||||
self.difficulty_menu.push_entry(MenuEntry::Active("Easy".to_owned()));
|
||||
self.difficulty_menu.push_entry(MenuEntry::Active("Normal".to_owned()));
|
||||
self.difficulty_menu.push_entry(MenuEntry::Active("Hard".to_owned()));
|
||||
self.difficulty_menu.push_entry(MenuEntry::Active("< Back".to_owned()));
|
||||
|
||||
self.difficulty_menu.selected = 2;
|
||||
|
||||
self.delete_confirm.push_entry(MenuEntry::Disabled("Delete?".to_owned()));
|
||||
self.delete_confirm.push_entry(MenuEntry::Active("Yes".to_owned()));
|
||||
self.delete_confirm.push_entry(MenuEntry::Active("No".to_owned()));
|
||||
|
@ -80,6 +94,10 @@ impl SaveSelectMenu {
|
|||
self.save_menu.update_height();
|
||||
self.save_menu.x = ((state.canvas_size.0 - self.save_menu.width as f32) / 2.0).floor() as isize;
|
||||
self.save_menu.y = 30 + ((state.canvas_size.1 - self.save_menu.height as f32) / 2.0).floor() as isize;
|
||||
self.difficulty_menu.update_height();
|
||||
self.difficulty_menu.x = ((state.canvas_size.0 - self.difficulty_menu.width as f32) / 2.0).floor() as isize;
|
||||
self.difficulty_menu.y =
|
||||
30 + ((state.canvas_size.1 - self.difficulty_menu.height as f32) / 2.0).floor() as isize;
|
||||
self.delete_confirm.update_height();
|
||||
self.delete_confirm.x = ((state.canvas_size.0 - self.delete_confirm.width as f32) / 2.0).floor() as isize;
|
||||
self.delete_confirm.y = 30 + ((state.canvas_size.1 - self.delete_confirm.height as f32) / 2.0).floor() as isize
|
||||
|
@ -95,22 +113,20 @@ impl SaveSelectMenu {
|
|||
self.update_sizes(state);
|
||||
match self.current_menu {
|
||||
CurrentMenu::SaveMenu => match self.save_menu.tick(controller, state) {
|
||||
MenuSelectionResult::Selected(0, _) => {
|
||||
state.save_slot = 1;
|
||||
state.reload_resources(ctx)?;
|
||||
state.load_or_start_game(ctx)?;
|
||||
}
|
||||
MenuSelectionResult::Selected(1, _) => {
|
||||
state.save_slot = 2;
|
||||
state.reload_resources(ctx)?;
|
||||
state.load_or_start_game(ctx)?;
|
||||
}
|
||||
MenuSelectionResult::Selected(2, _) => {
|
||||
state.save_slot = 3;
|
||||
state.reload_resources(ctx)?;
|
||||
state.load_or_start_game(ctx)?;
|
||||
}
|
||||
MenuSelectionResult::Selected(3, _) | MenuSelectionResult::Canceled => exit_action(),
|
||||
MenuSelectionResult::Selected(slot, _) => {
|
||||
state.save_slot = slot + 1;
|
||||
|
||||
if let Ok(_) =
|
||||
filesystem::user_open(ctx, state.get_save_filename(state.save_slot).unwrap_or("".to_string()))
|
||||
{
|
||||
state.reload_resources(ctx)?;
|
||||
state.load_or_start_game(ctx)?;
|
||||
} else {
|
||||
self.difficulty_menu.selected = 2;
|
||||
self.current_menu = CurrentMenu::DifficultyMenu;
|
||||
}
|
||||
}
|
||||
MenuSelectionResult::Right(slot, _, _) => {
|
||||
if slot <= 2 {
|
||||
self.current_menu = CurrentMenu::DeleteConfirm;
|
||||
|
@ -119,6 +135,17 @@ impl SaveSelectMenu {
|
|||
}
|
||||
_ => (),
|
||||
},
|
||||
CurrentMenu::DifficultyMenu => match self.difficulty_menu.tick(controller, state) {
|
||||
MenuSelectionResult::Selected(4, _) | MenuSelectionResult::Canceled => {
|
||||
self.current_menu = CurrentMenu::SaveMenu;
|
||||
}
|
||||
MenuSelectionResult::Selected(item, _) => {
|
||||
state.difficulty = GameDifficulty::from_index(item - 1);
|
||||
state.reload_resources(ctx)?;
|
||||
state.load_or_start_game(ctx)?;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
CurrentMenu::DeleteConfirm => match self.delete_confirm.tick(controller, state) {
|
||||
MenuSelectionResult::Selected(1, _) => {
|
||||
state.sound_manager.play_sfx(17); // Player Death sfx
|
||||
|
@ -144,6 +171,9 @@ impl SaveSelectMenu {
|
|||
CurrentMenu::SaveMenu => {
|
||||
self.save_menu.draw(state, ctx)?;
|
||||
}
|
||||
CurrentMenu::DifficultyMenu => {
|
||||
self.difficulty_menu.draw(state, ctx)?;
|
||||
}
|
||||
CurrentMenu::DeleteConfirm => {
|
||||
self.delete_confirm.draw(state, ctx)?;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::npc::list::NPCList;
|
|||
use crate::npc::{NPCLayer, NPC};
|
||||
use crate::player::Player;
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::shared_game_state::{GameDifficulty, SharedGameState};
|
||||
use crate::stage::Stage;
|
||||
|
||||
impl NPC {
|
||||
|
@ -137,6 +137,11 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub(crate) fn tick_n015_chest_closed(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||
if state.difficulty == GameDifficulty::Hard && self.chest_has_missile_flag() {
|
||||
self.cond.set_alive(false);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.action_num {
|
||||
0 | 1 => {
|
||||
if self.action_num == 0 {
|
||||
|
@ -332,6 +337,11 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub(crate) fn tick_n021_chest_open(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if state.difficulty == GameDifficulty::Hard && self.chest_has_missile_flag() {
|
||||
self.cond.set_alive(false);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
|
@ -429,6 +439,11 @@ impl NPC {
|
|||
}
|
||||
|
||||
pub(crate) fn tick_n032_life_capsule(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if state.difficulty == GameDifficulty::Hard {
|
||||
self.cond.set_alive(false);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.anim_counter = (self.anim_counter + 1) % 4;
|
||||
self.anim_num = self.anim_counter / 2;
|
||||
self.anim_rect = state.constants.npc.n032_life_capsule[self.anim_num as usize];
|
||||
|
@ -2609,4 +2624,9 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn chest_has_missile_flag(&self) -> bool {
|
||||
let missile_flags: [u16; 9] = [200, 201, 202, 218, 550, 766, 880, 920, 1551];
|
||||
missile_flags.contains(&self.flag_num)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -839,13 +839,15 @@ impl Player {
|
|||
self.vel_y = -0x400; // -2.0fix9
|
||||
}
|
||||
|
||||
self.life = self.life.saturating_sub(hp as u16);
|
||||
let final_hp = state.get_damage(hp);
|
||||
|
||||
self.life = self.life.saturating_sub(final_hp as u16);
|
||||
|
||||
if self.equip.has_whimsical_star() && self.stars > 0 {
|
||||
self.stars -= 1;
|
||||
}
|
||||
|
||||
self.damage = self.damage.saturating_add(hp as u16);
|
||||
self.damage = self.damage.saturating_add(final_hp as u16);
|
||||
if self.popup.value > 0 {
|
||||
self.popup.set_value(-(self.damage as i16));
|
||||
} else {
|
||||
|
|
|
@ -81,6 +81,7 @@ pub struct BasicPlayerSkin {
|
|||
direction: Direction,
|
||||
metadata: SkinMeta,
|
||||
tick: u16,
|
||||
skinsheet_offset: u16,
|
||||
}
|
||||
|
||||
impl BasicPlayerSkin {
|
||||
|
@ -111,8 +112,16 @@ impl BasicPlayerSkin {
|
|||
direction: Direction::Left,
|
||||
metadata,
|
||||
tick: 0,
|
||||
skinsheet_offset: state.get_skinsheet_offset(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_y_offset_by(&self, y: u16) -> u16 {
|
||||
return self
|
||||
.skinsheet_offset
|
||||
.saturating_mul(self.metadata.frame_size_height.saturating_mul(4))
|
||||
.saturating_add(y);
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerSkin for BasicPlayerSkin {
|
||||
|
@ -143,9 +152,13 @@ impl PlayerSkin for BasicPlayerSkin {
|
|||
|
||||
let y_offset = if direction == Direction::Left { 0 } else { self.metadata.frame_size_height }
|
||||
+ match self.appearance {
|
||||
PlayerAppearanceState::Default => 0,
|
||||
PlayerAppearanceState::MimigaMask => self.metadata.frame_size_height.saturating_mul(2),
|
||||
PlayerAppearanceState::Custom(i) => (i as u16).saturating_mul(self.metadata.frame_size_height),
|
||||
PlayerAppearanceState::Default => self.get_y_offset_by(0),
|
||||
PlayerAppearanceState::MimigaMask => {
|
||||
self.get_y_offset_by(self.metadata.frame_size_height.saturating_mul(2))
|
||||
}
|
||||
PlayerAppearanceState::Custom(i) => {
|
||||
self.get_y_offset_by((i as u16).saturating_mul(self.metadata.frame_size_height))
|
||||
}
|
||||
};
|
||||
|
||||
Rect::new_size(
|
||||
|
@ -241,4 +254,8 @@ impl PlayerSkin for BasicPlayerSkin {
|
|||
rect.bottom = rect.top + 8;
|
||||
return rect;
|
||||
}
|
||||
|
||||
fn apply_gamestate(&mut self, state: &SharedGameState) {
|
||||
self.skinsheet_offset = state.get_skinsheet_offset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::bitfield;
|
||||
use crate::common::{Color, Direction, Rect};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
pub mod basic;
|
||||
|
||||
|
@ -92,6 +93,9 @@ pub trait PlayerSkin: PlayerSkinClone {
|
|||
|
||||
/// Returns Whimsical Star rect location
|
||||
fn get_whimsical_star_rect(&self, index: usize) -> Rect<u16>;
|
||||
|
||||
/// Applies modifications on the skin based on current state
|
||||
fn apply_gamestate(&mut self, state: &SharedGameState);
|
||||
}
|
||||
|
||||
pub trait PlayerSkinClone {
|
||||
|
|
|
@ -3,13 +3,13 @@ use std::io;
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt, BE, LE};
|
||||
use num_traits::{clamp, FromPrimitive};
|
||||
|
||||
use crate::common::{Direction, FadeState};
|
||||
use crate::common::{get_timestamp, Direction, FadeState};
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameError::ResourceLoadError;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::player::ControlMode;
|
||||
use crate::scene::game_scene::GameScene;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::shared_game_state::{GameDifficulty, SharedGameState};
|
||||
use crate::weapon::{WeaponLevel, WeaponType};
|
||||
|
||||
pub struct WeaponData {
|
||||
|
@ -44,6 +44,8 @@ pub struct GameProfile {
|
|||
pub teleporter_slots: [TeleporterSlotData; 8],
|
||||
pub map_flags: [u8; 128],
|
||||
pub flags: [u8; 1000],
|
||||
pub timestamp: u64,
|
||||
pub difficulty: u8,
|
||||
}
|
||||
|
||||
impl GameProfile {
|
||||
|
@ -144,6 +146,11 @@ impl GameProfile {
|
|||
game_scene.inventory_player2 = game_scene.inventory_player1.clone();
|
||||
|
||||
game_scene.player1.cond.0 = 0x80;
|
||||
|
||||
state.difficulty = GameDifficulty::from_save_value(self.difficulty);
|
||||
|
||||
game_scene.player1.skin.apply_gamestate(state);
|
||||
game_scene.player2.skin.apply_gamestate(state);
|
||||
}
|
||||
|
||||
pub fn dump(state: &mut SharedGameState, game_scene: &mut GameScene) -> GameProfile {
|
||||
|
@ -228,6 +235,9 @@ impl GameProfile {
|
|||
}
|
||||
}
|
||||
|
||||
let timestamp = get_timestamp();
|
||||
let difficulty = state.difficulty.to_save_value();
|
||||
|
||||
GameProfile {
|
||||
current_map,
|
||||
current_song,
|
||||
|
@ -247,6 +257,8 @@ impl GameProfile {
|
|||
teleporter_slots,
|
||||
map_flags,
|
||||
flags,
|
||||
timestamp,
|
||||
difficulty,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,6 +303,11 @@ impl GameProfile {
|
|||
data.write_u32::<BE>(0x464c4147)?;
|
||||
data.write(&self.flags)?;
|
||||
|
||||
data.write_u32::<LE>(0)?; // unused(?) CS+ space
|
||||
|
||||
data.write_u64::<LE>(self.timestamp)?;
|
||||
data.write_u8(self.difficulty)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -363,6 +380,11 @@ impl GameProfile {
|
|||
let mut flags = [0u8; 1000];
|
||||
data.read_exact(&mut flags)?;
|
||||
|
||||
data.read_u32::<LE>().unwrap_or(0); // unused(?) CS+ space
|
||||
|
||||
let timestamp = data.read_u64::<LE>().unwrap_or(0);
|
||||
let difficulty = data.read_u8().unwrap_or(0);
|
||||
|
||||
Ok(GameProfile {
|
||||
current_map,
|
||||
current_song,
|
||||
|
@ -382,6 +404,8 @@ impl GameProfile {
|
|||
teleporter_slots,
|
||||
map_flags,
|
||||
flags,
|
||||
timestamp,
|
||||
difficulty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::ops::Div;
|
||||
use std::{cmp, ops::Div};
|
||||
|
||||
use bitvec::vec::BitVec;
|
||||
use chrono::{Datelike, Local};
|
||||
|
@ -67,6 +67,49 @@ impl TimingMode {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
pub enum GameDifficulty {
|
||||
Easy,
|
||||
Normal,
|
||||
Hard,
|
||||
}
|
||||
|
||||
impl GameDifficulty {
|
||||
pub fn from_index(index: usize) -> GameDifficulty {
|
||||
match index {
|
||||
0 => GameDifficulty::Easy,
|
||||
1 => GameDifficulty::Normal,
|
||||
2 => GameDifficulty::Hard,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_save_value(val: u8) -> GameDifficulty {
|
||||
match val {
|
||||
0 => GameDifficulty::Normal,
|
||||
2 => GameDifficulty::Easy,
|
||||
4 => GameDifficulty::Hard,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_save_value(self) -> u8 {
|
||||
match self {
|
||||
GameDifficulty::Normal => 0,
|
||||
GameDifficulty::Easy => 2,
|
||||
GameDifficulty::Hard => 4,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_skinsheet_offset(difficulty: GameDifficulty) -> u16 {
|
||||
match difficulty {
|
||||
GameDifficulty::Easy => 1, // Yellow Quote
|
||||
GameDifficulty::Normal => 0, // Good Quote
|
||||
GameDifficulty::Hard => 2, // Human Quote
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fps {
|
||||
pub frame_count: u32,
|
||||
pub fps: u32,
|
||||
|
@ -187,6 +230,7 @@ pub struct SharedGameState {
|
|||
pub sound_manager: SoundManager,
|
||||
pub settings: Settings,
|
||||
pub save_slot: usize,
|
||||
pub difficulty: GameDifficulty,
|
||||
pub shutdown: bool,
|
||||
}
|
||||
|
||||
|
@ -283,6 +327,7 @@ impl SharedGameState {
|
|||
sound_manager,
|
||||
settings,
|
||||
save_slot: 1,
|
||||
difficulty: GameDifficulty::Normal,
|
||||
shutdown: false,
|
||||
})
|
||||
}
|
||||
|
@ -584,4 +629,31 @@ impl SharedGameState {
|
|||
return "/290.rec".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_damage(&self, hp: i32) -> i32 {
|
||||
match self.difficulty {
|
||||
GameDifficulty::Easy => cmp::max(hp / 2, 1),
|
||||
GameDifficulty::Normal | GameDifficulty::Hard => hp,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_skinsheet_offset(&self) -> u16 {
|
||||
if !self.constants.is_cs_plus || self.settings.original_textures {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if self.settings.seasonal_textures {
|
||||
let season = Season::current();
|
||||
|
||||
if season == Season::Halloween {
|
||||
return 3; // Edgy Quote
|
||||
}
|
||||
|
||||
if season == Season::Christmas {
|
||||
return 4; // Furry Quote
|
||||
}
|
||||
}
|
||||
|
||||
GameDifficulty::get_skinsheet_offset(self.difficulty)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue