diff --git a/client/src/advance_ui.rs b/client/src/advance_ui.rs index bca5ca93..6b654737 100644 --- a/client/src/advance_ui.rs +++ b/client/src/advance_ui.rs @@ -1,18 +1,21 @@ +use itertools::Itertools; +use macroquad::hash; +use macroquad::math::{bool, vec2}; use std::cmp::min; use std::collections::HashMap; -use macroquad::math::bool; - use server::action::Action; -use server::content::advances::get_all; +use server::advance::{Advance, Bonus}; +use server::content::advances; use server::game::Game; use server::game::GameState; +use server::player::Player; use server::playing_actions::PlayingAction; use server::resource_pile::AdvancePaymentOptions; use server::status_phase::{StatusPhaseAction, StatusPhaseState}; use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate}; -use crate::dialog_ui::dialog; +use crate::dialog_ui::full_dialog; use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment}; use crate::resource_ui::{new_resource_map, ResourceType}; use crate::select_ui::HasCountSelectableObject; @@ -77,18 +80,18 @@ impl HasPayment for AdvancePayment { } pub fn show_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate { - show_generic_advance_menu("Advances", game, player, true, |name| { + show_generic_advance_menu("Advances", game, player, |name| { StateUpdate::SetDialog(ActiveDialog::AdvancePayment(AdvancePayment::new( game, player.index, - &name, + name, ))) }) } pub fn show_free_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate { - show_generic_advance_menu("Select a free advance", game, player, false, |name| { - StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name)) + show_generic_advance_menu("Select a free advance", game, player, |name| { + StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name.to_string())) }) } @@ -96,37 +99,91 @@ pub fn show_generic_advance_menu( title: &str, game: &Game, player: &ShownPlayer, - close_button: bool, - new_update: impl Fn(String) -> StateUpdate, + new_update: impl Fn(&str) -> StateUpdate, ) -> StateUpdate { - dialog(title, close_button, |ui| { + full_dialog(title, |ui| { let p = player.get(game); - for a in get_all() { - let name = a.name; - if player.can_play_action { - if p.has_advance(&name) { - ui.label(None, &name); - } else { - let can = if matches!( - game.state, - GameState::StatusPhase(StatusPhaseState::FreeAdvance) - ) { - p.can_advance_free(&name) + let mut update = StateUpdate::None; + let mut current_group = None; + for (_a, list) in &advances::get_all().iter().chunk_by(|a| { + if a.required.is_none() { + current_group = Some(&a.name); + &a.name + } else { + current_group.unwrap() + } + }) { + let advances = list.collect::>(); + ui.group(hash!(&advances[0].name), vec2(1500., 90.), |ui| { + for a in advances { + let name = &a.name; + let can_advance = if player.can_play_action { + p.can_advance(name) + } else if player.can_control + && matches!( + game.state, + GameState::StatusPhase(StatusPhaseState::FreeAdvance) + ) + { + p.can_advance_free(name) + } else { + false + }; + + let desc = description(p, a); + if p.has_advance(name) { + ui.label(None, &desc); + } else if can_advance { + if ui.button(None, desc) { + update = new_update(name); + } } else { - player.can_control && p.can_advance(&name) + ui.label(None, &desc); }; - if can && ui.button(None, name.clone()) { - return new_update(name); - } } - } else if p.has_advance(&name) { - ui.label(None, &name); - } + }); } - StateUpdate::None + update }) } +fn description(p: &Player, a: &Advance) -> String { + let name = &a.name; + let desc = &a.description; + + let mut parts = vec![]; + parts.push(if p.has_advance(name) { + format!("+ {name}") + } else { + format!(" {name}") + }); + parts.push(desc.clone()); + parts.push(format!("Cost: {}", p.advance_cost(name))); + if let Some(r) = &a.required { + parts.push(format!("Required: {r}")); + } + if let Some(c) = &a.contradicting { + parts.push(format!("Contradicts: {c}")); + } + if let Some(b) = &a.bonus { + parts.push(format!( + "Bonus: {}", + match b { + Bonus::MoodToken => "Mood Token", + Bonus::CultureToken => "Culture Token", + } + )); + } + if let Some(g) = &a.government { + parts.push(format!("Government: {g}")); + } + if let Some(u) = &a.unlocked_building { + parts.push(format!("Unlocks: {u}")); + } + + parts.join(", ") +} + pub fn pay_advance_dialog(ap: &AdvancePayment, player: &ShownPlayer) -> StateUpdate { payment_dialog( player, diff --git a/client/src/city_ui.rs b/client/src/city_ui.rs index 475de69c..905d7484 100644 --- a/client/src/city_ui.rs +++ b/client/src/city_ui.rs @@ -177,14 +177,12 @@ pub fn draw_city(owner: &Player, city: &City, state: &State) { for player_index in 0..4 { for b in &city.pieces.buildings(Some(player_index)) { let p = if matches!(b, Building::Port) { - hex_ui::rotate_around_rad( - c, - 60.0, - city.position - .coordinate() - .directions_to(city.port_position.unwrap().coordinate())[0] - .to_radians_pointy(), - ) + let r: f32 = city + .position + .coordinate() + .directions_to(city.port_position.unwrap().coordinate())[0] + .to_radians_pointy(); + hex_ui::rotate_around_rad(c, 60.0, r * -1.0 + std::f32::consts::PI / 3.0) } else { hex_ui::rotate_around(c, 20.0, 90 * i) }; diff --git a/client/src/client.rs b/client/src/client.rs index eecb3b32..eca7dd8c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -8,9 +8,7 @@ use server::position::Position; use server::status_phase::StatusPhaseAction; use crate::advance_ui::{pay_advance_dialog, show_advance_menu, show_free_advance_menu}; -use crate::client_state::{ - ActiveDialog, PendingUpdate, ShownPlayer, State, StateUpdate, StateUpdates, -}; +use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate, StateUpdates}; use crate::collect_ui::{click_collect_option, collect_resources_dialog}; use crate::construct_ui::pay_construction_dialog; use crate::dialog_ui::active_dialog_window; @@ -20,8 +18,8 @@ use crate::happiness_ui::{ use crate::hex_ui::pixel_to_coordinate; use crate::log_ui::show_log; use crate::map_ui::{draw_map, show_tile_menu}; -use crate::player_ui::{show_global_controls, show_globals, show_resources, show_wonders}; -use crate::{combat_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui}; +use crate::player_ui::{show_global_controls, show_globals, show_player_status, show_wonders}; +use crate::{combat_ui, dialog_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui}; pub async fn init(features: &Features) -> State { State::new(features).await @@ -56,7 +54,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate { let mut updates = StateUpdates::new(); let update = show_globals(game, player); updates.add(update); - show_resources(game, player_index); + show_player_status(game, player_index); show_wonders(game, player_index); if root_ui().button(vec2(1200., 100.), "Advances") { @@ -83,7 +81,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate { } if player.can_control { if let Some(u) = &state.pending_update { - updates.add(show_pending_update(u, player)); + updates.add(dialog_ui::show_pending_update(u, player)); return updates.result(); } } @@ -117,6 +115,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate { //status phase ActiveDialog::FreeAdvance => show_free_advance_menu(game, player), ActiveDialog::RazeSize1City => status_phase_ui::raze_city_dialog(player), + ActiveDialog::CompleteObjectives => status_phase_ui::complete_objectives_dialog(player), ActiveDialog::DetermineFirstPlayer => { status_phase_ui::determine_first_player_dialog(game, player) } @@ -128,6 +127,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate { } //combat + ActiveDialog::PlayActionCard => combat_ui::play_action_card_dialog(player), ActiveDialog::PlaceSettler => combat_ui::place_settler_dialog(player), ActiveDialog::Retreat => combat_ui::retreat_dialog(player), ActiveDialog::RemoveCasualties(s) => combat_ui::remove_casualties_dialog(game, s, player), @@ -138,19 +138,6 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate { updates.result() } -fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate { - active_dialog_window(player, "Are you sure?", |ui| { - ui.label(None, &format!("Warning: {}", update.warning.join(", "))); - if ui.button(None, "OK") { - return StateUpdate::ResolvePendingUpdate(true); - } - if ui.button(None, "Cancel") { - return StateUpdate::ResolvePendingUpdate(false); - } - StateUpdate::None - }) -} - pub fn try_click(game: &Game, state: &State, player: &ShownPlayer) -> StateUpdate { if !is_mouse_button_pressed(MouseButton::Left) { return StateUpdate::None; diff --git a/client/src/client_state.rs b/client/src/client_state.rs index dcf564bf..79761e9c 100644 --- a/client/src/client_state.rs +++ b/client/src/client_state.rs @@ -1,5 +1,4 @@ use macroquad::prelude::*; - use server::action::Action; use server::city::{City, MoodState}; use server::combat::{active_attackers, active_defenders, CombatPhase}; @@ -40,11 +39,13 @@ pub enum ActiveDialog { // status phase FreeAdvance, RazeSize1City, + CompleteObjectives, DetermineFirstPlayer, ChangeGovernmentType, ChooseAdditionalAdvances(ChooseAdditionalAdvances), // combat + PlayActionCard, PlaceSettler, Retreat, RemoveCasualties(RemoveCasualtiesSelection), @@ -69,9 +70,11 @@ impl ActiveDialog { ActiveDialog::CulturalInfluenceResolution(_) => "cultural influence resolution", ActiveDialog::FreeAdvance => "free advance", ActiveDialog::RazeSize1City => "raze size 1 city", + ActiveDialog::CompleteObjectives => "complete objectives", ActiveDialog::DetermineFirstPlayer => "determine first player", ActiveDialog::ChangeGovernmentType => "change government type", ActiveDialog::ChooseAdditionalAdvances(_) => "choose additional advances", + ActiveDialog::PlayActionCard => "play action card", ActiveDialog::PlaceSettler => "place settler", ActiveDialog::Retreat => "retreat", ActiveDialog::RemoveCasualties(_) => "remove casualties", @@ -322,11 +325,7 @@ impl State { ActiveDialog::CulturalInfluenceResolution(c.clone()) } GameState::StatusPhase(state) => match state { - StatusPhaseState::CompleteObjectives => { - // todo implement - // self.execute_status_phase(game, StatusPhaseAction::CompleteObjectives(vec![])) - ActiveDialog::None - } + StatusPhaseState::CompleteObjectives => ActiveDialog::CompleteObjectives, StatusPhaseState::FreeAdvance => ActiveDialog::FreeAdvance, StatusPhaseState::RaseSize1City => ActiveDialog::RazeSize1City, StatusPhaseState::ChangeGovernmentType => ActiveDialog::ChangeGovernmentType, @@ -334,13 +333,7 @@ impl State { }, GameState::PlaceSettler { .. } => ActiveDialog::PlaceSettler, GameState::Combat(c) => match c.phase { - CombatPhase::PlayActionCard(_) => { - // self.update( - // game, - // StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None))), - // ); - ActiveDialog::None - } //todo implement + CombatPhase::PlayActionCard(_) => ActiveDialog::PlayActionCard, CombatPhase::RemoveCasualties { player, casualties, .. } => { diff --git a/client/src/collect_ui.rs b/client/src/collect_ui.rs index 2c072bc5..0360a139 100644 --- a/client/src/collect_ui.rs +++ b/client/src/collect_ui.rs @@ -103,13 +103,16 @@ pub fn possible_resource_collections( .into_iter() .chain(iter::once(city_pos)) .filter_map(|pos| { - if city.port_position.is_some_and(|p| p == pos) { + if city + .port_position + .is_some_and(|p| p == pos && !is_blocked(game, player_index, p)) + { return Some((pos, PORT_CHOICES.to_vec())); } if let Some(t) = game.map.tiles.get(&pos) { if let Some(option) = collect_options .get(t) - .filter(|_| pos == city_pos || !is_blocked(game, pos)) + .filter(|_| pos == city_pos || !is_blocked(game, player_index, pos)) { return Some((pos, option.clone())); } @@ -172,10 +175,6 @@ pub fn draw_resource_collect_tile(state: &State, pos: Position) { }; } -fn is_blocked(game: &Game, pos: Position) -> bool { - //todo also look for enemy units - if game.get_any_city(pos).is_some() { - return true; - } - false +fn is_blocked(game: &Game, player_index: usize, pos: Position) -> bool { + game.get_any_city(pos).is_some() || game.enemy_player(player_index, pos).is_some() } diff --git a/client/src/combat_ui.rs b/client/src/combat_ui.rs index 5f56f0f5..8f5b5554 100644 --- a/client/src/combat_ui.rs +++ b/client/src/combat_ui.rs @@ -101,3 +101,12 @@ pub fn remove_casualties_dialog( |_| StateUpdate::None, ) } + +pub fn play_action_card_dialog(player: &ShownPlayer) -> StateUpdate { + active_dialog_window(player, "Play action card", |ui| { + if ui.button(None, "None") { + return StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None))); + } + StateUpdate::None + }) +} diff --git a/client/src/dialog_ui.rs b/client/src/dialog_ui.rs index 47329d19..30b79b2a 100644 --- a/client/src/dialog_ui.rs +++ b/client/src/dialog_ui.rs @@ -1,15 +1,15 @@ use macroquad::hash; -use macroquad::math::vec2; +use macroquad::math::{vec2, Vec2}; use macroquad::ui::widgets::Window; use macroquad::ui::{root_ui, Ui}; -use crate::client_state::{ShownPlayer, StateUpdate}; +use crate::client_state::{PendingUpdate, ShownPlayer, StateUpdate}; pub fn active_dialog_window(player: &ShownPlayer, title: &str, f: F) -> StateUpdate where F: FnOnce(&mut Ui) -> StateUpdate, { - dialog(title, false, |ui| { + dialog(title, |ui| { if player.can_control { f(ui) } else { @@ -18,23 +18,29 @@ where }) } -pub fn closeable_dialog_window(title: &str, f: F) -> StateUpdate +pub fn dialog(title: &str, f: F) -> StateUpdate where F: FnOnce(&mut Ui) -> StateUpdate, { - dialog(title, true, f) + custom_dialog(title, vec2(1100., 400.), vec2(800., 350.), f) } -pub fn dialog(title: &str, close_button: bool, f: F) -> StateUpdate +pub fn full_dialog(title: &str, f: F) -> StateUpdate where F: FnOnce(&mut Ui) -> StateUpdate, { - let window = Window::new(hash!(), vec2(1100., 400.), vec2(800., 350.)) + custom_dialog(title, vec2(100., 100.), vec2(1600., 800.), f) +} + +pub fn custom_dialog(title: &str, position: Vec2, size: Vec2, f: F) -> StateUpdate +where + F: FnOnce(&mut Ui) -> StateUpdate, +{ + let window = Window::new(hash!(), position, size) .titlebar(true) .movable(false) .label(title) - .movable(true) - .close_button(close_button); + .close_button(true); let ui = &mut root_ui(); let token = window.begin(ui); @@ -50,3 +56,16 @@ where update } } + +pub fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate { + active_dialog_window(player, "Are you sure?", |ui| { + ui.label(None, &format!("Warning: {}", update.warning.join(", "))); + if ui.button(None, "OK") { + return StateUpdate::ResolvePendingUpdate(true); + } + if ui.button(None, "Cancel") { + return StateUpdate::ResolvePendingUpdate(false); + } + StateUpdate::None + }) +} diff --git a/client/src/local_client.rs b/client/src/local_client.rs index 247e62bf..e9eb1519 100644 --- a/client/src/local_client.rs +++ b/client/src/local_client.rs @@ -65,6 +65,7 @@ pub fn setup_local_game() -> Game { add_city(&mut game, player_index1, "A1"); add_city(&mut game, player_index1, "C2"); add_city(&mut game, player_index2, "C1"); + add_city(&mut game, player_index2, "B2"); add_terrain(&mut game, "A1", Terrain::Fertile); add_terrain(&mut game, "A2", Terrain::Water); @@ -112,7 +113,7 @@ pub fn setup_local_game() -> Game { game.players[player_index1] .get_city_mut(Position::from_offset("C2")) .unwrap() - .port_position = Some(Position::from_offset("D2")); + .port_position = Some(Position::from_offset("C3")); game.players[player_index1] .get_city_mut(Position::from_offset("C2")) .unwrap() @@ -123,6 +124,17 @@ pub fn setup_local_game() -> Game { .unwrap() .increase_mood_state(); + game.players[player_index2] + .get_city_mut(Position::from_offset("B2")) + .unwrap() + .pieces + .port = Some(1); + game.players[player_index2] + .get_city_mut(Position::from_offset("B2")) + .unwrap() + .port_position = Some(Position::from_offset("C3")); + add_unit(&mut game, "B2", player_index2, UnitType::Ship); + game } diff --git a/client/src/log_ui.rs b/client/src/log_ui.rs index 440fa842..79fa5355 100644 --- a/client/src/log_ui.rs +++ b/client/src/log_ui.rs @@ -2,10 +2,10 @@ use macroquad::ui::Ui; use server::game::Game; use crate::client_state::StateUpdate; -use crate::dialog_ui::closeable_dialog_window; +use crate::dialog_ui::dialog; pub fn show_log(game: &Game) -> StateUpdate { - closeable_dialog_window("Log", |ui| { + dialog("Log", |ui| { game.log.iter().for_each(|l| { multiline(ui, l); }); diff --git a/client/src/map_ui.rs b/client/src/map_ui.rs index 02632e1a..e4f2075d 100644 --- a/client/src/map_ui.rs +++ b/client/src/map_ui.rs @@ -14,7 +14,7 @@ use server::unit::{MovementRestriction, Unit}; use crate::city_ui::{draw_city, show_city_menu, CityMenu}; use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate}; -use crate::dialog_ui::closeable_dialog_window; +use crate::dialog_ui::dialog; use crate::{collect_ui, hex_ui, unit_ui}; fn terrain_font_color(t: &Terrain) -> Color { @@ -131,7 +131,7 @@ pub fn show_generic_tile_menu( suffix: Vec, additional: impl FnOnce(&mut Ui) -> StateUpdate, ) -> StateUpdate { - closeable_dialog_window( + dialog( &format!( "{}/{}", position, diff --git a/client/src/player_ui.rs b/client/src/player_ui.rs index 0156b96f..857b6f0e 100644 --- a/client/src/player_ui.rs +++ b/client/src/player_ui.rs @@ -136,23 +136,37 @@ pub fn show_wonders(game: &Game, player_index: usize) { } } -pub fn show_resources(game: &Game, player_index: usize) { +pub fn show_player_status(game: &Game, player_index: usize) { let player = game.get_player(player_index); - let r: &ResourcePile = &player.resources; - let mut i: f32 = 0.; let mut res = |label: String| { - draw_text(&label, 1100., 30. + i, 20., BLACK); + draw_text(&label, 1000., 30. + i, 20., BLACK); i += 30.; }; - res(format!("Food {}", r.food)); - res(format!("Wood {}", r.wood)); - res(format!("Ore {}", r.ore)); - res(format!("Ideas {}", r.ideas)); - res(format!("Gold {}", r.gold)); - res(format!("Mood {}", r.mood_tokens)); - res(format!("Culture {}", r.culture_tokens)); + res(format!("Civ {}", player.civilization.name)); + res(format!("VP {}", player.victory_points())); + res(format!( + "Leader {}", + if let Some(l) = &player.active_leader { + &l.name + } else { + "-" + } + )); + res(resource_ui(player, "Food", |r| r.food)); + res(resource_ui(player, "Wood", |r| r.wood)); + res(resource_ui(player, "Ore", |r| r.ore)); + res(resource_ui(player, "Ideas", |r| r.ideas)); + res(resource_ui(player, "Gold", |r| r.gold as u32)); + res(resource_ui(player, "Mood", |r| r.mood_tokens)); + res(resource_ui(player, "Culture", |r| r.culture_tokens)); +} + +fn resource_ui(player: &Player, name: &str, f: impl Fn(&ResourcePile) -> u32) -> String { + let r: &ResourcePile = &player.resources; + let l: &ResourcePile = &player.resource_limit; + format!("{name} {}/{}", f(r), f(l)) } pub fn show_global_controls(game: &Game, state: &State) -> StateUpdate { diff --git a/client/src/status_phase_ui.rs b/client/src/status_phase_ui.rs index 7edb6c60..68ae2774 100644 --- a/client/src/status_phase_ui.rs +++ b/client/src/status_phase_ui.rs @@ -138,3 +138,12 @@ pub fn choose_additional_advances_dialog( }, ) } + +pub fn complete_objectives_dialog(player: &ShownPlayer) -> StateUpdate { + active_dialog_window(player, "Complete Objectives", |ui| { + if ui.button(None, "None") { + return StateUpdate::status_phase(StatusPhaseAction::CompleteObjectives(vec![])); + } + StateUpdate::None + }) +} diff --git a/client/src/unit_ui.rs b/client/src/unit_ui.rs index 72d463cd..9b972abe 100644 --- a/client/src/unit_ui.rs +++ b/client/src/unit_ui.rs @@ -63,7 +63,7 @@ pub fn draw_units(game: &Game) { pub trait UnitSelection: ConfirmSelection { fn selected_units(&self) -> &[u32]; fn selected_units_mut(&mut self) -> &mut Vec; - fn can_select(&self, game: &Game, unit: &Unit) -> bool; // todo return Option for why not + fn can_select(&self, game: &Game, unit: &Unit) -> bool; fn current_tile(&self) -> Option; } diff --git a/scripts/build-remote-client.sh b/scripts/build-remote-client.sh index a491e462..32ebd4f5 100755 --- a/scripts/build-remote-client.sh +++ b/scripts/build-remote-client.sh @@ -63,7 +63,11 @@ echo "Running wasm-bindgen..." mkdir -p dist -wasm-bindgen $TARGET_DIR/"$PROJECT_NAME".wasm --out-dir dist --target web --no-typescript +DEBUG_ARG="" +if [ "$RELEASE" != "yes" ]; then + DEBUG_ARG="--keep-debug --debug" +fi +wasm-bindgen $TARGET_DIR/"$PROJECT_NAME".wasm --out-dir dist $DEBUG_ARG --target web --no-typescript echo "Patching wasm-bindgen output..." diff --git a/server/src/advance.rs b/server/src/advance.rs index f46cd8bd..89f62bd3 100644 --- a/server/src/advance.rs +++ b/server/src/advance.rs @@ -21,6 +21,7 @@ pub struct Advance { } impl Advance { + #[must_use] pub fn builder(name: &str, description: &str) -> AdvanceBuilder { AdvanceBuilder::new(name.to_string(), description.to_string()) } @@ -63,31 +64,37 @@ impl AdvanceBuilder { } } + #[must_use] pub fn with_advance_bonus(mut self, advance_bonus: Bonus) -> Self { self.advance_bonus = Some(advance_bonus); self } + #[must_use] pub fn with_required_advance(mut self, required_advance: &str) -> Self { self.required_advance = Some(required_advance.to_string()); self } + #[must_use] pub fn with_contradicting_advance(mut self, contradicting_advance: &str) -> Self { self.contradicting_advance = Some(contradicting_advance.to_string()); self } + #[must_use] pub fn with_unlocked_building(mut self, unlocked_building: &str) -> Self { self.unlocked_building = Some(unlocked_building.to_string()); self } + #[must_use] pub fn leading_government_advance(mut self, government: &str) -> Self { self.government = Some(government.to_string()); self } + #[must_use] pub fn build(self) -> Advance { let player_initializer = ability_initializer::join_ability_initializers(self.player_initializers); @@ -159,6 +166,7 @@ pub enum Bonus { } impl Bonus { + #[must_use] pub fn resources(&self) -> ResourcePile { match self { MoodToken => ResourcePile::mood_tokens(1), diff --git a/server/src/content/advances.rs b/server/src/content/advances.rs index 6a520269..8ee40af9 100644 --- a/server/src/content/advances.rs +++ b/server/src/content/advances.rs @@ -28,6 +28,7 @@ pub fn get_all() -> Vec { game.players[player_index].resource_limit.food = 2; }) .with_advance_bonus(MoodToken) + .with_required_advance("Farming") .build(), Advance::builder( @@ -36,6 +37,7 @@ pub fn get_all() -> Vec { ) .add_collect_option(Barren, ResourcePile::food(1)) .with_advance_bonus(MoodToken) + .with_required_advance("Farming") .build(), //Construction @@ -50,6 +52,7 @@ pub fn get_all() -> Vec { ) .add_one_time_ability_initializer(Game::draw_wonder_card) .add_custom_action(ConstructWonder) + .with_required_advance("Mining") .build(), //Maritime diff --git a/server/src/lib.rs b/server/src/lib.rs index 04a46c23..9ae2cec2 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -13,7 +13,7 @@ mod ability_initializer; pub mod action; -mod advance; +pub mod advance; pub mod city; pub mod city_pieces; mod civilization;