Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tech #157

Merged
merged 5 commits into from
Feb 14, 2025
Merged

Tech #157

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added client/assets/crown-svgrepo-com.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/assets/justice-hammer-svgrepo-com.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions client/src/action_buttons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ fn generic_custom_action(
))));
}
}
return None;
}

match custom_action_type {
Expand All @@ -142,6 +143,12 @@ fn generic_custom_action(
CustomActionType::AbsolutePower => Some(StateUpdate::execute(Action::Playing(
PlayingAction::Custom(CustomAction::AbsolutePower),
))),
CustomActionType::ForcedLabor => Some(StateUpdate::execute(Action::Playing(
PlayingAction::Custom(CustomAction::ForcedLabor),
))),
CustomActionType::CivilRights => Some(StateUpdate::execute(Action::Playing(
PlayingAction::Custom(CustomAction::CivilRights),
))),
CustomActionType::Taxes => Some(StateUpdate::OpenDialog(ActiveDialog::Taxes(
Payment::new_gain(&tax_options(rc.shown_player), "Collect taxes"),
))),
Expand Down
8 changes: 8 additions & 0 deletions client/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,16 @@ impl Assets {
[
(
CustomActionType::AbsolutePower,
load_png(include_bytes!("../assets/crown-svgrepo-com.png")),
),
(
CustomActionType::ForcedLabor,
load_png(include_bytes!("../assets/slavery-whip-svgrepo-com.png")),
),
(
CustomActionType::CivilRights,
load_png(include_bytes!("../assets/justice-hammer-svgrepo-com.png")),
),
(
CustomActionType::Taxes,
load_png(include_bytes!("../assets/tax-svgrepo-com.png")),
Expand Down
3 changes: 2 additions & 1 deletion client/src/collect_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ impl CollectResources {

pub fn extra_resources(&self, game: &Game) -> i8 {
let city = game.get_city(self.player_index, self.city_position);
city.mood_modified_size() as i8 - self.collections.len() as i8
city.mood_modified_size(game.get_player(self.player_index)) as i8
- self.collections.len() as i8
}

pub fn collected(&self) -> ResourcePile {
Expand Down
11 changes: 9 additions & 2 deletions server/src/city.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::ops::{Add, Sub};
use serde::{Deserialize, Serialize};

use crate::consts::MAX_CITY_SIZE;
use crate::content::custom_actions::CustomActionType::ForcedLabor;
use crate::{
city_pieces::{Building, CityPieces, CityPiecesData},
game::Game,
Expand Down Expand Up @@ -187,11 +188,17 @@ impl City {
}

#[must_use]
pub fn mood_modified_size(&self) -> usize {
pub fn mood_modified_size(&self, player: &Player) -> usize {
match self.mood_state {
Happy => self.size() + 1,
Neutral => self.size(),
Angry => 1,
Angry => {
if player.played_once_per_turn_actions.contains(&ForcedLabor) {
self.size()
} else {
1
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion server/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn get_total_collection(
) -> Option<(CollectOptionsInfo, ResourcePile)> {
let player = &game.players[player_index];
let city = player.get_city(city_position)?;
if city.mood_modified_size() < collections.len() || city.player_index != player_index {
if city.mood_modified_size(player) < collections.len() || city.player_index != player_index {
return None;
}
let i = possible_resource_collections(
Expand Down
15 changes: 13 additions & 2 deletions server/src/content/advances_autocracy.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::ability_initializer::AbilityInitializerSetup;
use crate::advance::{Advance, AdvanceBuilder};
use crate::content::advances::{advance_group_builder, AdvanceGroup};
use crate::content::custom_actions::CustomActionType::AbsolutePower;
use crate::content::custom_actions::CustomActionType::{AbsolutePower, ForcedLabor};

pub(crate) fn autocracy() -> AdvanceGroup {
advance_group_builder("Autocracy", vec![nationalism(), absolute_power()])
advance_group_builder(
"Autocracy",
vec![nationalism(), absolute_power(), forced_labor()],
)
}

fn nationalism() -> AdvanceBuilder {
Expand All @@ -18,3 +21,11 @@ fn absolute_power() -> AdvanceBuilder {
)
.add_custom_action(AbsolutePower)
}

fn forced_labor() -> AdvanceBuilder {
Advance::builder(
"Forced Labor",
"Once per turn, as a free action, you may spend 1 mood token to treat your Angry cities as neutral for the rest of the turn",
)
.add_custom_action(ForcedLabor)
}
4 changes: 2 additions & 2 deletions server/src/content/advances_construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn sanitation() -> AdvanceBuilder {
.with_advance_bonus(MoodToken)
.add_player_event_listener(
|event| &mut event.recruit_cost,
|cost, units, ()| {
|cost, units, _| {
if units.settlers > 0 {
// insert at beginning so that it's preferred over gold
cost.info
Expand All @@ -55,6 +55,6 @@ fn sanitation() -> AdvanceBuilder {
);
}
},
0,
1,
)
}
28 changes: 17 additions & 11 deletions server/src/content/advances_democracy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@ use crate::ability_initializer::AbilityInitializerSetup;
use crate::advance::{Advance, AdvanceBuilder};
use crate::content::advances::{advance_group_builder, AdvanceGroup};
use crate::content::custom_actions::CustomActionType::{
FreeEconomyCollect, VotingIncreaseHappiness,
CivilRights, FreeEconomyCollect, VotingIncreaseHappiness,
};
use crate::playing_actions::PlayingActionType;

pub(crate) fn democracy() -> AdvanceGroup {
advance_group_builder(
"Democracy",
vec![
Advance::builder(
"Voting",
"As a free action, you may spend 1 mood token to gain an action 'Increase happiness'",
)
.add_custom_action(VotingIncreaseHappiness),
free_economy()
],
advance_group_builder("Democracy", vec![voting(), civil_rights(), free_economy()])
}

fn voting() -> AdvanceBuilder {
Advance::builder(
"Voting",
"As a free action, you may spend 1 mood token to gain an action 'Increase happiness'",
)
.add_custom_action(VotingIncreaseHappiness)
}

fn civil_rights() -> AdvanceBuilder {
Advance::builder(
"Civil Rights",
"As a free action, you may gain 3 mood tokens. The cost of Draft is increased to 2 mood token",
)
.add_custom_action(CivilRights)
}

fn free_economy() -> AdvanceBuilder {
Expand Down
17 changes: 9 additions & 8 deletions server/src/content/advances_warfare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,21 @@ fn draft() -> AdvanceBuilder {
.with_advance_bonus(CultureToken)
.add_player_event_listener(
|event| &mut event.recruit_cost,
|cost, units, ()| {
|cost, units, player| {
if units.infantry > 0 {
// insert at beginning so that it's preferred over gold

let pile = ResourcePile::mood_tokens(if player.has_advance("Civil Rights") {
2
} else {
1
});
cost.info
.log
.push("Draft reduced the cost of 1 Infantry to 1 mood token".to_string());

.push(format!("Draft reduced the cost of 1 Infantry to {pile}"));
cost.cost.conversions.insert(
0,
PaymentConversion::limited(
UnitType::cost(&UnitType::Infantry),
ResourcePile::mood_tokens(1),
1,
),
PaymentConversion::limited(UnitType::cost(&UnitType::Infantry), pile, 1),
);
}
},
Expand Down
29 changes: 26 additions & 3 deletions server/src/content/custom_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum CustomAction {
payment: ResourcePile,
},
AbsolutePower,
ForcedLabor,
CivilRights,
ArtsInfluenceCultureAttempt(InfluenceCultureAttempt),
VotingIncreaseHappiness(IncreaseHappiness),
FreeEconomyCollect(Collect),
Expand All @@ -43,6 +45,8 @@ pub enum CustomAction {
pub enum CustomActionType {
ConstructWonder,
AbsolutePower,
ForcedLabor,
CivilRights,
ArtsInfluenceCultureAttempt,
VotingIncreaseHappiness,
FreeEconomyCollect,
Expand All @@ -65,6 +69,12 @@ impl CustomAction {
payment,
} => construct_wonder(game, player_index, city_position, &wonder, payment),
CustomAction::AbsolutePower => game.actions_left += 1,
CustomAction::ForcedLabor => {
// we check that the action was played
}
CustomAction::CivilRights => {
game.players[player_index].gain_resources(ResourcePile::mood_tokens(3));
}
CustomAction::ArtsInfluenceCultureAttempt(c) => {
influence_culture_attempt(game, player_index, &c);
}
Expand All @@ -88,6 +98,8 @@ impl CustomAction {
match self {
CustomAction::ConstructWonder { .. } => CustomActionType::ConstructWonder,
CustomAction::AbsolutePower => CustomActionType::AbsolutePower,
CustomAction::ForcedLabor => CustomActionType::ForcedLabor,
CustomAction::CivilRights => CustomActionType::CivilRights,
CustomAction::ArtsInfluenceCultureAttempt(_) => {
CustomActionType::ArtsInfluenceCultureAttempt
}
Expand Down Expand Up @@ -117,6 +129,12 @@ impl CustomAction {
game.players[player_index].wonder_cards.push(wonder);
}
CustomAction::AbsolutePower => game.actions_left -= 1,
CustomAction::ForcedLabor => {
// we check that the action was played
}
CustomAction::CivilRights => {
game.players[player_index].lose_resources(ResourcePile::mood_tokens(3));
}
CustomAction::ArtsInfluenceCultureAttempt(_) => panic!("Action can't be undone"),
CustomAction::VotingIncreaseHappiness(i) => {
undo_increase_happiness(
Expand Down Expand Up @@ -149,6 +167,10 @@ impl CustomAction {
format!("{player_name} paid {payment} to construct the {wonder} wonder in the city at {city_position}"),
CustomAction::AbsolutePower =>
format!("{player_name} paid 2 mood tokens to get an extra action using Forced Labor"),
CustomAction::ForcedLabor =>
format!("{player_name} paid 1 mood token to treat Angry cities as neutral"),
CustomAction::CivilRights =>
format!("{player_name} gained 3 mood tokens using Civil Rights"),
CustomAction::ArtsInfluenceCultureAttempt(c) =>
format!("{} using Arts", format_cultural_influence_attempt_log_item(game, player_name, c)),
CustomAction::VotingIncreaseHappiness(i) =>
Expand All @@ -170,20 +192,21 @@ impl CustomActionType {
#[must_use]
pub fn action_type(&self) -> ActionType {
match self {
CustomActionType::ConstructWonder => ActionType::default(),
CustomActionType::AbsolutePower => {
ActionType::free_and_once_per_turn(ResourcePile::mood_tokens(2))
}
CustomActionType::CivilRights
| CustomActionType::Sports
| CustomActionType::ConstructWonder => ActionType::default(),
CustomActionType::ArtsInfluenceCultureAttempt => {
ActionType::free_and_once_per_turn(ResourcePile::culture_tokens(1))
}
CustomActionType::VotingIncreaseHappiness => {
ActionType::free(ResourcePile::mood_tokens(1))
}
CustomActionType::FreeEconomyCollect => {
CustomActionType::FreeEconomyCollect | CustomActionType::ForcedLabor => {
ActionType::free_and_once_per_turn(ResourcePile::mood_tokens(1))
}
CustomActionType::Sports => ActionType::new(false, false, ResourcePile::empty()),
CustomActionType::Taxes => ActionType::once_per_turn(ResourcePile::mood_tokens(1)),
CustomActionType::Theaters => ActionType::free_and_once_per_turn(ResourcePile::empty()),
}
Expand Down
4 changes: 2 additions & 2 deletions server/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1472,8 +1472,8 @@ impl Game {
" and captured {}'s city at {position}",
self.players[old_player_index].get_name()
));
self.players[new_player_index]
.gain_resources(ResourcePile::gold(city.mood_modified_size() as u32));
let size = city.mood_modified_size(&self.players[new_player_index]);
self.players[new_player_index].gain_resources(ResourcePile::gold(size as u32));
let take_over = self.players[new_player_index].is_city_available();

if take_over {
Expand Down
20 changes: 13 additions & 7 deletions server/src/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,13 +794,13 @@ impl Player {
|e| &e.recruit_cost,
&PaymentOptions::resources(vec.iter().map(UnitType::cost).sum()),
units,
&(),
self,
execute,
);
if !self.can_afford(&cost.cost) {
return None;
}
if vec.len() > city.mood_modified_size() {
if vec.len() > city.mood_modified_size(self) {
return None;
}
if vec.iter().any(|unit| matches!(unit, Cavalry | Elephant)) && city.pieces.market.is_none()
Expand Down Expand Up @@ -1050,15 +1050,21 @@ impl Player {
details: &V,
execute: Option<&ResourcePile>,
) -> CostInfo {
get_event(&self.events)
.get()
.trigger_with_minimal_modifiers(
&CostInfo::new(self, value.clone()),
let event = get_event(&self.events).get();
let mut cost_info = CostInfo::new(self, value.clone());
if let Some(execute) = execute {
event.trigger_with_minimal_modifiers(
&cost_info,
info,
details,
|i| execute.as_ref().is_none_or(|r| i.cost.is_valid_payment(r)),
|i| i.cost.is_valid_payment(execute),
|i, m| i.cost.modifiers = m,
)
} else {
let m = event.trigger(&mut cost_info, info, details);
cost_info.cost.modifiers = m;
cost_info
}
}

pub(crate) fn trigger_player_event<U, V>(
Expand Down
4 changes: 3 additions & 1 deletion server/src/player_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub(crate) struct PlayerEvents {
pub wonder_cost: Event<CostInfo, City, Wonder>,
pub advance_cost: Event<CostInfo, Advance>,
pub happiness_cost: Event<CostInfo>,
pub recruit_cost: Event<CostInfo, Units>,
pub recruit_cost: Event<CostInfo, Units, Player>,

pub is_playing_action_available: Event<bool, PlayingActionType, Player>,
pub terrain_collect_options: Event<HashMap<Terrain, HashSet<ResourcePile>>>,
Expand All @@ -46,6 +46,7 @@ impl PlayerEvents {

#[derive(Clone, PartialEq)]
pub(crate) struct ActionInfo {
pub(crate) player: usize,
pub(crate) undo: CommandUndoInfo,
pub(crate) info: HashMap<String, String>,
pub(crate) log: Vec<String>,
Expand All @@ -54,6 +55,7 @@ pub(crate) struct ActionInfo {
impl ActionInfo {
pub(crate) fn new(player: &Player) -> ActionInfo {
ActionInfo {
player: player.index,
undo: CommandUndoInfo::new(player),
info: player.event_info.clone(),
log: Vec::new(),
Expand Down
5 changes: 5 additions & 0 deletions server/src/playing_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,11 @@ impl ActionType {
Self::new(true, true, cost)
}

#[must_use]
pub fn regular(cost: ResourcePile) -> Self {
Self::new(false, false, cost)
}

#[must_use]
pub fn new(free: bool, once_per_turn: bool, cost: ResourcePile) -> Self {
Self {
Expand Down
Loading