Loading is borked, but tutorial worked...

main
Elijah C. Voigt 1 year ago
parent 2a33dd7464
commit 2295de0043

@ -83,21 +83,34 @@ But first things first! How do you play the dang game?
""", """,
] ]
objective = [ objective = [
"The Goal of Martian Chess is to have more points than your opponent when the game ends.", """
"You get points by capturing your opponent's pieces.", The Goal of Martian Chess is to have more points than your opponent when the game ends.
"The game ends when one player has no more pieces in their zone.", """,
"""
You get points by capturing your opponent's pieces.
""",
"""
The game ends when one player has no more pieces in their zone.
""",
] ]
ownership = [ ownership = [
""" """
This here line is called the canal. And blow me down if she aint a beaut! See herein lies the kicker of Martian warfare: You control any and only the pieces on your side of the canal. When you move a piece across the canal, your opponent assumes control over it. This here line down the middle is called the canal. And blow me down if she aint a beaut! See herein lies the kicker of Martian warfare: You control any and only the pieces on your side of the canal. When you move a piece across the canal, your opponent assumes control over it.
""",
"""
Keep playing and try to score some points!
""", """,
"Keep playing and try to score some points!",
] ]
promotions = [ promotions = [
""" """
Oh and one last thing: real nerds occasionally employ the field promotions strategy. Here's how it works: If you control no drones, you may combine two pawns to make a drone. Similarly, if you control no Queens, you may combine two drones to make a queen. Real nerds occasionally employ the field promotions strategy. Here's how it works: If you control no drones, you may combine two pawns to make a drone. Similarly, if you control no Queens, you may combine a drone and a pawn to make a queen.
""", """,
] ]
undo = [
"""
One last thing: no take-backsies. You cannot 'undo' a piece's last move if it crossed the canal.
"""
]
outro = [ outro = [
""" """
Ok I gotta go now, but You now know enough to prevent human extinction. Do you want to finish this practice round? Ok I gotta go now, but You now know enough to prevent human extinction. Do you want to finish this practice round?
@ -105,12 +118,44 @@ Ok I gotta go now, but You now know enough to prevent human extinction. Do you w
] ]
[tutorial.pieces] [tutorial.pieces]
prompt = ["Try picking up a piece"] prompt = [
pawn = ["Pawn. The Pawn is worth 1 point, and moves 1 space diagonally. This thing ain't worth your time. Put it down."] """
drone = ["Drone. The Drone is worth 2 points, and moves 1 or 2 spaces horizontally or vertically. Neat. Back on the board."] Try picking up a piece
queen = ["Queen. The Queen is worth 3 Points, and moves any distance in a straight line. Woah, watch where you point that thing. Best put it back down."] """
jumping = ["Note that jumping is not allowed. Martians banned any and all jumping in their society long ago."] ]
end = ["Ok, now move some pieces somewheres!"] pawn = [
"""
Pawn.
A captured Pawn is worth 1 point, and moves 1 space diagonally. This thing ain't worth your time. Put it down.
""",
]
drone = [
"""
Drone.
A captured Drone is worth 2 points, and moves 1 or 2 spaces horizontally or vertically. Neat. Back on the board.
"""
]
queen = [
"""
Queen.
A captured Queen is worth 3 Points, and moves any distance in a straight line. Woah, watch where you point that thing. Best put it back down.
"""
]
jumping = [
"""
Note that jumping over pieces is not allowed.
Martians banned any and all jumping in their society long ago.
"""
]
end = [
"""
Ok, now move some pieces somewheres!
"""
]
[resolution] [resolution]

