add coop menu (#141)

This commit is contained in:
IruzzArcana 2022-06-22 23:08:36 +01:00 committed by GitHub
parent d7face2544
commit 18a7670248
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 243 additions and 17 deletions

View File

@ -41,6 +41,16 @@
"hard": "Hard"
},
"coop_menu": {
"title": "Select Number of Players",
"one": "Single Player",
"two": "Two Players"
},
"skin_menu": {
"title": "Select Player 2's appearance",
"label": "Appearance:"
},
"challenge_menu": {
"start": "Start",
"no_replay": "No Replay",

View File

@ -36,6 +36,15 @@
"normal": "普通",
"hard": "難しい"
},
"coop_menu": {
"title": "プレイヤー数を選択",
"one":"1人プレイ",
"two": "2人プレイ"
},
"skin_menu": {
"title": "プレーヤー2の外観を選択します",
"label": "外観:"
},
"challenge_menu": {
"start": "スタート",
"no_replay": "ノーリプレイ",

View File

@ -142,7 +142,7 @@ impl LiveDebugger {
game_scene.drop_player2();
}
} else if ui.button("Add Player 2") {
game_scene.add_player2();
game_scene.add_player2(state);
}
ui.same_line();

120
src/menu/coop_menu.rs Normal file
View File

@ -0,0 +1,120 @@
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::filesystem;
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::{PlayerCount, SharedGameState};
pub enum CurrentMenu {
CoopMenu,
PlayerSkin,
}
pub struct PlayerCountMenu {
current_menu: CurrentMenu,
coop_menu: Menu,
skin_menu: Menu,
}
impl PlayerCountMenu {
pub fn new() -> PlayerCountMenu {
PlayerCountMenu {
coop_menu: Menu::new(0, 0, 130, 0),
skin_menu: Menu::new(0, 0, 130, 0),
current_menu: CurrentMenu::CoopMenu,
}
}
pub fn init(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult {
self.coop_menu = Menu::new(0, 0, 130, 0);
self.skin_menu = Menu::new(0, 0, 130, 0);
self.coop_menu.push_entry(MenuEntry::Disabled(state.t("menus.coop_menu.title")));
self.coop_menu.push_entry(MenuEntry::Active(state.t("menus.coop_menu.one")));
self.coop_menu.push_entry(MenuEntry::Active(state.t("menus.coop_menu.two")));
self.coop_menu.push_entry(MenuEntry::Active(state.t("common.back")));
self.coop_menu.selected = 1;
self.skin_menu.push_entry(MenuEntry::Disabled(state.t("menus.skin_menu.title")));
self.skin_menu.push_entry(MenuEntry::PlayerSkin);
self.skin_menu.push_entry(MenuEntry::Active(state.t("menus.main_menu.start")));
self.skin_menu.push_entry(MenuEntry::Active(state.t("common.back")));
self.skin_menu.selected = 1;
self.update_sizes(state);
Ok(())
}
fn update_sizes(&mut self, state: &SharedGameState) {
self.coop_menu.update_width(state);
self.coop_menu.update_height();
self.coop_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.3).floor() as isize;
self.coop_menu.y =
30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
self.skin_menu.update_width(state);
self.skin_menu.update_height();
self.skin_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.3).floor() as isize;
self.skin_menu.y =
30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
}
pub fn tick(
&mut self,
exit_action: &mut dyn FnMut(),
controller: &mut CombinedMenuController,
state: &mut SharedGameState,
ctx: &mut Context,
) -> GameResult {
self.update_sizes(state);
match self.current_menu {
CurrentMenu::CoopMenu => match self.coop_menu.tick(controller, state) {
MenuSelectionResult::Selected(3, _) | MenuSelectionResult::Canceled => exit_action(),
MenuSelectionResult::Selected(1, _) => {
state.player_count = PlayerCount::One;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
}
MenuSelectionResult::Selected(2, _) => {
if state.constants.is_cs_plus {
self.current_menu = CurrentMenu::PlayerSkin;
} else {
state.player_count = PlayerCount::Two;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
}
}
_ => (),
},
CurrentMenu::PlayerSkin => match self.skin_menu.tick(controller, state) {
MenuSelectionResult::Selected(3, _) | MenuSelectionResult::Canceled => {
self.current_menu = CurrentMenu::CoopMenu;
}
MenuSelectionResult::Selected(1, _) =>{
state.player2_skin += 2;
}
MenuSelectionResult::Selected(2, _) =>{
state.player_count = PlayerCount::Two;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
}
_ => (),
},
}
Ok(())
}
pub fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
match self.current_menu {
CurrentMenu::CoopMenu => {
self.coop_menu.draw(state, ctx)?;
}
CurrentMenu::PlayerSkin => {
self.skin_menu.draw(state, ctx)?;
}
}
Ok(())
}
}

View File

@ -12,6 +12,7 @@ use crate::shared_game_state::{GameDifficulty, MenuCharacter, SharedGameState};
pub mod pause_menu;
pub mod save_select_menu;
pub mod settings_menu;
pub mod coop_menu;
#[allow(dead_code)]
#[derive(Clone)]
@ -27,6 +28,7 @@ pub enum MenuEntry {
SaveData(MenuSaveInfo),
SaveDataSingle(MenuSaveInfo),
NewSave,
PlayerSkin,
}
impl MenuEntry {
@ -43,6 +45,7 @@ impl MenuEntry {
MenuEntry::SaveData(_) => 32.0,
MenuEntry::SaveDataSingle(_) => 32.0,
MenuEntry::NewSave => 32.0,
MenuEntry::PlayerSkin => 24.0,
}
}
@ -59,6 +62,7 @@ impl MenuEntry {
MenuEntry::SaveData(_) => true,
MenuEntry::SaveDataSingle(_) => true,
MenuEntry::NewSave => true,
MenuEntry::PlayerSkin=> true,
}
}
}
@ -161,6 +165,7 @@ impl Menu {
MenuEntry::SaveData(_) => {}
MenuEntry::SaveDataSingle(_) => {}
MenuEntry::NewSave => {}
MenuEntry::PlayerSkin => {}
}
}
@ -491,6 +496,24 @@ impl Menu {
ctx,
)?;
}
MenuEntry::PlayerSkin => {
state.font.draw_text(
state.t("menus.skin_menu.label").chars(),
self.x as f32 + 20.0,
y,
&state.constants,
&mut state.texture_set,
ctx,
)?;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
batch.add_rect(
self.x as f32 + 88.0,
y - 4.0,
&Rect::new_size(0, (state.player2_skin).saturating_mul(2 * 16), 16, 16),
);
batch.draw(ctx)?;
}
MenuEntry::SaveData(save) | MenuEntry::SaveDataSingle(save) => {
let name = &state.stages[save.current_map as usize].name;
let bar_width = (save.life as f32 / save.max_life as f32 * 39.0) as u16;
@ -621,6 +644,7 @@ impl Menu {
| MenuEntry::DescriptiveOptions(_, _, _, _)
| MenuEntry::SaveData(_)
| MenuEntry::NewSave
| MenuEntry::PlayerSkin
if (self.selected == idx && controller.trigger_ok())
|| state.touch_controls.consume_click_in(entry_bounds) =>
{

View File

@ -3,9 +3,10 @@ use crate::framework::error::GameResult;
use crate::framework::filesystem;
use crate::input::combined_menu_controller::CombinedMenuController;
use crate::menu::MenuEntry;
use crate::menu::coop_menu::PlayerCountMenu;
use crate::menu::{Menu, MenuSelectionResult};
use crate::profile::GameProfile;
use crate::shared_game_state::{GameDifficulty, SharedGameState};
use crate::shared_game_state::{GameDifficulty, PlayerCount, SharedGameState};
#[derive(Clone, Copy)]
pub struct MenuSaveInfo {
@ -22,9 +23,13 @@ impl Default for MenuSaveInfo {
MenuSaveInfo { current_map: 0, max_life: 0, life: 0, weapon_count: 0, weapon_id: [0; 8], difficulty: 0 }
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
#[repr(u8)]
#[allow(unused)]
pub enum CurrentMenu {
SaveMenu,
DifficultyMenu,
PlayerCountMenu,
DeleteConfirm,
LoadConfirm,
}
@ -34,6 +39,7 @@ pub struct SaveSelectMenu {
save_menu: Menu,
save_detailed: Menu,
difficulty_menu: Menu,
coop_menu: PlayerCountMenu,
delete_confirm: Menu,
load_confirm: Menu,
skip_difficulty_menu: bool,
@ -45,6 +51,7 @@ impl SaveSelectMenu {
saves: [MenuSaveInfo::default(); 3],
current_menu: CurrentMenu::SaveMenu,
save_menu: Menu::new(0, 0, 230, 0),
coop_menu: PlayerCountMenu::new(),
save_detailed: Menu::new(0, 0, 230, 0),
difficulty_menu: Menu::new(0, 0, 130, 0),
delete_confirm: Menu::new(0, 0, 75, 0),
@ -56,6 +63,7 @@ impl SaveSelectMenu {
pub fn init(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult {
self.save_menu = Menu::new(0, 0, 230, 0);
self.save_detailed = Menu::new(0, 0, 230, 0);
self.coop_menu.init(state, ctx)?;
self.difficulty_menu = Menu::new(0, 0, 130, 0);
self.delete_confirm = Menu::new(0, 0, 75, 0);
self.load_confirm = Menu::new(0, 0, 75, 0);
@ -88,6 +96,8 @@ impl SaveSelectMenu {
self.difficulty_menu.selected = 2;
//self.coop_menu.init(state, ctx);
self.delete_confirm.push_entry(MenuEntry::Disabled(state.t("menus.save_menu.delete_confirm")));
self.delete_confirm.push_entry(MenuEntry::Active(state.t("common.yes")));
self.delete_confirm.push_entry(MenuEntry::Active(state.t("common.no")));
@ -99,6 +109,7 @@ impl SaveSelectMenu {
self.load_confirm.push_entry(MenuEntry::Active(state.t("common.back")));
self.save_detailed.draw_cursor = false;
if let MenuEntry::SaveData(save) = self.save_menu.entries[0] {
self.save_detailed.push_entry(MenuEntry::SaveDataSingle(save));
}
@ -164,8 +175,7 @@ impl SaveSelectMenu {
self.current_menu = CurrentMenu::LoadConfirm;
self.load_confirm.selected = 0;
} else if self.skip_difficulty_menu {
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
} else {
self.difficulty_menu.selected = 2;
self.current_menu = CurrentMenu::DifficultyMenu;
@ -179,21 +189,30 @@ impl SaveSelectMenu {
}
MenuSelectionResult::Selected(1, _) => {
state.difficulty = GameDifficulty::Easy;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
MenuSelectionResult::Selected(2, _) => {
state.difficulty = GameDifficulty::Normal;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
MenuSelectionResult::Selected(3, _) => {
state.difficulty = GameDifficulty::Hard;
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
_ => (),
},
CurrentMenu::PlayerCountMenu => {
let cm = &mut self.current_menu;
let rm = CurrentMenu::SaveMenu;
self.coop_menu.tick(
&mut || {
*cm = rm;
},
controller,
state,
ctx,
)?;
},
CurrentMenu::DeleteConfirm => match self.delete_confirm.tick(controller, state) {
MenuSelectionResult::Selected(1, _) => {
state.sound_manager.play_sfx(17); // Player Death sfx
@ -212,8 +231,7 @@ impl SaveSelectMenu {
},
CurrentMenu::LoadConfirm => match self.load_confirm.tick(controller, state) {
MenuSelectionResult::Selected(0, _) => {
state.reload_resources(ctx)?;
state.load_or_start_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
MenuSelectionResult::Selected(1, _) => {
self.current_menu = CurrentMenu::DeleteConfirm;
@ -237,6 +255,9 @@ impl SaveSelectMenu {
CurrentMenu::DifficultyMenu => {
self.difficulty_menu.draw(state, ctx)?;
}
CurrentMenu::PlayerCountMenu => {
self.coop_menu.draw(state, ctx)?;
}
CurrentMenu::DeleteConfirm => {
self.save_detailed.draw(state, ctx)?;
self.delete_confirm.draw(state, ctx)?;

View File

@ -258,4 +258,7 @@ impl PlayerSkin for BasicPlayerSkin {
fn apply_gamestate(&mut self, state: &SharedGameState) {
self.skinsheet_offset = state.get_skinsheet_offset();
}
fn set_skinsheet_offset(&mut self, offset: u16) {
self.skinsheet_offset = offset;
}
}

View File

@ -96,6 +96,9 @@ pub trait PlayerSkin: PlayerSkinClone {
/// Applies modifications on the skin based on current state
fn apply_gamestate(&mut self, state: &SharedGameState);
/// Sets the spritesheet's offset
fn set_skinsheet_offset(&mut self, offset: u16);
}
pub trait PlayerSkinClone {

View File

@ -46,7 +46,7 @@ use crate::scene::title_scene::TitleScene;
use crate::scene::Scene;
use crate::scripting::tsc::credit_script::CreditScriptVM;
use crate::scripting::tsc::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
use crate::shared_game_state::{Language, ReplayState, SharedGameState, TileSize};
use crate::shared_game_state::{Language, ReplayState, PlayerCount, SharedGameState, TileSize};
use crate::stage::{BackgroundType, Stage, StageTexturePaths};
use crate::texture_set::SpriteBatch;
use crate::weapon::bullet::BulletManager;
@ -180,10 +180,10 @@ impl GameScene {
pub fn display_map_name(&mut self, ticks: u16) {
self.map_name_counter = ticks;
}
pub fn add_player2(&mut self) {
pub fn add_player2(&mut self, state: &mut SharedGameState) {
self.player2.cond.set_alive(true);
self.player2.cond.set_hidden(self.player1.cond.hidden());
self.player2.skin.set_skinsheet_offset(state.player2_skin);
self.player2.x = self.player1.x;
self.player2.y = self.player1.y;
self.player2.vel_x = self.player1.vel_x;
@ -1598,6 +1598,11 @@ impl Scene for GameScene {
if state.mod_path.is_some() && state.replay_state == ReplayState::Recording {
self.replay.initialize_recording(state);
}
if state.player_count == PlayerCount::Two {
self.add_player2(state);
} else {
self.drop_player2();
}
if state.mod_path.is_some() && state.replay_state == ReplayState::Playback {
self.replay.initialize_playback(state, ctx)?;

View File

@ -9,6 +9,7 @@ use crate::input::combined_menu_controller::CombinedMenuController;
use crate::input::touch_controls::TouchControlType;
use crate::map::Map;
use crate::menu::save_select_menu::SaveSelectMenu;
use crate::menu::coop_menu::PlayerCountMenu;
use crate::menu::settings_menu::SettingsMenu;
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
use crate::scene::jukebox_scene::JukeboxScene;
@ -25,6 +26,7 @@ enum CurrentMenu {
SaveSelectMenu,
ChallengesMenu,
ChallengeConfirmMenu,
PlayerCountMenu,
}
pub struct TitleScene {
@ -35,6 +37,7 @@ pub struct TitleScene {
save_select_menu: SaveSelectMenu,
challenges_menu: Menu,
confirm_menu: Menu,
coop_menu: PlayerCountMenu,
settings_menu: SettingsMenu,
background: Background,
frame: Frame,
@ -75,6 +78,7 @@ impl TitleScene {
save_select_menu: SaveSelectMenu::new(),
challenges_menu: Menu::new(0, 0, 150, 0),
confirm_menu: Menu::new(0, 0, 150, 0),
coop_menu: PlayerCountMenu::new(),
settings_menu,
background: Background::new(),
frame: Frame::new(),
@ -171,6 +175,8 @@ impl Scene for TitleScene {
self.save_select_menu.init(state, ctx)?;
self.coop_menu.init(state, ctx)?;
let mut selected: usize = 0;
let mut mutate_selection = true;
@ -319,12 +325,14 @@ impl Scene for TitleScene {
self.nikumaru_rec.load_counter(state, ctx)?;
self.current_menu = CurrentMenu::ChallengeConfirmMenu;
}
state.reload_graphics();
}
}
MenuSelectionResult::Canceled => {
state.mod_path = None;
self.nikumaru_rec.load_counter(state, ctx)?;
self.current_menu = CurrentMenu::MainMenu;
state.reload_graphics();
}
_ => (),
}
@ -333,8 +341,7 @@ impl Scene for TitleScene {
MenuSelectionResult::Selected(1, _) => {
state.difficulty = GameDifficulty::Normal;
state.replay_state = ReplayState::Recording;
state.reload_resources(ctx)?;
state.start_new_game(ctx)?;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
MenuSelectionResult::Selected(2, _) => {
state.difficulty = GameDifficulty::Normal;
@ -350,6 +357,18 @@ impl Scene for TitleScene {
self.current_menu = CurrentMenu::ChallengesMenu;
}
_ => (),
}
CurrentMenu::PlayerCountMenu => {
let cm = &mut self.current_menu;
let rm = CurrentMenu::ChallengeConfirmMenu;
self.coop_menu.tick(
&mut || {
*cm = rm;
},
&mut self.controller,
state,
ctx,
)?;
},
}
@ -381,6 +400,7 @@ impl Scene for TitleScene {
CurrentMenu::ChallengeConfirmMenu | CurrentMenu::SaveSelectMenu => (state.t("menus.main_menu.start")),
CurrentMenu::OptionMenu => (state.t("menus.main_menu.options")),
CurrentMenu::MainMenu => unreachable!(),
CurrentMenu::PlayerCountMenu => (state.t("menus.main_menu.start")),
};
state.font.draw_colored_text_with_shadow_scaled(
window_title.chars(),
@ -410,6 +430,7 @@ impl Scene for TitleScene {
CurrentMenu::ChallengeConfirmMenu => self.confirm_menu.draw(state, ctx)?,
CurrentMenu::OptionMenu => self.settings_menu.draw(state, ctx)?,
CurrentMenu::SaveSelectMenu => self.save_select_menu.draw(state, ctx)?,
CurrentMenu::PlayerCountMenu => self.coop_menu.draw(state, ctx)?,
}
Ok(())

View File

@ -77,6 +77,12 @@ pub enum GameDifficulty {
Hard = 4,
}
#[derive(PartialEq, Eq, Copy, Clone, num_derive::FromPrimitive)]
pub enum PlayerCount {
One,
Two,
}
impl GameDifficulty {
pub fn from_primitive(val: u8) -> GameDifficulty {
return num_traits::FromPrimitive::from_u8(val).unwrap_or(GameDifficulty::Normal);
@ -270,6 +276,8 @@ pub struct SharedGameState {
pub settings: Settings,
pub save_slot: usize,
pub difficulty: GameDifficulty,
pub player_count: PlayerCount,
pub player2_skin: u16,
pub replay_state: ReplayState,
pub mod_requirements: ModRequirements,
pub tutorial_counter: u16,
@ -397,6 +405,8 @@ impl SharedGameState {
settings,
save_slot: 1,
difficulty: GameDifficulty::Normal,
player_count: PlayerCount::One,
player2_skin: 0,
replay_state: ReplayState::None,
mod_requirements,
tutorial_counter: 0,