@ -22,9 +22,8 @@ impl Plugin for Display3dPlugin {
.add_systems( .add_systems(
OnExit(GameState::Loading), OnExit(GameState::Loading),
( (
fix_skybox.before(initialize), fix_skybox,
initialize, initialize.after(fix_skybox),
update_tweaks.run_if(resource_exists::<tweak::GameTweaks>),
), ),
) )
// Systems related to color and camera // Systems related to color and camera
@ -84,6 +83,7 @@ impl Plugin for Display3dPlugin {
select select
.run_if(in_state(GameState::Play)) .run_if(in_state(GameState::Play))
.run_if(in_state(DisplayState::Display3d)) .run_if(in_state(DisplayState::Display3d))
.run_if(not(in_state(MenuState::On)))
.run_if(just_pressed(MouseButton::Left)), .run_if(just_pressed(MouseButton::Left)),
pick_up.run_if(any_component_added::<game::Selected>()), pick_up.run_if(any_component_added::<game::Selected>()),
put_down.run_if(any_component_removed::<game::Selected>()), put_down.run_if(any_component_removed::<game::Selected>()),
@ -221,7 +221,7 @@ fn load_assets(
/// Initialize the board and pieces /// Initialize the board and pieces
fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<AssetsMap>) { fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<AssetsMap>) {
info!("Initializing root"); debug!("Initializing root");
commands commands
.spawn(( .spawn((
SpatialBundle { SpatialBundle {
@ -232,7 +232,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
DisplayState::Display3d, DisplayState::Display3d,
)) ))
.with_children(|parent| { .with_children(|parent| {
info!("Intializing 3D Board!"); debug!("Intializing 3D Board!");
parent parent
.spawn(( .spawn((
Display3d, Display3d,
@ -330,7 +330,7 @@ fn hydrate_camera(
.iter() .iter()
.filter(|(name, _)| name.as_str() == "GameCam") .filter(|(name, _)| name.as_str() == "GameCam")
.for_each(|(_, entity)| { .for_each(|(_, entity)| {
info!("Initialize 3d camera"); debug!("Initialize 3d camera");
let skybox_handle = tweak let skybox_handle = tweak
.get_handle::<Image>("display3d_models_skybox_file") .get_handle::<Image>("display3d_models_skybox_file")
.unwrap(); .unwrap();
@ -339,7 +339,7 @@ fn hydrate_camera(
.get::<f32>("display3d_environment_map_light_intensity") .get::<f32>("display3d_environment_map_light_intensity")
.unwrap(); .unwrap();
info!("Hydrating camera {:?}", entity); debug!("Hydrating camera {:?}", entity);
// Populate the components for the camera // Populate the components for the camera
commands.entity(entity).insert(( commands.entity(entity).insert((
DisplayState::Display3d, DisplayState::Display3d,
@ -446,7 +446,7 @@ fn fix_skybox(
.unwrap(); .unwrap();
let image = images.get_mut(handle).unwrap(); let image = images.get_mut(handle).unwrap();
info!("Loaded skybox image"); debug!("Loaded skybox image");
// NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture, // NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
// so they appear as one texture. The following code reconfigures the texture as necessary. // so they appear as one texture. The following code reconfigures the texture as necessary.
if image.texture_descriptor.array_layer_count() == 1 { if image.texture_descriptor.array_layer_count() == 1 {
@ -470,7 +470,7 @@ fn set_board_model(
.get(tweaks_file.handle.clone()) .get(tweaks_file.handle.clone())
.expect("Load tweakfile"); .expect("Load tweakfile");
boards.iter_mut().for_each(|mut handle| { boards.iter_mut().for_each(|mut handle| {
info!("Setting board model"); debug!("Setting board model");
let assets_handle = tweak let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file") .get_handle::<Gltf>("display3d_models_assets_file")
.unwrap(); .unwrap();
@ -503,7 +503,7 @@ fn set_title_model(
titles titles
.iter_mut() .iter_mut()
.for_each(|(mut handle, mut transform, mut visibility)| { .for_each(|(mut handle, mut transform, mut visibility)| {
info!("Setting title model"); debug!("Setting title model");
let assets_handle = tweak let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file") .get_handle::<Gltf>("display3d_models_assets_file")
.unwrap(); .unwrap();
@ -546,7 +546,7 @@ fn board_translation(&BoardIndex { x, y }: &BoardIndex) -> Vec3 {
} }
fn capture_translation(side: &Side, num: usize) -> Vec3 { fn capture_translation(side: &Side, num: usize) -> Vec3 {
info!("Side: {:?} Num: {:?}", side, num); debug!("Side: {:?} Num: {:?}", side, num);
let x = 5.0 - ((num % 4) as f32 * 1.3); let x = 5.0 - ((num % 4) as f32 * 1.3);
let y = -1.3; let y = -1.3;
let z = 4.0 + ((num / 4) as f32 * 1.3); let z = 4.0 + ((num / 4) as f32 * 1.3);
@ -634,7 +634,7 @@ fn update_pieces(
// Set position of piece // Set position of piece
let new_translation = board_translation(board_index); let new_translation = board_translation(board_index);
if transform.translation != new_translation { if transform.translation != new_translation {
info!("Updating piece transform"); debug!("Updating piece transform");
transform.translation = new_translation; transform.translation = new_translation;
} }
@ -644,7 +644,7 @@ fn update_pieces(
.count(); .count();
if animating > 0 { if animating > 0 {
info!("Piece {:?} is animating. Skipping...", entity); debug!("Piece {:?} is animating. Skipping...", entity);
} else { } else {
debug!("Checking piece object scene for {:?}", entity); debug!("Checking piece object scene for {:?}", entity);
@ -679,7 +679,6 @@ fn select(
selected: Query<Entity, With<game::Selected>>, selected: Query<Entity, With<game::Selected>>,
state: Res<State<game::TurnState>>, state: Res<State<game::TurnState>>,
) { ) {
// info!("Board index selected: {:?}", board_index);
match *piece { match *piece {
PiecePointer(Some(e)) => { PiecePointer(Some(e)) => {
query.get(e).iter().for_each(|(board_index, side)| { query.get(e).iter().for_each(|(board_index, side)| {
@ -799,7 +798,7 @@ fn set_valid_move_model(
.get_handle::<Gltf>("display3d_models_assets_file") .get_handle::<Gltf>("display3d_models_assets_file")
.unwrap(); .unwrap();
if let Some(gltf) = gltfs.get(assets_handle) { if let Some(gltf) = gltfs.get(assets_handle) {
info!("Setting valid move model"); debug!("Setting valid move model");
events.iter_mut().for_each(|(mut handle, mut visibility)| { events.iter_mut().for_each(|(mut handle, mut visibility)| {
*handle = gltf *handle = gltf
@ -834,19 +833,19 @@ fn pick_up(
.get(tweaks_file.handle.clone()) .get(tweaks_file.handle.clone())
.expect("Load tweakfile"); .expect("Load tweakfile");
events.iter_mut().for_each(|(entity, piece)| { events.iter_mut().for_each(|(entity, piece)| {
info!("Picking up piece"); debug!("Picking up piece");
let assets_handle = tweak let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file") .get_handle::<Gltf>("display3d_models_assets_file")
.unwrap(); .unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
info!("Pickup animation for {:?}", entity); debug!("Pickup animation for {:?}", entity);
children.iter_descendants(entity).for_each(|child| { children.iter_descendants(entity).for_each(|child| {
info!(" Child: {:?}", child); debug!(" Child: {:?}", child);
if let Ok((name, mut player)) = players.get_mut(child) { if let Ok((name, mut player)) = players.get_mut(child) {
let pickup_animation = let pickup_animation =
format!("display3d_models_animations_pick_up_{}", name.as_str(),); format!("display3d_models_animations_pick_up_{}", name.as_str(),);
info!( debug!(
"Picking up {:?} ({:?}) {:?} {:?}", "Picking up {:?} ({:?}) {:?} {:?}",
name, entity, piece, pickup_animation name, entity, piece, pickup_animation
); );
@ -905,7 +904,7 @@ fn put_down(
.expect("Load tweakfile"); .expect("Load tweakfile");
events.read().for_each(|entity| { events.read().for_each(|entity| {
if let Ok(_) = query.get_mut(entity) { if let Ok(_) = query.get_mut(entity) {
info!("Putting down piece"); debug!("Putting down piece");
let assets_handle = tweak let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file") .get_handle::<Gltf>("display3d_models_assets_file")
@ -913,7 +912,7 @@ fn put_down(
let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
children.iter_descendants(entity).for_each(|child| { children.iter_descendants(entity).for_each(|child| {
if let Ok((name, mut player)) = players.get_mut(child) { if let Ok((name, mut player)) = players.get_mut(child) {
info!("Putting down {:?}", entity); debug!("Putting down {:?}", entity);
let putdown_animation = let putdown_animation =
format!("display3d_models_animations_put_down_{}", name.as_str()); format!("display3d_models_animations_put_down_{}", name.as_str());
let putdown_handle = gltf let putdown_handle = gltf
@ -927,7 +926,7 @@ fn put_down(
.expect("PutDown Animation"); .expect("PutDown Animation");
if let Some(putdown_clip) = clips.get(putdown_handle) { if let Some(putdown_clip) = clips.get(putdown_handle) {
if putdown_clip.compatible_with(name) { if putdown_clip.compatible_with(name) {
info!("Compatible with put-down clip!"); debug!("Compatible with put-down clip!");
player player
.start_with_transition( .start_with_transition(
putdown_handle.clone(), putdown_handle.clone(),
@ -935,20 +934,20 @@ fn put_down(
) )
.set_repeat(RepeatAnimation::Never); .set_repeat(RepeatAnimation::Never);
} else { } else {
info!( debug!(
"Clip {:?}({:?}) not compatible with {:?}", "Clip {:?}({:?}) not compatible with {:?}",
putdown_animation, putdown_clip, name putdown_animation, putdown_clip, name
); );
} }
} else { } else {
info!("Clip not found"); debug!("Clip not found");
} }
} else { } else {
info!("Player not found"); debug!("Player not found");
} }
}) })
} else { } else {
info!("Piece+Side not found for entity"); debug!("Piece+Side not found for entity");
} }
}) })
} }
@ -957,7 +956,7 @@ fn set_tile_hitbox(
mut events: Query<(&mut Transform, &BoardIndex), (With<Display3d>, Added<game::Tile>)>, mut events: Query<(&mut Transform, &BoardIndex), (With<Display3d>, Added<game::Tile>)>,
) { ) {
events.iter_mut().for_each(|(mut transform, index)| { events.iter_mut().for_each(|(mut transform, index)| {
info!("Setting tile hitbox"); debug!("Setting tile hitbox");
*transform = Transform::from_translation(board_translation(index)); *transform = Transform::from_translation(board_translation(index));
}); });
@ -965,7 +964,7 @@ fn set_tile_hitbox(
fn opening_animation(mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>) { fn opening_animation(mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>) {
players.iter_mut().for_each(|mut player| { players.iter_mut().for_each(|mut player| {
info!("Playing intro camera animation"); debug!("Playing intro camera animation");
player.resume() player.resume()
}); });
} }
@ -1009,7 +1008,7 @@ fn switch_sides(
.unwrap(); .unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
players.iter_mut().for_each(|mut player| { players.iter_mut().for_each(|mut player| {
info!("Switching sides"); debug!("Switching sides");
let animation = match state.get() { let animation = match state.get() {
game::TurnState(game::Side::A) => gltf.named_animations.get( game::TurnState(game::Side::A) => gltf.named_animations.get(
@ -1072,7 +1071,7 @@ fn setup_dissolve_materials(
.filter(|(child, _, _)| query.iter_many(parents.iter_ancestors(*child)).count() > 0) .filter(|(child, _, _)| query.iter_many(parents.iter_ancestors(*child)).count() > 0)
// Handle this entity (mesh) // Handle this entity (mesh)
.for_each(|(child, std_handle, name)| { .for_each(|(child, std_handle, name)| {
info!("Setting up dissolve material for {:?} {:?}", name, child); debug!("Setting up dissolve material for {:?} {:?}", name, child);
// Get dissolvable data for percentage start // Get dissolvable data for percentage start
let dissolvable = query let dissolvable = query
@ -1138,7 +1137,7 @@ fn capture_piece(
// Wait for fade-out animation // Wait for fade-out animation
// If all pieces are done dissolving // If all pieces are done dissolving
if dissolving.is_empty() { if dissolving.is_empty() {
info!("Nothing dissolving, moving on to next step!"); debug!("Nothing dissolving, moving on to next step!");
// Move to next state now that animation is done // Move to next state now that animation is done
*state = s.next(); *state = s.next();
// This takes effect after updating all children // This takes effect after updating all children
@ -1150,7 +1149,7 @@ fn capture_piece(
.expect("Visibility and Transform of captured piece"); .expect("Visibility and Transform of captured piece");
// HACK: This is dirty. Why side, but score.captures(!side)? // HACK: This is dirty. Why side, but score.captures(!side)?
info!( debug!(
"Capture translation: ({:?}, {:?}) {:?}", "Capture translation: ({:?}, {:?}) {:?}",
side, side,
score.captures(!*side).saturating_sub(1), score.captures(!*side).saturating_sub(1),
@ -1168,7 +1167,7 @@ fn capture_piece(
game::CaptureFlow::FadeIn(_entity) => { game::CaptureFlow::FadeIn(_entity) => {
// If we have completed the dissolve-in animation // If we have completed the dissolve-in animation
if dissolving.is_empty() { if dissolving.is_empty() {
info!("Nothing dissolving, moving on to next step!"); debug!("Nothing dissolving, moving on to next step!");
// Move to next state now that animation is done // Move to next state now that animation is done
*state = s.next(); *state = s.next();
@ -1215,14 +1214,14 @@ fn monitor_animations(
// Remove Animating component from players that are done // Remove Animating component from players that are done
active.iter().for_each(|(entity, player)| { active.iter().for_each(|(entity, player)| {
if player.is_finished() { if player.is_finished() {
info!("Entity {:?} is done, removing animating marker", entity); debug!("Entity {:?} is done, removing animating marker", entity);
commands.entity(entity).remove::<Animating>(); commands.entity(entity).remove::<Animating>();
} }
}); });
// Set inactive entities to active // Set inactive entities to active
inactive.iter_mut().for_each(|(entity, mut player)| { inactive.iter_mut().for_each(|(entity, mut player)| {
if !player.is_finished() && *player.animation_clip() != Handle::<AnimationClip>::default() { if !player.is_finished() && *player.animation_clip() != Handle::<AnimationClip>::default() {
info!( debug!(
"Entity {:?} is playing {:?}, adding animating marker", "Entity {:?} is playing {:?}, adding animating marker",
entity, entity,
player.animation_clip() player.animation_clip()
@ -1328,7 +1327,7 @@ fn dissolve_animation(
// If animation is done, remove dissolving component // If animation is done, remove dissolving component
if percentage <= 0.0 || percentage >= 1.0 { if percentage <= 0.0 || percentage >= 1.0 {
info!( debug!(
"Removing dissolving from {:?} with percentage {:?}", "Removing dissolving from {:?} with percentage {:?}",
entity, percentage entity, percentage
); );
@ -1485,3 +1484,4 @@ fn animate_title_light_out(
}) })
}); });
} }

@ -158,7 +158,7 @@ pub(crate) struct ValidMove;
pub(crate) struct Captured; pub(crate) struct Captured;
#[derive(Debug, Component)] #[derive(Debug, Component)]
pub(crate) struct Merged; pub(crate) struct Promoted;
// manually for the type. // manually for the type.
impl std::fmt::Display for Piece { impl std::fmt::Display for Piece {
@ -300,7 +300,7 @@ pub(crate) enum MoveType {
#[default] #[default]
Invalid, Invalid,
Capture, Capture,
Merge(Piece), Promotion(Piece),
} }
#[derive(Debug, Component, PartialEq, Clone, Copy, Eq, Hash, Default)] #[derive(Debug, Component, PartialEq, Clone, Copy, Eq, Hash, Default)]
@ -372,10 +372,14 @@ impl Board {
fn new() -> Board { fn new() -> Board {
Board::from_ascii( Board::from_ascii(
r#".....dqq // r#".....dqq
dpp..pdq // dpp..pdq
qdp..ppd // qdp..ppd
qqd....."#, // qqd....."#,
r#"........
...p....
..p.....
........"#,
) )
} }
@ -439,11 +443,10 @@ impl Board {
MoveType::Invalid => { MoveType::Invalid => {
Err(GameError::InvalidMove) Err(GameError::InvalidMove)
}, },
MoveType::Valid | MoveType::Capture | MoveType::Merge(..) => { MoveType::Valid | MoveType::Capture | MoveType::Promotion(..) => {
// The current epoch is the last epoch + 1 // The current epoch is the last epoch + 1
let epoch = self.current_epoch(); let epoch = self.current_epoch();
// Local moves vec we can return // Local moves vec we can return
let mut moves = vec![]; let mut moves = vec![];
@ -465,7 +468,20 @@ impl Board {
move_type: move_type.clone(), move_type: move_type.clone(),
}); });
self.inner[to.y][to.x] = Some(*from_piece); self.inner[to.y][to.x] = match move_type {
MoveType::Promotion(_) => {
match (self.at(from), self.at(to)) {
(Some(Piece::Pawn), Some(Piece::Pawn)) => {
Some(Piece::Drone)
},
(Some(Piece::Pawn), Some(Piece::Drone)) | (Some(Piece::Drone), Some(Piece::Pawn)) => {
Some(Piece::Queen)
},
_ => panic!("Merges can only happen between pawn+pawn or pawn+drone!")
}
},
_ => Some(*from_piece)
};
self.inner[from.y][from.x] = None; self.inner[from.y][from.x] = None;
self.moves.extend(moves.clone()); self.moves.extend(moves.clone());
@ -554,10 +570,10 @@ impl Board {
Some(to_piece) => { Some(to_piece) => {
match (piece, to_piece) { match (piece, to_piece) {
(Piece::Pawn, Piece::Pawn) => { (Piece::Pawn, Piece::Pawn) => {
(!side_has_drone).then_some(MoveType::Merge(Piece::Drone)) (!side_has_drone).then_some(MoveType::Promotion(Piece::Drone))
} }
(Piece::Drone, Piece::Pawn) | (Piece::Pawn, Piece::Drone) => { (Piece::Drone, Piece::Pawn) | (Piece::Pawn, Piece::Drone) => {
(!side_has_queen).then_some(MoveType::Merge(Piece::Queen)) (!side_has_queen).then_some(MoveType::Promotion(Piece::Queen))
}, },
_ => { _ => {
Some(MoveType::Invalid) Some(MoveType::Invalid)
@ -605,7 +621,7 @@ impl Board {
let result = self.move_type(current_board_index, *move_index); let result = self.move_type(current_board_index, *move_index);
match result { match result {
MoveType::Invalid => None, MoveType::Invalid => None,
MoveType::Capture | MoveType::Merge(..) | MoveType::Valid => { MoveType::Capture | MoveType::Promotion(..) | MoveType::Valid => {
Some(*move_index) Some(*move_index)
}, },
} }
@ -764,7 +780,7 @@ mod test {
assert_eq!(expected, given, "Pawn can merge to make a drone"); assert_eq!(expected, given, "Pawn can merge to make a drone");
let move_type = board.move_type((0, 0).into(), (1, 1).into()); let move_type = board.move_type((0, 0).into(), (1, 1).into());
assert_eq!(MoveType::Merge(Piece::Drone), move_type); assert_eq!(MoveType::Promotion(Piece::Drone), move_type);
} }
// Pawn cannot merge with queen // Pawn cannot merge with queen
@ -909,10 +925,10 @@ mod test {
assert_eq!(MoveType::Capture, capture_move); assert_eq!(MoveType::Capture, capture_move);
let merge_move = board.move_type((3, 1).into(), (2, 1).into()); let merge_move = board.move_type((3, 1).into(), (2, 1).into());
assert_eq!(MoveType::Merge(Piece::Queen), merge_move); assert_eq!(MoveType::Promotion(Piece::Queen), merge_move);
let long_merge_move = board.move_type((3, 1).into(), (3, 3).into()); let long_merge_move = board.move_type((3, 1).into(), (3, 3).into());
assert_eq!(MoveType::Merge(Piece::Queen), long_merge_move); assert_eq!(MoveType::Promotion(Piece::Queen), long_merge_move);
let jump_move = board.move_type((3, 1).into(), (1, 1).into()); let jump_move = board.move_type((3, 1).into(), (1, 1).into());
assert_eq!(MoveType::Invalid, jump_move); assert_eq!(MoveType::Invalid, jump_move);
@ -936,7 +952,7 @@ mod test {
// Pawn + Pawn on same side = Promotion // Pawn + Pawn on same side = Promotion
let merge_move = board.move_type((3, 1).into(), (2, 2).into()); let merge_move = board.move_type((3, 1).into(), (2, 2).into());
assert_eq!(MoveType::Merge(Piece::Drone), merge_move); assert_eq!(MoveType::Promotion(Piece::Drone), merge_move);
// Pawn + Pawn on other side = Capture // Pawn + Pawn on other side = Capture
let capture_move = board.move_type((3, 1).into(), (4, 2).into()); let capture_move = board.move_type((3, 1).into(), (4, 2).into());
@ -1023,7 +1039,7 @@ pub(crate) fn update_board(
} }
if *from != *to_idx { if *from != *to_idx {
match move_type { match move_type {
MoveType::Merge(piece) => { MoveType::Promotion(piece) => {
error!("Hey Eli, this is where you are merging pieces"); error!("Hey Eli, this is where you are merging pieces");
// Here we insert a new Piece type based on the merge // Here we insert a new Piece type based on the merge
// Other system should automatically update the model // Other system should automatically update the model
@ -1049,11 +1065,11 @@ pub(crate) fn update_board(
.remove::<BoardIndex>() .remove::<BoardIndex>()
.insert(Captured); .insert(Captured);
}, },
MoveType::Merge(..) => { MoveType::Promotion(..) => {
commands commands
.entity(entity) .entity(entity)
.remove::<BoardIndex>() .remove::<BoardIndex>()
.insert(Merged); .insert(Promoted);
}, },
_ => { _ => {
panic!("How did you do this!?"); panic!("How did you do this!?");

@ -70,9 +70,10 @@ fn loading(
.all(|id| server.is_loaded_with_dependencies(id)); .all(|id| server.is_loaded_with_dependencies(id));
let f = (!fonts.is_empty()) && fonts.ids().all(|id| server.is_loaded_with_dependencies(id)); let f = (!fonts.is_empty()) && fonts.ids().all(|id| server.is_loaded_with_dependencies(id));
debug!("s {} g {} t {} f {}", s, g, t, f); info!("Loading :: images: {} :: gltfs: {} :: tweaks: {} :: fonts: {}", s, g, t, f);
if t { if s && g && t && f {
info!("Starting game intro");
next_state.set(GameState::Intro) next_state.set(GameState::Intro)
} }
} }

@ -17,7 +17,7 @@ impl Plugin for MenuPlugin {
manage_state_entities::<MenuState>().run_if(state_changed::<MenuState>), manage_state_entities::<MenuState>().run_if(state_changed::<MenuState>),
) )
.add_systems( .add_systems(
Update, PostUpdate,
( (
handle_button_press::<GameState>, handle_button_press::<GameState>,
handle_button_press::<MenuState>, handle_button_press::<MenuState>,
@ -340,5 +340,8 @@ fn handle_button_press<S: States + Clone + Component>(
.filter_map(|(interaction, button_action)| { .filter_map(|(interaction, button_action)| {
(*interaction == Interaction::Pressed).then_some(button_action) (*interaction == Interaction::Pressed).then_some(button_action)
}) })
.for_each(|ButtonAction(ba)| next_state.set(ba.clone())); .for_each(|ButtonAction(ba)| {
info!("Button press: {:?} => {:?}", next_state, ba);
next_state.set(ba.clone())
});
} }

@ -17,31 +17,29 @@ impl Plugin for TutorialPlugin {
( (
// Evaluate if a piece is selected // Evaluate if a piece is selected
step.run_if( step.run_if(
state_exists::<TutorialState>.and_then( // A piece changes sides
// A piece changes sides any_component_changed::<game::Side>()
any_component_changed::<game::Side>() // When a piece is selected, we
// When a piece is selected, we .or_else(any_component_added::<game::Selected>())
.or_else(any_component_added::<game::Selected>()) // A piece is de-selected
// A piece is de-selected .or_else(any_component_removed::<game::Selected>())
.or_else(any_component_removed::<game::Selected>()) // TEMP: The user hits 'enter'
// TEMP: The user hits 'enter' .or_else(
.or_else( just_pressed(KeyCode::Enter)
just_pressed(KeyCode::Enter) .or_else(just_pressed(MouseButton::Left)),
.or_else(just_pressed(MouseButton::Left)), ),
),
),
), ),
), ),
) )
// Manage visible/hidden states // Manage visible/hidden states
.add_systems( .add_systems(
Update, Update,
manage_state_entities::<TutorialState>().run_if(state_changed::<TutorialState>), (
) manage_state_entities::<TutorialState>(),
.add_systems( activate_tutorial_step,
Update, )
activate_tutorial_step .run_if(not(in_state(GameState::Loading)))
.run_if(state_exists::<TutorialState>.and_then(state_changed::<TutorialState>)), .run_if(state_changed::<TutorialState>),
); );
} }
} }
@ -60,7 +58,7 @@ pub(crate) enum TutorialState {
PieceJump, PieceJump,
PieceEnd, PieceEnd,
Ownership, Ownership,
_Promotions, Promotions,
Outro, Outro,
} }
@ -106,7 +104,7 @@ fn initialize_tutorial(
.expect("Tutorial ownership"), .expect("Tutorial ownership"),
), ),
( (
TutorialState::_Promotions, TutorialState::Promotions,
tweak tweak
.get::<Vec<String>>("tutorial_promotions") .get::<Vec<String>>("tutorial_promotions")
.expect("Tutorial promotions"), .expect("Tutorial promotions"),
@ -201,7 +199,7 @@ fn initialize_tutorial(
.map(|line| TextSection { .map(|line| TextSection {
value: line.clone(), value: line.clone(),
style: TextStyle { style: TextStyle {
font_size: 8.0, font_size: 12.0,
color: Color::hex(&text_visible_hex).unwrap(), color: Color::hex(&text_visible_hex).unwrap(),
font: ui_font.handle.clone(), font: ui_font.handle.clone(),
}, },
@ -248,7 +246,7 @@ fn initialize_tutorial(
value: "R e s t a r t".into(), value: "R e s t a r t".into(),
style: TextStyle { style: TextStyle {
color: Color::WHITE, color: Color::WHITE,
font_size: 8.0, font_size: 10.0,
font: font_handle.clone(), font: font_handle.clone(),
}, },
}], }],
@ -287,7 +285,7 @@ fn initialize_tutorial(
value: "C o n t i n u e".into(), value: "C o n t i n u e".into(),
style: TextStyle { style: TextStyle {
color: Color::WHITE, color: Color::WHITE,
font_size: 12.0, font_size: 8.0,
font: font_handle.clone(), font: font_handle.clone(),
}, },
}], }],
@ -341,6 +339,7 @@ fn step(
| TutorialState::PieceEnd | TutorialState::PieceEnd
| TutorialState::PieceJump | TutorialState::PieceJump
| TutorialState::Empty | TutorialState::Empty
| TutorialState::Promotions
| TutorialState::Ownership => { | TutorialState::Ownership => {
// PERF: Doing all of this work up front results in unnecessary work // PERF: Doing all of this work up front results in unnecessary work
let piece_selected = !pieces.is_empty(); let piece_selected = !pieces.is_empty();
@ -351,6 +350,7 @@ fn step(
let ownership_done = seen.0.contains(&TutorialState::Ownership); let ownership_done = seen.0.contains(&TutorialState::Ownership);
let ownership_check = !ownership_done && transitions.iter().count() > 0; let ownership_check = !ownership_done && transitions.iter().count() > 0;
let jump_done = seen.0.contains(&TutorialState::PieceJump); let jump_done = seen.0.contains(&TutorialState::PieceJump);
let promotions_done = seen.0.contains(&TutorialState::Promotions);
let queen_selected = pieces.iter().filter(|&p| *p == game::Piece::Queen).count() > 0; let queen_selected = pieces.iter().filter(|&p| *p == game::Piece::Queen).count() > 0;
let queen_seen = seen.0.contains(&TutorialState::PieceQueen); let queen_seen = seen.0.contains(&TutorialState::PieceQueen);
let drone_selected = pieces.iter().filter(|&p| *p == game::Piece::Drone).count() > 0; let drone_selected = pieces.iter().filter(|&p| *p == game::Piece::Drone).count() > 0;
@ -375,7 +375,7 @@ fn step(
// There are no pieces selected // There are no pieces selected
} else { } else {
// All move, jump, and ownership tutorials done, say goodbye // All move, jump, and ownership tutorials done, say goodbye
if all_moves_done && jump_done && ownership_done { if all_moves_done && jump_done && ownership_done && promotions_done {
TutorialState::Outro TutorialState::Outro
} }
// A piece moves sides, so talk about ownership // A piece moves sides, so talk about ownership
@ -385,11 +385,17 @@ fn step(
// We have not touched on jumping yet // We have not touched on jumping yet
else if all_moves_done && !jump_done { else if all_moves_done && !jump_done {
TutorialState::PieceJump TutorialState::PieceJump
}
// We have not touched on field promotions yet
else if all_moves_done && !promotions_done {
TutorialState::Promotions
}
// All pieces tutorialized, so prompt user to move pieces for more tutorial // All pieces tutorialized, so prompt user to move pieces for more tutorial
} else if all_moves_done { else if all_moves_done {
TutorialState::PieceEnd TutorialState::PieceEnd
}
// Default, empty (tutorial doesn't always need to show something) // Default, empty (tutorial doesn't always need to show something)
} else { else {
TutorialState::PieceIntro TutorialState::PieceIntro
} }
}; };
@ -398,7 +404,6 @@ fn step(
} }
// After the outro, we exit the tutorial // After the outro, we exit the tutorial
TutorialState::Outro => error!("Press a button!"), TutorialState::Outro => error!("Press a button!"),
TutorialState::_Promotions => todo!("Not implemented yet!"),
} }
} }
@ -406,7 +411,7 @@ fn activate_tutorial_step(
state: Res<State<TutorialState>>, state: Res<State<TutorialState>>,
mut query: Query<(&mut Visibility, &TutorialState), Without<GameState>>, mut query: Query<(&mut Visibility, &TutorialState), Without<GameState>>,
) { ) {
info!("Activating step {:?}", state.get()); info!("Activating tutorial step {:?}", state.get());
// Iterate over all entities with TutorialState components // Iterate over all entities with TutorialState components
query.iter_mut().for_each(|(mut v, s)| { query.iter_mut().for_each(|(mut v, s)| {

Loading…
Cancel
Save